Commit 69c585c
authored
docs(proposals): product architecture — layered model + two-platform composition (#502)
* docs(proposals): product architecture — layered model + two-platform composition
Foundational design doc capturing the layered architecture for products
across the SDK: wire / internal-config (recipe) / capability overlap /
supporting tables. Anchors the missing prerequisite that the salesagent
migration guide (PR #489) currently has no answer for.
Key conceptual moves:
- Four-layer model with explicit ownership per layer.
- Two-platform composition: ProposalManager + DecisioningPlatform,
with the recipe (implementation_config) as the typed contract
between them.
- Three concrete shapes: tight coupling (LinkedIn), sophisticated
multi-decisioning (Prebid salesagent), naive (programmatic
non-guaranteed).
- Path B recipe binding: discriminated-union with recipe_kind tag,
explicit tenant binding, boot-time validation.
- ProposalCapabilities is sales-axis-scoped (not generic to all
specialisms) — guaranteed vs non-guaranteed flavors.
Status: DRAFT (conceptual scaffold). Concrete examples sections marked
[citations pending] for follow-up agent pass once budget allows.
Python-first; ports back to JS once settled. Reverses the typical
direction (lifecycle-state proposal went JS-to-Python) because the
conceptual gap surfaced during the Python migration story.
Refs:
- PR #489 (migration guide reviewer feedback that prompted this)
- Issues #491-#497 (already-filed buyer-side request-shape helpers)
- #477 (multi-platform proof — interacts with tenant binding model)
- proposals/decisioning-platform-dispatch-design.md (current
DecisioningPlatform design)
* docs(proposals): v1 ProposalManager is mock-backend forwarder, not new catalog impl
Brian's review correction: the mock seller backend (bin/adcp.js
mock-server) already implements the naive case via product fixtures.
SDK doesn't need a separate SimpleCatalogProposalManager.
v1 of ProposalManager is just the wiring that forwards to the mock
backend — symmetric with DecisioningPlatform's upstream_for(ctx)
mock-mode dispatch from Phase 2. Adopters declare a mock_upstream_url;
framework forwards get_products / refine; recipes flow back.
Updates:
- Shape 3 reframed: Naive → Mock-backed (v1 default)
- MockProposalManager sketch with parallel pattern to upstream_for
- Independent-modes table: ProposalManager and DecisioningPlatform
can each be mock or live independently
- Future-issues list: SimpleCatalogProposalManager replaced with
MockProposalManager (the v1 work is wiring, not a new impl)
- §What ships in v1 framing: framework wiring, not catalog content
* docs(proposals): address review comments — recipe lifecycle, hydration, finalize
Four corrections from Brian's review:
1. Recipe lifecycle (Layer 2): never on the wire. Lives in framework
session cache during negotiation; persists alongside the committed
proposal after finalize; the framework hydrates it for every
subsequent operation in the buy's lifecycle. Adopters do NOT store
recipes themselves — the SDK is the system of record.
2. ProposalManager flavors: don't lock the formal taxonomy. Two
extremes today (simple catalog vs complex proposal); useful
variants will emerge between. sales_specialism + capability flags
let adopters declare their actual shape; naming variants is
future-state work.
3. Proposal hydration + capability validation upstream of adapter:
buyer may reference packages by proposal_id OR product_id;
framework hydrates from session cache or persisted store and
validates the buyer's request against capability_overlap BEFORE
invoking adapter. Buyer asking for geo-metro targeting on a
product that doesn't expose it gets a structured error without
adapter code participating. Layer 3 capability-overlap seam
gets concrete.
4. Acceptance IS in the spec — buying_mode='refine' with refine[]
action='finalize' transitions a draft proposal to committed
with locked pricing, expires_at hold window, optional HITL.
I incorrectly said the spec had no proposal lifecycle.
Rewrote the section to walk the actual wire flow:
get_products → refine → finalize → create_media_buy. SDK
responsibilities at the seam: session cache, finalize transition,
expires_at enforcement, persistence through the buy lifecycle.1 parent 786e6a2 commit 69c585c
1 file changed
Lines changed: 885 additions & 0 deletions
0 commit comments