feat(decisioning): refine[] flow scaffold for get_products (#496)#505
Merged
Conversation
74179b2 to
ce96f24
Compare
…nstruct test instances)
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.
Closes #496
Adds capability-gated framework support for
buying_mode='refine'onget_products. When a buyer sendsrefine[]entries, the framework dispatches to an optionalSalesPlatform.refine_get_products()method, projects the adopter'sRefineResultinto the wire response, and constructs position-matchedrefinement_applied[]echoes by zipping outcomes with the request'srefine[]array.What's in the PR
src/adcp/decisioning/refine.py(new):RefineResultdataclass —{ products, proposals, per_refine_outcome }RefinementOutcomedataclass —{ status, notes }assert_buying_mode_consistent()— enforces wire spec mutual-exclusion:refine + brief,wholesale + brief,refinewithoutrefine[]→INVALID_REQUESTbuild_refinement_applied()— position-matched echo across the three discriminated scope variants (request/product/proposal); raisesValueErroron count mismatch (developer-facing)project_refine_response()— assembles the wireGetProductsResponsehas_refine_support()—hasattrcheck used at dispatch timesrc/adcp/decisioning/handler.py:get_productsshim runs buying-mode validation, then dispatches torefine_get_products()whenbuying_mode='refine'. Rejects unsupported refine viaINVALID_REQUEST(field='buying_mode').src/adcp/decisioning/specialisms/sales.py: documentsrefine_get_productsas truly optional — kept out of the Protocol body so adopters who don't implement remain structurally conformant. Theget_productsdocstring notes the dispatch behavior.src/adcp/decisioning/__init__.py: exportsRefineResult,RefinementOutcome,RefinementStatus,assert_buying_mode_consistent,build_refinement_applied,has_refine_support,project_refine_response.tests/test_decisioning_refine.py(new) — 17 tests covering validation rules, position-matched echo across all three scope variants, mismatched outcome counts, handler dispatch, and rejection of unsupported refine.Test plan
pytest tests/test_decisioning_refine.py— all greenmypy src/adcp/decisioning/refine.py src/adcp/decisioning/handler.py— no new errorsruff check— cleanOut of scope
previous_response_statethread (issue mentions an opaque state — adopters can read products fromreq.refine[].product_idreferences; framework doesn't manage state).action='finalize'proposal-scoped refines (separateSalesResulthybrid concern; can be added when needed).🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com