Decompose: Backend /v1/export and /v1/threads/resolve stub replacements #25
Labels
No labels
blocked:commit-ready-failed
blocked:gate-fetch
blocked:gate-lint
blocked:gate-plan
blocked:gate-research
blocked:needs-attention
blocked:needs-decision
blocked:needs-human
blocked:no-changes
blocked:verify-failed
bug
deferred
feature-request
in-progress
needs-decompose
needs-triage
quickfix
security/medium
triage-approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Mark/Kimi_Agent_Brother_10_Digitizing_App#25
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
The backend
easystitch-serviceexposes two POST endpoints that arestubbed:
POST /v1/export— should serialize stitch objects to PES/DST/EXP/JEFbytes for the user's embroidery machine. Currently returns
{"error": "not_implemented"}with HTTP 200.POST /v1/threads/resolve— should find the nearest Brother PR10catalog matches for a list of input hex colors. Currently returns
{"error": "not_implemented"}with HTTP 200.The HTTP-200-with-error-body shape is the worst of both worlds:
integration tests that assert "status 200 == success" pass, but no
real work is happening. Frontend's
readErrorBody(easystitch-client.ts:276) doesn't catch thispattern because it gates on
response.ok— it only fires for4xx/5xx, not 200.
Both backend stubs must be replaced with real implementations.
Goal
Replace the two stubbed POST endpoints with real logic, returning
proper status codes and body shapes:
POST /v1/export→ returns binary payload(
application/octet-streamor appropriate format-specific MIME), withX-Stitch-CountandX-Color-Countresponse headers alreadyconsumed by
exportPESateasystitch-client.ts:201-218.POST /v1/threads/resolve→ returns 200 with{ matches: [{src, best: ThreadCatalogEntry, deltaE, alternatives: [...]}] }.Non-goals
Pipeline stages
P1: Implement POST /v1/threads/resolve
Goal: Match a list of input hex colors against the Brother PR10
catalog (depends on #24's catalog endpoint being loadable; we'll
load the JSON in-process here).
Approach candidates:
against every catalog entry, return top-K.
scipy.spatial.distance.cdist.Recommend B. Already have
vectorized thread-pair Delta-E checkin theengine codebase (commit history shows numpy adoption elsewhere) and a
one-time vectorized loop beats O(n*m) for any realistic palette size.
Outputs: new route handler in
easystitch-service/app.pythat:colors: [...]from the request body (the shape alreadyestablished by the frontend's
resolveThreads).can).
{matches: [{src, best, deltaE, alternatives}, ...]}.Acceptance:
POST http://localhost:8080/v1/threads/resolvewith{"colors": ["#ff0000", "#0000ff"]}returns 200 with thematchesshape.bestentry must have ahexfieldthat is exactly equal (or very close, Delta-E < 2.0) to the input.
alternativesreturns the next 3 closest catalog entries.colors, emptycolors, invalid hex) returns422 with structured error envelope.
Files touched:
/home/b/Projects/easystitch-service/app.py(add the route)/home/b/Projects/easystitch-service/app.py(extract catalogloading helper shared with #24/P1)
P2: Add tests for /v1/threads/resolve
Goal: Backend test coverage for the resolve endpoint.
Outputs: new test file
/home/b/Projects/easystitch-service/tests/unit/test_threads_resolve.py.Acceptance:
python -m pytest tests/unit/test_threads_resolve.py -vexits 0ordering, malformed input, empty color list.
Files touched:
/home/b/Projects/easystitch-service/tests/unit/test_threads_resolve.py(new)P3: Implement POST /v1/export
Goal: Replace the stub with a real serializer. Format parameter
selects PES/DST/EXP/JEF.
Approach candidates:
pyembroiderylibrary (already in service deps for formatwriter support; uses standard format specs).
Recommend A.
pyembroideryis the established community library forthis; re-implementing format serialization correctly is deep work
that's easy to get wrong.
Outputs: route handler in
easystitch-service/app.pythat:stitchObjects: [...]and optionalformat: "pes"|"dst"|"exp"|"jef"from the body.
pyembroidery.writeto bytes.Content-Type: application/octet-streamand thefilename in
Content-Disposition.X-Stitch-CountandX-Color-Countheaders (count from theinput array).
Acceptance:
POST /v1/exportwith{"stitchObjects": [...], "format": "pes"}returns 200, Content-Type
application/octet-stream, body isvalid PES bytes (verify with
pyembroidery.read).pyembroidery.read.Files touched:
/home/b/Projects/easystitch-service/app.py(route handler)/home/b/Projects/easystitch-service/models.py(if new requestmodels are needed for the body shape)
P4: Add tests for /v1/export
Goal: Lock down P3 with backend tests including a round-trip
write → readverification for each format.Outputs: new test file
/home/b/Projects/easystitch-service/tests/unit/test_export.py.Acceptance:
python -m pytest tests/unit/test_export.py -vexits 0return 422.
Files touched:
/home/b/Projects/easystitch-service/tests/unit/test_export.py(new)Dependencies
helper added by #24/P1. If #24's loader isn't ready, P1 here can do
its own minimal catalog loader inline.
user clicks Export in the workspace).
Research required
pyembroideryis on the service's deps listand can serialize the stitch-object shape the frontend produces.
If not, this work moves to a different module that pulls in
pyembroidery.
Auto-triage: needs decompose
Marked
triage-approved+needs-decompose. decompose-executor will pick this up and break it into implementable sub-issues.Backend /v1/export and /v1/threads/resolve return 200 {"error":"not_implemented"} — looks healthy, isn'tto Decompose: Backend /v1/export and /v1/threads/resolve stub replacementsThis issue has been decomposed into the following sub-issues:
write → readEach sub-issue has been labeled with
triage-approvedand is ready for queue routing.