Skip to content

feat(decisioning): refine[] flow scaffold for get_products (#496)#505

Merged
bokelley merged 4 commits into
mainfrom
bokelley/refine-flow-scaffold
May 3, 2026
Merged

feat(decisioning): refine[] flow scaffold for get_products (#496)#505
bokelley merged 4 commits into
mainfrom
bokelley/refine-flow-scaffold

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

@bokelley bokelley commented May 3, 2026

Closes #496

Adds capability-gated framework support for buying_mode='refine' on get_products. When a buyer sends refine[] entries, the framework dispatches to an optional SalesPlatform.refine_get_products() method, projects the adopter's RefineResult into the wire response, and constructs position-matched refinement_applied[] echoes by zipping outcomes with the request's refine[] array.

What's in the PR

  • src/adcp/decisioning/refine.py (new):

    • RefineResult dataclass — { products, proposals, per_refine_outcome }
    • RefinementOutcome dataclass — { status, notes }
    • assert_buying_mode_consistent() — enforces wire spec mutual-exclusion: refine + brief, wholesale + brief, refine without refine[]INVALID_REQUEST
    • build_refinement_applied() — position-matched echo across the three discriminated scope variants (request/product/proposal); raises ValueError on count mismatch (developer-facing)
    • project_refine_response() — assembles the wire GetProductsResponse
    • has_refine_support()hasattr check used at dispatch time
  • src/adcp/decisioning/handler.py: get_products shim runs buying-mode validation, then dispatches to refine_get_products() when buying_mode='refine'. Rejects unsupported refine via INVALID_REQUEST(field='buying_mode').

  • src/adcp/decisioning/specialisms/sales.py: documents refine_get_products as truly optional — kept out of the Protocol body so adopters who don't implement remain structurally conformant. The get_products docstring notes the dispatch behavior.

  • src/adcp/decisioning/__init__.py: exports RefineResult, 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 green
  • mypy src/adcp/decisioning/refine.py src/adcp/decisioning/handler.py — no new errors
  • ruff check — clean

Out of scope

  • The narrowing logic itself (adopter business logic).
  • previous_response_state thread (issue mentions an opaque state — adopters can read products from req.refine[].product_id references; framework doesn't manage state).
  • HITL action='finalize' proposal-scoped refines (separate SalesResult hybrid concern; can be added when needed).

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

@bokelley bokelley force-pushed the bokelley/refine-flow-scaffold branch from 74179b2 to ce96f24 Compare May 3, 2026 23:34
@bokelley bokelley merged commit b584e70 into main May 3, 2026
15 checks passed
@bokelley bokelley deleted the bokelley/refine-flow-scaffold branch May 3, 2026 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(decisioning): refine[] flow scaffold for get_products (position-matched echo)

1 participant