Summary
Field feedback from hands-on testing of the seller-agent reference implementation (tag v2.0 · SHA 0f544a5) while working on drafting a runbook here in Australia to potentially support a local pilot. The SDK is in good shape overall (boot, catalogue, API-key lifecycle, partial-patch updates and the event bus all worked first time). Three reproducible observations are reported below, plus a note on tagging.
Happy to share full logs, retest on a candidate fix or newer tag, and feed learnings back as needed.
Environment
seller-agent: tag v2.0 · SHA 0f544a5 (see tagging note — local checkout of this SHA
may not match the running process)
host: WSL2 Ubuntu 24.04 (Windows 11), Python 3.12.3, venv install (pip install -e .)
config: AD_SERVER_TYPE=csv, CSV_DATA_DIR=./data/csv/samples/aws_workshop
run: uvicorn ad_seller.interfaces.api.main:app --port 8001
Observation 1: product IDs from /products don't resolve on /products/{id}
A product ID read from GET /products returns 404 Not Found on an immediate GET /products/{id} lookup.
ID=$(curl -s localhost:8001/products | python3 -c "import json,sys; print(json.load(sys.stdin)['products'][0]['product_id'])")
curl -s -o /dev/null -w "%{http_code}\n" localhost:8001/products/$ID
# observed: 404
This behaviour is puzzling against the source on this tag: both handlers read from _get_static_product_catalog(), whose docstring states IDs are "generated once and cached," so a list-then-lookup should hit the same cache and succeed. Separately, repeated ProductSetupFlow execution blocks appeared in the server log (each ending Created 4 mock synced packages) around catalogue activity even though list_products is documented to read the static cache instead of running the flow (to avoid an OpenDirect MCP session.initialize() hang). The observed flow runs may be triggered by a different endpoint in the session.
I cannot reconcile the observed 404s with the static-cache design, so this is reported as-observed. It may indicate a regeneration / caching path not visible in the read handlers, or a divergence between the checked-out SHA and the running process.
Server log excerpt (trimmed):
Starting Flow Execution — Name: ProductSetupFlow
INFO Created 4 mock synced packages product_setup_flow.py:277
INFO: 127.0.0.1 - "GET /products HTTP/1.1" 200 OK
...
INFO: 127.0.0.1 - "GET /products/prod-47d04b2e HTTP/1.1" 404 Not Found
Observation 2: curated-package creation silently produces empty placements (cause confirmed in source)
POST /packages with product_ids taken from /products returns 200, emits PACKAGE_CREATED, but the created package has placements: [] — products are not attached and no error or warning is returned.
# take two IDs from /products, then immediately:
curl -s -X POST localhost:8001/packages -H "Content-Type: application/json" \
-d '{"name":"Test Bundle","product_ids":["<id1>","<id2>"],"base_price":38.0,"floor_price":30.0}' \
| python3 -c "import json,sys; p=json.load(sys.stdin); print(p['package_id'], 'placements:', len(p.get('placements',[])))"
# observed: pkg-... placements: 0 (HTTP 200, PACKAGE_CREATED emitted)
Root cause is visible in the source. create_package builds placements by calling storage.get_product(pid) for each id and only appends when the lookup returns data. However, /products serves from the in-memory _get_static_product_catalog(), which is a different data store from storage. Product IDs surfaced by /products are therefore absent from storage, every get_product misses, and placements are silently skipped.
(POST /packages/assemble correctly raises 400 "No valid products found for assembly" in the equivalent case; the primary POST /packages path surfaces nothing.)
Suggested fixes:
- (a) Reconcile the read catalogue with
storage so /products IDs are resolvable by create_package; and/or
- (b) Have
create_package return 400/422 (or at least a warning field) when none of the supplied product_ids resolve, matching the behaviour of assemble.
Observation 3: package/media-kit counts grow across repeated reads
Counts climb with repeated catalogue reads. After creating one package and featuring one other, GET /media-kit reported total_packages: 13, featured_count: 8 which is well above what was curated. This is consistent with the mock packages being re-seeded during the session (the repeated Created 4 mock synced packages lines noted above), though the exact trigger has not been confirmed in source.
for i in 1 2 3; do curl -s localhost:8001/products > /dev/null; done
curl -s localhost:8001/packages | python3 -c "import json,sys; print('packages:', len(json.load(sys.stdin)['packages']))"
Note on tagging: v2.0 appears to have moved
A checkout of v2.0 on ~17 July resolved to seller a8b4eff / buyer 846acba; a fresh clone on 22 July resolved v2.0 to 0f544a5 / cc9c4d7. Separately, the local checkout of 0f544a5 has a /products implementation (static cache, IDs cached once) that does not match the runtime behaviour observed, which raises the possibility that the running server and the checked-out commit are not identical.
Since participants are being advised to pin to release tags for reproducibility, immutable or point-versioned tags (v2.0.1, etc.) would help considerably.
What worked well
CSV-mode boot, /health, the A2A agent card at /.well-known/agent.json, the 12-product workshop catalogue with correct AdCOM/taxonomy fields, buyer API-key minting via POST /auth/api-keys (shown-once design + usage tracking), partial-patch PUT /packages/{id} (emits PACKAGE_UPDATED), and the event bus persisting events with UUIDs all behaved exactly as documented. The two-layer /packages (operator CRUD) vs /media-kit (buyer read-only) split is a genuinely teachable illustration of the standard.
Summary
Field feedback from hands-on testing of the seller-agent reference implementation (tag
v2.0· SHA0f544a5) while working on drafting a runbook here in Australia to potentially support a local pilot. The SDK is in good shape overall (boot, catalogue, API-key lifecycle, partial-patch updates and the event bus all worked first time). Three reproducible observations are reported below, plus a note on tagging.Happy to share full logs, retest on a candidate fix or newer tag, and feed learnings back as needed.
Environment
Observation 1: product IDs from
/productsdon't resolve on/products/{id}A product ID read from
GET /productsreturns404 Not Foundon an immediateGET /products/{id}lookup.This behaviour is puzzling against the source on this tag: both handlers read from
_get_static_product_catalog(), whose docstring states IDs are "generated once and cached," so a list-then-lookup should hit the same cache and succeed. Separately, repeatedProductSetupFlowexecution blocks appeared in the server log (each endingCreated 4 mock synced packages) around catalogue activity even thoughlist_productsis documented to read the static cache instead of running the flow (to avoid an OpenDirect MCPsession.initialize()hang). The observed flow runs may be triggered by a different endpoint in the session.I cannot reconcile the observed 404s with the static-cache design, so this is reported as-observed. It may indicate a regeneration / caching path not visible in the read handlers, or a divergence between the checked-out SHA and the running process.
Server log excerpt (trimmed):
Observation 2: curated-package creation silently produces empty placements (cause confirmed in source)
POST /packageswithproduct_idstaken from/productsreturns200, emitsPACKAGE_CREATED, but the created package hasplacements: []— products are not attached and no error or warning is returned.Root cause is visible in the source.
create_packagebuilds placements by callingstorage.get_product(pid)for each id and only appends when the lookup returns data. However,/productsserves from the in-memory_get_static_product_catalog(), which is a different data store fromstorage. Product IDs surfaced by/productsare therefore absent fromstorage, everyget_productmisses, and placements are silently skipped.(
POST /packages/assemblecorrectly raises400 "No valid products found for assembly"in the equivalent case; the primaryPOST /packagespath surfaces nothing.)Suggested fixes:
storageso/productsIDs are resolvable bycreate_package; and/orcreate_packagereturn400/422(or at least a warning field) when none of the suppliedproduct_idsresolve, matching the behaviour ofassemble.Observation 3: package/media-kit counts grow across repeated reads
Counts climb with repeated catalogue reads. After creating one package and featuring one other,
GET /media-kitreportedtotal_packages: 13, featured_count: 8which is well above what was curated. This is consistent with the mock packages being re-seeded during the session (the repeatedCreated 4 mock synced packageslines noted above), though the exact trigger has not been confirmed in source.Note on tagging:
v2.0appears to have movedA checkout of
v2.0on ~17 July resolved to sellera8b4eff/ buyer846acba; a fresh clone on 22 July resolvedv2.0to0f544a5/cc9c4d7. Separately, the local checkout of0f544a5has a/productsimplementation (static cache, IDs cached once) that does not match the runtime behaviour observed, which raises the possibility that the running server and the checked-out commit are not identical.Since participants are being advised to pin to release tags for reproducibility, immutable or point-versioned tags (
v2.0.1, etc.) would help considerably.What worked well
CSV-mode boot,
/health, the A2A agent card at/.well-known/agent.json, the 12-product workshop catalogue with correct AdCOM/taxonomy fields, buyer API-key minting viaPOST /auth/api-keys(shown-once design + usage tracking), partial-patchPUT /packages/{id}(emitsPACKAGE_UPDATED), and the event bus persisting events with UUIDs all behaved exactly as documented. The two-layer/packages(operator CRUD) vs/media-kit(buyer read-only) split is a genuinely teachable illustration of the standard.