Pod

Yes, this is on purpose. Pod is built for agents, so the default page is plain HTML.
Human? View the normal website.
Agent? You probably prefer /mcp/gam-seller-mcp-node/issues.md or /mcp/gam-seller-mcp-node/issues.json, or Pod over MCP.

Reported issues for gam-seller-mcp-node

Pod holds 16 of 19 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.

Back to gam-seller-mcp-node.

Most discussed

README security section should state the hash-chain attribution boundary (ADR-4)

hashEntry covers { seq, event_class, payload, prev_hash, timestamp } (src/audit/event.ts:54) and deliberately excludes the top-level buyer_id / request_id (ADR-4 decision B, event.ts:43-45). This is a sound tradeoff — it lets crypto-shred (Art. 17) anonymize entries without breaking the chain — but the README's "every decision audited / hash-chained" reads as if attribution is tamper-evident. Reattribution of an entry's top-level actor is not covered by the chain (the pseudonym

Read the thread · 2026-08-10 · closed · 2 comments

Add JSDoc to public-facing types in catalog/store.ts and pricing/store.ts

What to do

Add JSDoc comments to the exported interfaces and types that buyer agents and publisher operators interact with:

Example

/** A coarse product family visible to an entitled buyer agent.
 *  Raw inventory IDs, deal IDs, and exact floor prices are never included.
 */

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/10) · 2026-07-22 · open · 2 comments

### RFC: Bucket thresholds — define what Low / Mid / High means in impression terms

## Background

\`get_forecast\` returns one of three buckets: \`low\`, \`mid\`, \`high\`. The current implementation is synthetic and deterministic. When the real GAM ForecastService adapter lands (#4), the engine will need to map actual impression forecasts to these three values.

The thresholds are not yet defined. This issue is the place to discuss and ratify them.

## Questions

**Absolute vs relative thresholds?**
- Absolute: \`low < 100k impressions\`, \`mid = 100k–1M\`, \`high > 1M\`
- Re

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/12) · 2026-07-22 · closed · 1 comment

### Production transport: TLS termination, bind posture, and single-instance limitation

## Problem

The HTTP transport binds loopback and expects a reverse proxy to terminate TLS; there is no in-process TLS. And the rate limiter, replay guard, and intent store are in-memory per process, so the node is **single-instance** — scaling out would split that state.

**Anchor:** `docs/PUBLISHER-DEPLOYMENT.md` (reverse-proxy + single-instance notes) and `src/http.ts` (bind).

## Impact

A publisher deploying without a correctly configured TLS-terminating proxy exposes plaintext; a publisher

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/86) · 2026-08-18 · open · 0 comments

### Head-hash anchor is a local rewritable file — move to external WORM / Object Lock for production

## Problem

The tamper-evidence guarantee assumes the head-hash anchor lives in an **append-only external** store. Today it is written to a local file with a rewritable `writeFileSync`.

**Anchor:** `src/audit/anchor.ts` — the code comment itself notes: *"Production: use cloud-immutable write instead (never overwrite)."*

## Impact

An adversary who can rewrite the local ledger can also rewrite the local anchor alongside it, defeating the "tamper with the local file alone isn't enough" property.

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/85) · 2026-08-18 · open · 0 comments

### Audit event taxonomy: 9 of 16 EventClasses are emitted; 7 are defined-but-unused

## Problem

`src/audit/event.ts` defines **16** `EventClass` values, but only **9** are ever emitted via `ledger.append(...)`.

**Emitted (9):** `BUYER_AUTHENTICATION`, `SCOPE_RESOLUTION`, `FORECAST_REQUEST`, `INTENT_CREATED`, `INTENT_EXPIRED`, `INTENT_REVOKED`, `TOKEN_ISSUANCE`, `TOKEN_REVOCATION`, `ANCHORING`.

**Defined but never emitted (7):** `FORECAST_CACHE_FILL`, `SOFT_LOCK_SET`, `SOFT_LOCK_EXPIRED`, `SOFT_LOCK_REVOKED`, `OPERATOR_GATE_APPROVAL`, `OPERATOR_GATE_REJECTION`, `RESTORE`.

## 

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/84) · 2026-08-18 · open · 0 comments

### DSR overlay retains the raw buyer_id after an Art. 17 erasure (P3 residual)

## Problem

To make an erasure durable (so a config redeploy can't silently re-expose an erased buyer), the DSR overlay persists the buyer in `data/dsr-state.json`. But it stores the **raw** `buyer_id` in `suppressed[]` / `restricted[]`.

**Anchor:** `src/policy/dsr-state.ts` — `DsrState = { suppressed: string[]; restricted: string[] }`, populated with raw buyer ids.

So after `DsrToolkit.suppressBuyer()` crypto-shreds the pseudonym key and purges `intents.json`, the raw identifier still survive

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/83) · 2026-08-18 · open · 0 comments

### client_request_id is optional → a request can bypass SEC-GATE-3 (replay detection)

## Problem

Replay detection (SEC-GATE-3) only runs when the caller supplies `client_request_id`. A request that omits it skips the dedup step entirely — the replay guard is never consulted.

**Anchor:** `src/server.ts` — every tool handler guards replay behind `if (client_request_id !== undefined) { … replayGuard.isReplay(...) … }`. No field → no check.

## Impact

An attacker replaying a captured authenticated request without `client_request_id` is not caught by SEC-GATE-3 (it still faces auth

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/82) · 2026-08-18 · open · 0 comments

## Most recent

### issue-buyer-token.ts leaves an un-anchored ledger → server fail-closes on next startup (no_anchor_but_non_empty_ledger)

## Summary

Minting a buyer token with the documented CLI (`scripts/issue-buyer-token.ts`) on a fresh state writes a `TOKEN_ISSUANCE` event to the persistent audit ledger but never anchors the head. The **next server startup then aborts fail-closed**:

Fatal: [audit] FATAL: ledger integrity check failed on startup (no_anchor_but_non_empty_ledger) — refusing to serve requests with a suspect chain. Investigate the ledger and anchor before restarting.


So the node won't start after followin

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/73) · 2026-08-12 · closed · 0 comments

### Add a structural test that every authenticated tool routes through policy (scope gate)

`resolveScope()` (the policy/allowlist gate) is invoked **manually inside each authenticated handler** (`src/server.ts:228, 290, 354, 442`), not enforced by the tool-registration path. The README states *"Adding a new tool in the future cannot bypass this"* (`README.md:218`), but there is no wrapper and no test that enforces it: a new `server.tool(...)` that omits the `authenticate` / `resolveScope` calls would bypass policy silently.

All 5 current surfaces are correctly gated — `well_known_cap

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/67) · 2026-08-10 · closed · 0 comments

### Persistence-health surfacing (v0.6 E1) only covers the ledger; extend to the other 4 stores + /health

**Tier:** 1–2 (integrity / observability)

**Use case**
v0.6 added a persistence-health flag to `AuditLedger` (`isPersistenceHealthy()`, `src/audit/ledger.ts`) and surfaced it through `GET /health` (v0.8, `status:"degraded"`). But the other four disk-backed stores still **swallow write failures** as a benign `WARNING`:

- `src/audit/pseudonym.ts`
- `src/audit/anchor.ts`
- `src/audit/retention.ts`
- `src/identity/denylist.ts`

(all matched by `grep -rn "could not persist" src/`).

**Why it matter

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/51) · 2026-07-30 · closed · 0 comments

### Intent store is in-memory only: committed intents are lost on restart

**Tier:** 1 (durability of a core surface)

**Describe the bug**
`IntentStore` holds intents in a plain in-memory `Map` with no persistence (`src/intent/store.ts:45` — `private readonly byId = new Map(...)`, no `persistPath`), unlike the ledger (`src/audit/ledger.ts`) and denylist (`src/identity/denylist.ts`) which are file-backed. So a node restart drops all live intents.

This was acceptable in v0.5 (create-only, no read/revoke surface). It stopped being acceptable in **v0.7**, which added `re

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/50) · 2026-07-30 · closed · 0 comments

### Add integration test: pricing_options absent when valid_until has expired

## Context

\`PricingStore.priceFor()\` returns \`undefined\` for expired prices (fail-closed). This is unit-tested in \`tests/pricing.test.ts\`. However, the end-to-end buyer-agent session test (\`tests/buyer-agent-session.test.ts\`) only covers the happy path (valid price → \`pricing_options\` present).

## What to add

A new \`it()\` block in \`tests/buyer-agent-session.test.ts\` or \`tests/server.test.ts\` that:

1. Builds a server with a \`PricingStore\` configured with an **already-expired

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/11) · 2026-07-22 · closed · 0 comments

### OpenRTB 3.0 product taxonomy: align family_id scheme with IAB standards

## Context

Currently, \`family_id\` values are publisher-defined free-form strings (\`"display-ros"\`, \`"video-pre-roll"\`). A buyer agent connecting to multiple seller nodes has no way to know that \`"display-ros"\` at Publisher A is the same product type as \`"display-banner"\` at Publisher B.

Aligning \`family_id\` with the [OpenRTB 3.0](https://iabtechlab.com/standards/openrtb/) / [AdCOM](https://iabtechlab.com/standards/adcom/) taxonomy would make family IDs interoperable across publishe

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/9) · 2026-07-22 · open · 0 comments

### Prometheus metrics endpoint: observability for production deployments

## Context

In a production deployment, operators need to monitor:
- Request rates per buyer and per tool
- Auth failure rates (spike = probing or misconfigured buyer)
- Rate-limit hit frequency
- Audit ledger size and last anchor time
- Forecast bucket distribution (to detect synthetic vs real data divergence)

Currently, none of this is observable without reading the audit ledger files directly.

## Proposed endpoint

A scrape-friendly Prometheus metrics endpoint at \`/metrics\` (not exposed t

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/8) · 2026-07-22 · closed · 0 comments

### OIDC buyer authentication: replace manual entitlements.json with federated identity

## Context

Currently, buyer entitlements are granted by editing \`config/entitlements.json\` manually and restarting the node. This is fine for a pilot with 1-2 buyers, but it doesn't scale to a publisher managing dozens of buyer organizations.

## Proposed solution

Support OIDC/JWT bearer tokens issued by a trusted Identity Provider (IdP) — e.g. Auth0, Okta, or a publisher-operated IdP. The \`entitlements.json\` config would define which OIDC issuers and claims map to which surfaces and scope

[Read the thread](https://github.com/juan-sibbo/gam-seller-mcp-node/issues/7) · 2026-07-22 · open · 0 comments

The remaining reports are on [the project's issue tracker](https://github.com/juan-sibbo/gam-seller-mcp-node/issues).