Skip to content

Feedback (v2.0 / 0f544a5): product ID resolution 404, silent empty placements on POST /packages, and growing package counts #34

Description

@jaanijuk

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions