{"data":{"@kind":"guide","slug":"become-an-upstream","title":"Become a tributary — contribute your data source to Cambridge TCG","subtitle":"Implement SourceModule. Open a PR. Your data flows in.","intro":"If you operate a TCG data source (an API, a scraper, a marketplace feed) and want Cambridge TCG to ingest it, you can contribute a SourceModule. Eight-step protocol. We accept PRs against the open-source repo. Your source becomes a typed contract; downstream of us, every adopter automatically gets your data.","audiences":["operator_of_upstream","federation_partner"],"prerequisites":["Your data source is reachable via HTTP (API, scrape target, or paid feed)","TypeScript familiarity","Read access to https://github.com/cambridgetcg/Cambridge-TCG-monorepo"],"estimated_minutes":90,"step_count":5,"steps":[{"step_number":1,"title":"Read the source protocol","instruction":"Start at /methodology/source-protocol — the eight steps. Then read packages/data-ingest/src/cardrush/ as the canonical example (the smallest working source). Understand SourceMeta + read + normalize + canonical types.","links":[{"label":"Source protocol methodology","href":"https://github.com/cambridgetcg/Cambridge-TCG-monorepo/blob/main/docs/methodology/source-protocol.md"},{"label":"CardRush reference implementation","href":"https://github.com/cambridgetcg/Cambridge-TCG-monorepo/tree/main/packages/data-ingest/src/cardrush"},{"label":"Pipeline design","href":"https://github.com/cambridgetcg/Cambridge-TCG-monorepo/blob/main/docs/connections/the-pipeline.md"}]},{"step_number":2,"title":"Add the row to the-tributaries catalog","instruction":"Edit docs/connections/the-tributaries.md to add a row for your source: name, upstream URL, access method, license tier, freshness budget, ToS notes, game coverage, status: planned. Submit a PR with just this change first — we'll review the row and discuss scope before any code."},{"step_number":3,"title":"Implement the SourceModule","instruction":"Create packages/data-ingest/src/<your-source-id>/ with index.ts exporting `SourceMeta`, `read`, `normalize`. Type the raw row and the canonical record. Per-source rate-limit declared in meta. Lazy AsyncIterable for read. Pure normalize."},{"step_number":4,"title":"Pass the audits","instruction":"Run `pnpm audit:tributaries` — it runs ten checks (module exists, shape conforms, required meta non-empty, id parity, catalog anchor resolved, ToS non-empty, license coherence, game codes valid, ingest-run recency for shipped sources, license-propagation drift). Pass all of them. Then open a PR."},{"step_number":5,"title":"Operator review + first dry-run","instruction":"Yu reviews the PR. If accepted, we wire it into a per-app cron (storefront or wholesale, depending on data type) and do a first dry-run via `?dryRun=1&maxCards=20`. The ingest_run row records the result; failed normalizations land in ingest_quarantine for your review."}],"gotchas":[{"title":"If your source has redistribute: false, declare it","description":"We honour your upstream's license. The `meta.redistribute` flag + the kingdom's license_propagation rule (kingdom-081) thread your tier through every downstream emission. Don't lie about your license — the audit check #10 will catch it."},{"title":"Your normalizer must be pure","description":"Same input → same output. No I/O, no clock reads, no random. Failed normalizations return `{ ok: false, reason }` — never throw. The reason must be actionable ('unmapped lang qya; add to LANG_MAP'), not 'normalization failed'."}],"next_guide":{"slug":"cite-cambridge-tcg","title":"How to cite Cambridge TCG in your downstream product","url":"/api/v1/guides/cite-cambridge-tcg","html_url":"/agents/guides/cite-cambridge-tcg"},"see_also":[{"label":"the-tributaries catalog","href":"https://github.com/cambridgetcg/Cambridge-TCG-monorepo/blob/main/docs/connections/the-tributaries.md"},{"label":"the-pipeline design","href":"https://github.com/cambridgetcg/Cambridge-TCG-monorepo/blob/main/docs/connections/the-pipeline.md"},{"label":"Source protocol","href":"https://github.com/cambridgetcg/Cambridge-TCG-monorepo/blob/main/docs/methodology/source-protocol.md"}],"last_verified":"2026-05-14","feedback":{"kind":"guide-feedback","endpoint":"/api/v1/feedback","body_template":{"kind":"guide-feedback","guide_slug":"become-an-upstream","step_number":"<which step had the issue, or null for whole-guide feedback>","observation":"<what you observed>","expected":"<what you expected>","reporter_contact":"<your email>"}},"html_sibling":"/agents/guides/become-an-upstream"},"_meta":{"spec_version":"1","endpoint":"/api/v1/guides/[slug]","retrieved_at":"2026-05-13T19:58:51.439Z","as_of":"2026-05-13T19:58:51.439Z","sources":["ctcg-derived"],"freshness_seconds":86400,"license":"CC0-1.0","request_id":"req_a5ba92ac-d1a","deprecation":null,"next_link":null,"self_reference":{"this_endpoint":"/api/v1/guides/[slug]","contains_self":true},"source_license":["CC0-1.0"]}}