Anuva Python Server API Implementation Plan
Created: 2026-05-21 13:30 UTC
Goal
Implement a worker-facing /api/worker/v1 API for the Anuva Python Server that fully replaces the current /api/render-jobs renderer API and matches the contract defined in docs/AnuvaPythonServer_SystemDescription.md.
The resulting backend must let the Python worker:
- Discover or claim one render job at a time
- Fetch a complete render package
- Report status, heartbeat, and failures
- Upload the render result through signed S3 upload
- Finalize the job and update presentation-level final video pointers
Non-Goals
- Changing Python worker code beyond the contract assumptions already documented
- Changing Unity runtime behavior beyond consuming the documented package contract
- Reworking presentation generation, scene generation, or Mastra orchestration flows
- Adding a legacy compatibility layer that preserves
/api/render-jobs - Shipping direct multipart upload fallback in V1
Current Behavior
- Render jobs are persisted in
video_generation_jobs. - The current renderer surface is limited to:
GET /api/render-jobsPATCH /api/render-jobs/{jobId}- Current auth uses
x-renderer-secret, not bearer token worker auth. src/app/(frontend)/app/presentation/actions.tscreates render jobs withconfigSnapshot.publicConfig, which is the closest existing renderer-facing config snapshot.- There is no dedicated claim endpoint, package endpoint, heartbeat endpoint, signed upload issuance/confirmation flow, or failure diagnostics persistence model.
video_generation_jobs.progressis stored as0..100, while the Python worker contract expects0.0..1.0.video_generation_jobscurrently lacks worker-native statusesclaimedanduploadFailed.
Target Behavior
- The backend exposes the full worker contract under
/api/worker/v1. /api/render-jobsis removed.RenderJobPackage.configis exactlyPresentationConfigPublic.- The package endpoint returns a normalized asset manifest with signed URLs and safe basenames.
- Internal progress remains
0..100invideo_generation_jobs, but the worker API translates progress to and from0.0..1.0. - Worker auth uses
Authorization: Bearer <ANUVA_WORKER_API_TOKEN>. - Worker state is split into:
render_workersfor latest heartbeat and worker staterender_worker_reportsfor append-only failure diagnostics and related reports- Final render upload uses presigned S3 upload and confirmation only.
Planned Flow
flowchart TD
queued["video_generation_jobs: queued"] --> next["GET /api/worker/v1/jobs/next"]
next --> claim["POST /jobs/{jobId}/claim"]
claim --> package["GET /jobs/{jobId}/package"]
package --> config["config = PresentationConfigPublic"]
package --> assets["signed asset manifest"]
config --> worker["Python worker rewrites to localhost URLs"]
assets --> worker
worker --> status["PATCH /jobs/{jobId}/status"]
worker --> heartbeat["POST /workers/{workerId}/heartbeat"]
worker --> signed["POST /jobs/{jobId}/uploads/signed"]
signed --> s3["PUT to S3"]
s3 --> confirm["POST /jobs/{jobId}/uploads/confirm"]
confirm --> complete["POST /jobs/{jobId}/complete"]
worker --> fail["POST /jobs/{jobId}/fail"]
worker --> cancel["POST /jobs/{jobId}/cancel"]
Assumptions
/api/worker/v1fully replaces/api/render-jobsin one change.RenderJobPackage.configisPresentationConfigPublicwith no wrapper.- Signed asset URLs are generated on demand and are not persisted in Payload documents.
- Signed upload confirmation creates or resolves the final
media_assetsrecord before job completion. - Direct multipart upload fallback is intentionally omitted from V1.
Affected Files And Modules
Worker API routes
- Remove or replace:
src/app/api/render-jobs/route.tssrc/app/api/render-jobs/[jobId]/route.ts- Add:
src/app/api/worker/v1/jobs/next/route.tssrc/app/api/worker/v1/jobs/available/route.tssrc/app/api/worker/v1/jobs/[jobId]/route.tssrc/app/api/worker/v1/jobs/[jobId]/claim/route.tssrc/app/api/worker/v1/jobs/[jobId]/package/route.tssrc/app/api/worker/v1/jobs/[jobId]/status/route.tssrc/app/api/worker/v1/jobs/[jobId]/uploads/signed/route.tssrc/app/api/worker/v1/jobs/[jobId]/uploads/confirm/route.tssrc/app/api/worker/v1/jobs/[jobId]/complete/route.tssrc/app/api/worker/v1/jobs/[jobId]/fail/route.tssrc/app/api/worker/v1/jobs/[jobId]/cancel/route.tssrc/app/api/worker/v1/workers/[workerId]/heartbeat/route.ts
Shared render-worker helpers
- Add a shared worker/render helper area under
src/lib, for example: - worker auth validation
- render job serializers
- progress conversion helpers
- claim and transition helpers
- render package builder
- S3 presign/confirm helpers
Schema and job-creation touchpoints
src/collections/anuvax/index.tssrc/payload-types.ts- generated import map output
src/app/(frontend)/app/presentation/actions.tssrc/lib/presentation-config/schema.ts- optional shared media/storage helpers if package assembly or upload confirmation needs them
Test harness and coverage
tests/integration/helpers/fake-payload.tstests/integration/helpers/presentation-fixtures.ts- new worker API integration tests
- existing render-job integration tests that assume old route semantics
Affected Docs
docs/AnuvaPythonServer_SystemDescription.mddocs/core/WorkersAndJobs.mddocs/core/SystemArchitecture.mddocs/core/PresentationConfig.mddocs/state/RouteMap.mddocs/state/CollectionMap.mddocs/state/CurrentImplementationMap.mddocs/state/KnownGaps.mddocs/changes/2026-05-21-1330-anuva-python-server-api/ImplementationLog.md
Data And Schema Impact
video_generation_jobs
- Add statuses:
claimeduploadFailed- Keep persisted
progressas0..100. - Add worker-facing metadata fields:
workerIdclaimedAterrorCodestatusMessage- Keep existing core relationships:
workspacepresentationcompilationresultMedia
render_workers
- New workspace-scoped collection for latest worker state
- Proposed fields:
workspaceworkerIdstatusactiveJobdetailslastHeartbeatAt
render_worker_reports
- New workspace-scoped append-only collection for diagnostics and worker reports
- Proposed fields:
workspaceworkerIdjobreportTypeerrorCodeerrorMessagediagnostics- timestamps
Generated artifacts
- Regenerate:
src/payload-types.ts- Payload import map
Implementation Phases
Phase 1. Contract and schema foundation
- Add worker auth helper for bearer-token validation
- Define shared route-level serializers and parsers for:
RenderJobRenderJobSummaryRenderJobPackageWorkerHeartbeat- signed-upload responses
UploadedMedia- Update
video_generation_jobs - Add
render_workers - Add
render_worker_reports - Regenerate Payload types and import map
Phase 2. Core job lifecycle APIs
- Implement
next,available, and summary endpoints - Implement atomic claim logic
- Implement shared status transition rules
- Implement progress conversion at the API boundary
- Remove old route-specific assumptions tied to
x-renderer-secret
Phase 3. Render package and asset manifest
- Build package assembly from existing render-job state
- Use
configSnapshot.publicConfigasRenderJobPackage.config - Dynamically collect referenced media assets and emit signed URLs plus safe basenames
- Ensure the package is fully sufficient for worker-side local materialization
Phase 4. Worker operational APIs
- Implement
status,heartbeat,fail, andcancel - Persist latest worker state in
render_workers - Persist diagnostics history in
render_worker_reports - Ensure invalid terminal rewrites are rejected
Phase 5. Upload and completion flow
- Add S3 presign helper using existing AWS SDK dependencies
- Implement
uploads/signed - Implement
uploads/confirm - Create or resolve the final
media_assetsrecord during confirmation - Implement
completeso presentation final-video pointers update only after confirmed upload
Phase 6. Cleanup, tests, and docs
- Remove
/api/render-jobs - Update integration harness and add contract coverage
- Update all impacted docs
- Record final implementation details in
ImplementationLog.md
Ordered Tasks
- [x] 1. Add shared worker auth and contract serialization helpers.
- [x] 2. Update
video_generation_jobsschema and addrender_workersplusrender_worker_reports. - [x] 3. Regenerate Payload types and import map.
- [x] 4. Extract shared claim, status-transition, and progress-conversion helpers.
- [x] 5. Implement
GET /api/worker/v1/jobs/next. - [x] 6. Implement
GET /api/worker/v1/jobs/available. - [x] 7. Implement
GET /api/worker/v1/jobs/{jobId}. - [x] 8. Implement
POST /api/worker/v1/jobs/{jobId}/claim. - [x] 9. Implement
GET /api/worker/v1/jobs/{jobId}/package. - [x] 10. Implement
PATCH /api/worker/v1/jobs/{jobId}/status. - [x] 11. Implement
POST /api/worker/v1/workers/{workerId}/heartbeat. - [x] 12. Implement
POST /api/worker/v1/jobs/{jobId}/fail. - [x] 13. Implement
POST /api/worker/v1/jobs/{jobId}/cancel. - [x] 14. Implement
POST /api/worker/v1/jobs/{jobId}/uploads/signed. - [x] 15. Implement
POST /api/worker/v1/jobs/{jobId}/uploads/confirm. - [x] 16. Implement
POST /api/worker/v1/jobs/{jobId}/complete. - [x] 17. Update render-job creation to remain compatible with the new worker package contract.
- [x] 18. Remove the old
/api/render-jobsroute surface and update any internal references. - [x] 19. Update integration test harnesses and add worker API contract tests.
- [x] 20. Update docs and write final notes to
ImplementationLog.md.
Verification Plan
Run:
pnpm generate:typespnpm generate:importmappnpm lintpnpm typecheckpnpm test:int
Test Cases And Scenarios
GET /jobs/nextreturnsnullor204when no queued jobs exist.GET /jobs/availablereturns only safe summary data and does not leak config or signed asset URLs.POST /claimatomically claims a queued job and returns409on conflict.GET /packagereturnsPresentationConfigPublicexactly inconfig.GET /packagereturns a valid asset manifest with unique asset IDs and safe basenames.- Progress conversion is correct:
- API input
0.42persists as42 - persisted
50returns as0.5 PATCH /statusaccepts valid transitions and rejects invalid terminal rewrites.POST /heartbeatupserts latest worker state intorender_workers.POST /failstores diagnostics inrender_worker_reportsand marks the job failed.POST /uploads/signedreturns a valid signed upload response shape.POST /uploads/confirmcreates or resolvesmedia_assetsand returnsmediaId.POST /completemarks the job completed and updates presentation final-video pointers only after confirmed upload.POST /canceltransitions the job tocancelled.- Existing render-job creation still produces a worker-consumable queued job with
configSnapshot.publicConfig.
Docs Parity Checklist
- [ ] Replace
/api/render-jobswith/api/worker/v1in route documentation. - [ ] Document the Python worker lifecycle in
docs/core/WorkersAndJobs.md. - [ ] Document that
PresentationConfigPublicis the exactRenderJobPackage.config. - [ ] Add
render_workersandrender_worker_reportstodocs/state/CollectionMap.md. - [ ] Update system architecture and implementation maps to reflect worker-facing render APIs.
- [ ] Update known gaps if any intentional V1 limitations remain after implementation.
- [ ] Update
ImplementationLog.mdwith tasks completed, files changed, tests run, and deviations.
Acceptance Criteria
- A Python worker using the documented bearer-token contract can acquire, claim, render, upload, and finalize a job using only
/api/worker/v1. /api/render-jobsno longer exists in code or docs.RenderJobPackage.configis exactly the persistedPresentationConfigPublicsnapshot.- The render package includes all required asset references as signed URLs plus safe basenames.
video_generation_jobssupportsclaimedanduploadFailed.- API progress uses
0.0..1.0while persistence remains0..100. - Worker heartbeats persist in
render_workers. - Failure diagnostics persist in
render_worker_reports. - Signed upload confirmation returns normalized media data with
mediaId. - Presentation final-video state updates only after confirmed upload and successful completion.
Rollback And Recovery Notes
- If the new worker API fails in non-production verification, restore the previous route surface from git before rollout because this plan intentionally removes
/api/render-jobs. - If schema changes land but worker routes are incomplete, block rollout until the new route family and generated Payload artifacts are in sync.
- If signed upload confirmation fails after upload, preserve
uploadFailedstate and diagnostics so the job can be retried without losing the render artifact context.