|
| 1 | +# MarketIR consumer examples |
| 2 | + |
| 3 | +This directory holds reference implementations of downstream consumers of the |
| 4 | +MarketIR data set. They are documentation that runs. |
| 5 | + |
| 6 | +## Contents |
| 7 | + |
| 8 | +| File | Purpose | |
| 9 | +| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | |
| 10 | +| `consume.mjs` | Reference consumer — reads the lockfile, verifies sha256 integrity for every locked file, walks the index, and prints a per-tool summary. | |
| 11 | + |
| 12 | +## When to read these examples |
| 13 | + |
| 14 | +- You are building a downstream consumer (e.g. the public mcptoolshop.com |
| 15 | + site, a Slack notifier, a static-site generator integration) and want a |
| 16 | + worked example of the lockfile-verify-then-walk pattern. |
| 17 | +- You are evaluating whether to depend on this dataset and want a 5-minute |
| 18 | + proof that the contract works the way the README claims. |
| 19 | +- You are debugging a "why does my snapshot diverge from the lockfile" issue |
| 20 | + and want a known-good reference implementation to diff against. |
| 21 | + |
| 22 | +## When NOT to copy these examples wholesale |
| 23 | + |
| 24 | +The example uses **relative filesystem paths** to keep the demo runnable from |
| 25 | +a fresh checkout with no setup. A production consumer should: |
| 26 | + |
| 27 | +- Use a **stable URL** (e.g. `raw.githubusercontent.com/<tag>/<path>`) instead |
| 28 | + of relative paths, so the consumer is not coupled to a local checkout layout. |
| 29 | +- **Cache aggressively** — every IR file is content-addressed via the |
| 30 | + lockfile's sha256, so a sha256 match is a byte-for-byte cache hit. |
| 31 | +- **Validate against the published JSON Schema** rather than trusting the |
| 32 | + field shape produced by the example. |
| 33 | +- **Pin to a specific tag** rather than fetching from `main` so a producer-side |
| 34 | + edit cannot change the bytes you depend on without your knowledge. |
| 35 | + |
| 36 | +## Running consume.mjs |
| 37 | + |
| 38 | +From the repo root: |
| 39 | + |
| 40 | +```bash |
| 41 | +node examples/consume.mjs # human-readable summary |
| 42 | +node examples/consume.mjs --json # structured JSON to stdout |
| 43 | +node examples/consume.mjs --root <p> # alternate marketing/ tree |
| 44 | +node examples/consume.mjs --help # full options |
| 45 | +``` |
| 46 | + |
| 47 | +Exit codes: |
| 48 | + |
| 49 | +- `0` — Walked + verified everything successfully. |
| 50 | +- `1` — Integrity failure (sha256 mismatch / unreadable file / schema mismatch). |
| 51 | + |
| 52 | +## What `consume.mjs` actually does |
| 53 | + |
| 54 | +1. Reads `marketing/manifests/marketing.lock.json` (the entry point). |
| 55 | +2. Checks the lockfile's `schemaVersion` against the supported MAJOR; warns |
| 56 | + on mismatch. |
| 57 | +3. For each entry in `lock.files[]`, recomputes `sha256` + `bytes` from disk |
| 58 | + and compares to the lockfile entry. This is the **load-bearing** step — |
| 59 | + without it, the lockfile is "polite suggestion," not "tamper-evident." |
| 60 | +4. Reads `marketing/data/marketing.index.json` and walks `tools[]`, |
| 61 | + `audiences[]`, `campaigns[]`. |
| 62 | +5. For each tool, prints: name, oneLiner, status counts (proven / |
| 63 | + aspirational / deprecated), first 2 messages, and a press boilerplate |
| 64 | + snippet. |
| 65 | + |
| 66 | +## When the consumer contract changes |
| 67 | + |
| 68 | +If you add a new file under `marketing/`, the lockfile-walk step automatically |
| 69 | +picks it up — no consumer change needed. |
| 70 | + |
| 71 | +If you change the **shape** of the IR (e.g. rename a field, add a new top-level |
| 72 | +section), update `consume.mjs` to demonstrate the new field. Drift between the |
| 73 | +schema and this example is a contract-surface bug; the docs domain owns |
| 74 | +flagging it during review. |
0 commit comments