Repository navigation
feat: Taxomind contract from its OpenAPI document (M09) - #1
Merged
Merged
Conversation
Taxomind (FastAPI) serves its OpenAPI document at /openapi.json. A snapshot (Taxomind f7a9e91) is committed in lib/contracts/; `npm run taxomind:types` generates the types with openapi-typescript, and lib/ai-labeling.ts calls Taxomind through openapi-fetch. It keeps the bearer token, the timeouts and the best-effort cancel. Every response is parsed in lib/contracts/taxomind.ts with zod schemas that are checked against the generated types: the job id per resource (`jobId` for /learn), the status enum and the labeling result. parseLabelingResults moved there from lib/ai-results.ts and now expects the contract's `sentenceId` and string `nodeCode`. A malformed status response counts as a failed request (backoff), and a job Taxomind reports `canceled` fails with that reason instead of being polled until it times out. The stub service in tests/integration/ai-job-monitor.test.ts checks every request and reply against the document (z.fromJSONSchema). It adds cases for malformed and partial replies, Taxomind-side cancellation, taxonomy sync through the sync-ai route, sourceSlug, leading zeros and the unknown codes. W07's idempotent start stays open: Taxomind does not deduplicate batchId. The plan also records that /taxonomies rejects the delete route's `action: 'delete'`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXfhpzKa2n5fw4nyZnTn2h
Resolves the import conflict in tests/integration/ai-job-monitor.test.ts: fixtures now use the owner client from ./helpers (staging), plus the contract test's imports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXfhpzKa2n5fw4nyZnTn2h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements M09 from
docs/plans/modernization-2026-10.md, starting fromstagingatc7b9c53.What changed
Taxomind is a FastAPI service and serves its OpenAPI document at
/openapi.json, with a response model on every endpoint classiflow uses. So this PR follows the OpenAPI path of the plan:lib/contracts/taxomind.openapi.jsonis a snapshot of that document. It was taken from Taxomindf7a9e91with FastAPI 0.121.3 and Pydantic 2.12.4, the versions in itsrequirements-prod.txt.npm run taxomind:typesregeneratestaxomind.openapi.tsfrom it withopenapi-typescript7.13.0 (devDependency). openapi-typescript declares atypescript ^5peer dependency, so anoverridesentry lets it use the repo's TypeScript 6.lib/ai-labeling.tscalls Taxomind throughopenapi-fetch0.17.0. The bearer token, the 3 min / 30 s timeouts and the best-effort cancel are unchanged. Labeling and learning requests are typed by the generatedLabelingRequest/LearningRequest.startAIJob('/taxonomies', …),monitorAIJobandcancelAIJobkeep signatures the taxonomy routes can call unchanged, so those routes are untouched.lib/contracts/taxomind.tsparses every response with zod: the job id of each creation response (jobIdfor/learn,job_idotherwise), the status enum and the labeling result. Each schema is checked against the generated type withsatisfies, so a regenerated contract that renames or retypes a field fails typecheck. I checked this by changing the generated types by hand.lib/ai-results.tsmoved into this file asparseLabelingResults.tests/integration/ai-job-monitor.test.tsconverts the document's schemas withz.fromJSONSchema. It checks every request classiflow sends and every reply the stub itself gives, and answers a request that breaks the contract with a 422, as Taxomind would. New cases:sync-airoute, and cancelsourceSlug=AI_SOURCE_SLUG--<workspaceId>Behaviour changes (all follow from the contract)
complete,successanderrorare no longer accepted. Taxomind's enum ispending | running | completed | failed | canceled.canceledis now marked failed with that reason, in both the monitor and the taxonomy sync. Before, it was polled until it timed out.parseLabelingResultsexpects the contract'ssentenceIdand stringnodeCode. Thesentence_idalias and numeric codes are dropped: Taxomind's Pydantic models cannot emit either, and a stringified number would lose leading zeros.Still open (recorded in the plan)
batchIdbut creates a new job for every request (uuid4) and does not deduplicate./taxonomiesaccepts onlyaction: 'create', so the delete route'saction: 'delete'gets a 422 andaiNotifiedis always false./taxonomiespayload is still untyped, because it is built in the taxonomy routes, which were outside this task's scope. Taxomind also ignores thedescriptionandsynonymsthe sync route sends.Checks
npm run typecheck: cleannpm run lint: 0 errors (the 24 warnings were already there)npm test: 48 passednpm run test:integrationon PostgreSQL 16: 77 passednpm run build: succeedscanceledbranch, or droppingbatchIdfrom the payload, makes the contract tests fail.npm cisucceeds. Re-running npm on Linux would rewrite the Windows-generated peer/dev flags, so only the new package entries were merged in.User management,
prisma/and migrations are not touched.Generated by Claude Code