fix(gateway): open-taxonomy buyer-path — ad-hoc capabilities buyable end-to-end - #212
Open
LamaSu wants to merge 3 commits into
Open
fix(gateway): open-taxonomy buyer-path — ad-hoc capabilities buyable end-to-end#212LamaSu wants to merge 3 commits into
LamaSu wants to merge 3 commits into
Conversation
…n pricing for ad-hoc types POST /api/jobs/submit-from-discovery computed its quote via getTemplate(capabilityType)?.basePricingHints?.basePrice, falling back to a hardcoded $10 for any type without a built-in @pcc/contract-builder template -- silently mispricing every ad-hoc-capability escrow funded through this fast-track endpoint. This was the last unclosed piece of the open-taxonomy buyer-path fix: negotiate/session and build/options already derive ad-hoc pricing via getCapabilityDescriptor() (coord 6be1ebbe/5e2b3aeb, PR #148) and buyer-listing matching already keys off the capability's own type (coord 6d33a1a5, PR #169) -- this endpoint was the one quote-computation path the prior sessions flagged as a residual gap (MATCHING-NOTES.md #1: "the order path must consume [the listing's own price]"). Fix mirrors the existing build.ts/negotiation.ts pattern exactly: getCapabilityDescriptor(capabilityType) resolves template vs ad-hoc vs missing; ad-hoc derives basePrice/currency from the capability row's own pricingModel; missing returns a clean 404 (capability_not_buildable) instead of silently quoting $10. Removed the now-unused direct getTemplate import (getCapabilityDescriptor calls it internally). Verified: negotiate-ad-hoc.test.ts (14/14), request-matching.test.ts (12/12), onboard-analyze.test.ts (11/11, one route-integration test needs a >10s hook timeout on this cold from-source worktree -- confirmed a pre-existing transform-timing artifact, not a logic issue, by re-running standalone with --hookTimeout=90000), requests.test.ts all green -- confirming bugs 1-4 from the open-taxonomy handoff were already fixed and merged to master (PRs #148/#168/#169) before this session started. New test file submit-from-discovery-adhoc-pricing.test.ts (3/3 passing) covers this fix directly. Not added to paid-job-flow.test.ts because that file is excluded from the default vitest run for pre-existing, unrelated reasons (vitest.config.ts: "facade rewrite changed route behavior" -- confirmed by temporarily un-excluding it: 3 job-completion/scope assertions fail there independent of this change, the other 15/18 including this fix's behavior pass). vitest.config.ts and paid-job-flow.test.ts are unchanged (diff-verified byte-for-byte reverted after the temporary investigation). Scoped tsc --noEmit shows 500 pre-existing errors, all "Cannot find module @pcc/*" (workspace dist/*.d.ts not built in this worktree, affects the whole package uniformly, e.g. sse/producers.ts) plus pre-existing TS7006 implicit-any on lines untouched by this diff. Zero new errors introduced. Did not touch: settlement contracts, kernels.ts, onboard-kit's separate VALID_CAPABILITY_TYPES allow-list (already flagged in MATCHING-NOTES.md as an adjacent, out-of-scope gap for a different owner), NL-inference of ad-hoc types, or /requests/:id/decompose re-templating -- all explicitly out of scope per the prior sessions' own gap analysis. fixer-taxonomy Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…, don't reject) VALID_CAPABILITY_TYPES was a hard allow-list: an operator onboarding a well-formed but non-built-in capability (wood-fired-pizza, rideshare-driver, pizza.order) failed config validation with a blocking error, even though PCC is an open taxonomy — buyers reach any registered type by its own type string + pricing model (the whole point of the buyer-path fixes). Flagged as the adjacent onboard-kit gap in MATCHING-NOTES.md #5. Reframe the set as RECOGNIZED_CAPABILITY_TYPES (ships a built-in template) and classify each type three ways: - recognized → info (built-in) - ad-hoc → warning, ALLOWED (well-formed slug, not built-in) - malformed → error, REJECTED (empty / spaces / uppercase / illegal chars) A well-formed slug is /^[a-z0-9]+([.-][a-z0-9]+)*$/ — matches built-ins, hyphenated ad-hoc types, and dotted namespaced types (pizza.order). Same three-way logic applied to profile.capabilityType. The ad-hoc check is severity:"warning" with passed:false — this codebase derives `warnings` from failed checks (checks.filter(c => !c.passed && severity==="warning")) while `valid` keys only off severity:"error", matching the existing tier-2-camera warning convention. So an ad-hoc type is allowed AND surfaced as a warning, never blocking. Test contract updated to the open taxonomy: the old "invalid-type" (a well-formed slug) is no longer an error — replaced with a genuinely malformed type ("Not A Real Type!") + empty-string cases for the error path, plus new tests that a well-formed ad-hoc type (wood-fired-pizza) and a dotted type (pizza.order) validate with a warning, and that a built-in stays warning-free. Verified: 14/14 validate.test.ts green (solo run, cache-cleared, exit 0); cross-checked against the real source via a standalone esbuild bundle (wood-fired-pizza → valid=true, errs=0, ad-hoc warning present; malformed → error). onboard-kit is a leaf package not imported by the gateway, so this is operator-onboarding-config validation only — zero buyer-path runtime change. fixer-taxonomy Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…g on re-decompose, auto-assign on publish Closes the three remaining open-taxonomy buyer-path gaps documented in MATCHING-NOTES.md (#2, #3, #4) so a buyer request for an ad-hoc capability flows all the way from free text to a funded, operator-targeted job. 2. NL inference of ad-hoc types (request-matcher.ts: inferListingFromText). A request with NO capabilityType used to always fall to the generic custom_product template — "I want a wood-fired pizza" never reached the pizzeria's listing. Now, on the no-LLM path (after agentic decompose declines), a deterministic pass infers ONE registered listing from the description, keyed off each capability's own type slug + name tokens (no allow-list). Conservative by construction: minimum distinctive-token score, must be strictly stronger than the runner-up of a different type (no ambiguous ties), skips stopwords, and is kill-switchable via PCC_NL_INFER_ADHOC_DISABLED=1. On any doubt it declines and the composite template path runs unchanged — it never hijacks a real multi-step request. An inferred match stays status="decomposed" (unpublished) because inference is a guess the buyer confirms; the response carries `inferredMatch` so the routing is transparent. 3. Re-decompose preserves direct-match routing (routes/requests.ts). A request routed to one listing carries a lone node with kernelId + capabilityId. POST /:id/decompose used to re-run the NL/template decomposer and drop that routing, stranding the buyer from their chosen operator. Now it detects the direct-match node, re-resolves the SAME listing via matchListings (picking up any price change), recovers the original quantity from the stored cost, and rebuilds the direct-match node. Only falls back to composite if the listing was removed. Composite requests re-decompose unchanged. 4. Publish auto-assign (routes/requests.ts). POST /:id/publish minted open bounties for every node and left assignment manual — but a direct-match node already knows its operator. Now direct-match nodes (those carrying kernelId) auto-assign straight to the operator (kernel.operatorAddress, falling back to kernelId), status→"assigned", skipping the bounty auction; generic template nodes still publish as open bounties. Response adds `autoAssigned` / `autoAssignedCount` alongside the existing bounty fields. Tests: new request-adhoc-routing-extras.test.ts (8/8) covers all three — inference routes pizza/rideshare, does NOT hijack the animatronic-robot composite, honors the kill switch; re-decompose keeps kernel+capability+qty (and re-templates composites unchanged); publish auto-assigns the operator and still mints bounties for composite nodes. request-matching.test.ts unchanged (12/12, no regression — the inference change leaves composite routing intact). Agentic decompose forced off in the new suite so the deterministic path is what's under test. 20/20 green (exit 0). Verification limits: gateway `tsc --noEmit` not re-run (workspace @pcc/* dist/*.d.ts absent in this worktree → ~500 pre-existing module-resolution errors that swamp signal, same limitation the prior buyer-path commits noted); runtime + behavior verified by the green vitest suites (esbuild transform compiles the touched files). RoutedCapabilityNode + inferListingFromText are properly exported. No settlement/contracts/kernels.ts touched; no deploy. fixer-taxonomy Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Makes ad-hoc capabilities (pizza, rideshare) quotable/orderable, not just discoverable.
7 upstream buyer-path bugs were already merged (#148/#168/#169/#171/#172/#173/#170); this closes the residual gaps. No settlement/kernels.ts touched, no deploy. Worklist: ai/research/HANDOFF-open-taxonomy-buyer-path.md
🤖 Generated with Claude Code