# VOC-EmiJay-01 — Capture Coverage & Gap Log

**Study:** emijay · **Window:** 12 months · **Captured:** 2026-07-16
**Focal:** Emi Jay · **Competitors:** Kitsch, Chunks, Machete, Invisibobble, Slip
**Total records:** 3,356 (corpus.jsonl)

## Coverage matrix (source × brand)

| Source | emi_jay | kitsch | chunks | machete | invisibobble | slip | _topics |
|---|---|---|---|---|---|---|---|
| reddit | 42 | 173 | 301 | 4† | 68 | 494 | 1641 |
| youtube | 99 | 12 | 120 | 209 | 82 | 55 | — |
| instagram | 8 | 8 | 11 | 8 | 8 | 8 | — |
| onsite | — | walled | walled | walled | 5 | walled | — |
| tiktok | GAP | GAP | GAP | GAP | GAP | GAP | — |

By source: reddit 2723 · youtube 577 · instagram 51 · onsite 5

## Documented gaps (findings, not silent failures)

1. ~~**TikTok — full gap.**~~ **RESOLVED 2026-07-17:** captured 388 records via a hybrid
   path — video discovery through the logged-in web-cli session (`dp-tiktok-session`,
   residential egress) + comment harvesting via the Apify `clockworks/tiktok-comments-scraper`
   actor ($0.48). The pure browser path could NOT read comments (see method notes below).

2. **Onsite reviews — 5 of 6 domains walled.** Only invisibobble.com (Judge.me public
   widget) was readable (5 reviews, its public cap). emijay.com, mykitsch.com,
   shopmachete.com, slip.com all detect **Yotpo** but return 0 via the public widget API
   (tokenized/JS-walled tail — capture footgun #5). chunksforall.com: fetch_fail
   (datacenter-IP block). Documented and skipped per the <15-min-per-domain rule.

3. **Reddit "machete" = 4, and they are NOT the hair brand.** "Machete" is a common word;
   the 4 listing hits are noise ("Machete vs Coca-Cola" mentos experiments, etc.). Machete
   (the hair-accessory brand) has effectively **zero organic Reddit brand chatter** — a real
   finding about the brand's small footprint, not a capture failure. Real Machete voice comes
   from YouTube (209) + IG (8).

## Method notes / footguns hit this run

- **TikTok hybrid path (worked):** web-cli logged-in session (`dp-tiktok-session` +
  spider residential shim) handles **search/discovery** fine, but the browser could NOT
  read comments: TikTok returns the signed `/api/comment/list/` with an **empty body
  (200, len 0)** to the automated browser — headless AND headful, JS click AND real
  mouse click — and the comment sidebar stays empty (only "Add comment..." renders).
  Fix: discover video URLs in web-cli, then harvest comments via the Apify
  `clockworks/tiktok-comments-scraper` actor (server-side signing). $0.48 for 388 records.
  Also: TikTok SPA navigations race — always interstitial `about:blank` between
  `page.goto()` calls, and use `domcontentloaded` not `commit`.
- **Arctic-Shift search endpoint (mentions/comments verbs) was 422-throttled** the entire
  run. Pivoted to the **listing path** (`posts <sub> --query`, local keyword match) per
  capture footgun #4 — fully replaced search for brand-mention capture. `tree` (comment
  depth) worked fine.
- **Pipe-alternation bug:** the scraper's `--query` local matcher treats `"A|B"` as a
  literal, not an OR. Focal `emi_jay` initially captured 0 because its query was
  `"Emi Jay|emijay"`; re-ran with single-token `"Emi Jay"` → 42 records. All other brands
  used single tokens and were unaffected.
- **Instagram:** installed scraper is **Apify-backed** (config's `--direct` note is stale).
  `posts <handle>` returned 0 (handle-resolution quirk); `hashtag <tag>` works. Ran low-volume
  (8 posts/tag) per DP $0-marginal convention; total Apify cost ≈ **$0.02**.
- **Reddit topic trees:** pulled full comment trees on the top 20 highest-engagement
  hair-accessory threads (capped + wall-clock budget per footgun #11).

## Quality caveats for analysis (capture-wide-filter-downstream)

- **`brand` tag is a capture bucket, not verified attribution.** YouTube sweeps pull all
  comments from videos that *ranked* for a brand query — many comments don't name the brand
  (e.g. emi_jay: 54/149 explicitly name Emi Jay). Lenses MUST attribute per-record via
  keyword + Reddit lineage, not trust the capture `brand` field.
- **`lang` is null on ~all records** (scrapers didn't populate it). Filter non-English at
  analysis if needed; corpus is overwhelmingly English by subreddit/channel selection.
- **_topics (1641)** is the track-1b discussion bucket (brand-agnostic category threads +
  full comment trees) — attribute brands downstream from comment text + thread lineage.

## Gate status: PASS (with documented gaps)
Every enabled source × brand cell is filled or explained. TikTok is the one full-source
gap (attended-session blocker, logged). Ready for consolidate → analysis.
