Primary-Research / Channel-Check Harvester (finance-desk role #4 — the weakest leg)
The desk's job here is ground-truth: what do people who actually use the product, attend
the concalls, and dig into the filings say — does it corroborate or disconfirm the dossier?
This is the only finance-desk role with no canonical free data source (no Bloomberg/Refinitiv
equivalent for retail), so it is the weakest leg by design. Treat its output as questions to
verify, never as fact, and never let it move a grade.
This leg earns its keep ONLY by disconfirming ([[primary-research-earns-edge-only-by-disconfirming]]).
Because markets aggregate public information efficiently, a harvest that confirms a popular long adds
nothing — that view is already priced. The only durable contribution is (a) a fact that disproves a
pillar of the thesis (a moat-bust, a channel breakdown), or (b) a checkable hard fact / forensic lead.
Frame every run as an attempt to break the thesis, not to cheer it.
What this is / isn't (read before running)
- Output = LIVE DD CONTEXT, written to
extracted/research/source_captures/<TICKER>_primary_research.md
— exactly like the existing dossier/source captures. It feeds Stage 1 (dossier / understanding)
of stock-onboarding-pipeline and the forensic-accounting-redflags screen as corroboration /
disconfirmation.
- It is NOT vault atomics. Do NOT write to
vault/canon or vault/perspectives, do NOT
touch the brain index. Munger/Buffett (the binding CIO via 32_consult_brain.py) remain the sole
arbiter of verdict, conviction and MoS. This skill supplies context, never a verdict.
- Weakest-leg honesty (state it in every capture). Indian retail community quality varies wildly;
ValuePickr & Reddit are self-selected and often talk-their-book; concalls are management's own framing.
Weight every signal with human judgment and down-weight it hard against the vault.
- Epistemic ceiling (the EMH limit — state it too). Public chatter about a well-followed name is mostly
already in the price. So this harvest's only durable output is a disconfirmation or a checkable hard
fact — never a confirmation of a crowded long. A glowing forum consensus is not a buy signal; at most it is
a sentiment-froth datum (see STEP 5). This is the binding resolution of the efficiency tension: Damodaran's
efficiency view is cited here to limit the skill's claims, never to license acting on crowd information.
Division of labour: the SCRIPT does the cheap scrapes, YOU do the MCP + judgment
- Script (
data/scripts/61_harvest_primary_research.py) does the parts that are scriptable and
cheap: paginated ValuePickr capture (Discourse .json API), screener.in transcript-PDF discovery +
pdftotext extraction, and a generic-web fallback that reuses capture_web from
60_ingest_external.py (defuddle → Apify). Apify spend ≈ $0 (defuddle/JSON first).
- You (the agent) do what a standalone script can't: the Reddit step (Reddit MCP) and the
final synthesis. A script has no MCP access, so the Reddit pull is agent-only — this is explicit
in the generated file.
STEP 0 — Frame the harvest as disconfirmation (+ pull the standing arbiter frame)
Before scraping, write down the dossier's core bull thesis in one line, then run the whole harvest as an
explicit attempt to disprove it. Anchoring to the existing view is the failure mode here
(avoid-anchoring-and-destroy-previous-ideas); a harvest that only confirms is flagged as anchoring and
re-run with bear-case queries (" problems / fraud / churn / competition / promoter").
Then pull the standing arbiter frame from the desk/binding layer via --corpus blended — it admits the
desk atomics alongside the binding mentors, kept on relevance to the query:
set -a && source /Users/Dhiraj/dev/invest/.env && set +a && /Users/Dhiraj/dev/invest/.venv/bin/python \
/Users/Dhiraj/dev/invest/data/scripts/32_consult_brain.py \
--company "<name> primary research disconfirming channel checks promoter credibility" --model general --step understanding --corpus blended \
--json-out extracted/grilling/<TICKER>_primary.json
This surfaces [[primary-research-earns-edge-only-by-disconfirming]] and [[loudest-promoter-is-least-credible-source]]
ALONGSIDE the binding arbiter atoms (beware-fraudulent-information-sources, do-not-talk-up-your-investments).
The desk atomics are connective tissue, not a vote — they never set verdict/conviction/MoS.
STEP 1 — Run the harvester (ValuePickr + screener, scriptable)
First find the ValuePickr thread URL (web-search forum.valuepickr.com <company> — the thread id is the
number in /t/<slug>/<id>). The screener URL is derivable from the ticker. Then:
set -a && source /Users/Dhiraj/dev/invest/.env && set +a && /Users/Dhiraj/dev/invest/.venv/bin/python \
/Users/Dhiraj/dev/invest/data/scripts/61_harvest_primary_research.py \
--ticker <TICKER> \
--valuepickr-url "https://forum.valuepickr.com/t/<slug>/<id>" \
--screener-url "https://www.screener.in/company/<TICKER>/consolidated/"
This writes extracted/research/source_captures/<TICKER>_primary_research.md with the ValuePickr
bull/bear raw signal + the discovered transcript links, and leaves clearly-marked TODOs for the Reddit
and synthesis steps. It is idempotent — re-runs read the cache under
data/apify_runs/_primary_research/<TICKER>/ and re-spend nothing (use --force to re-fetch).
Notes:
- ValuePickr topic pages are JS-rendered, so
defuddle/capture_web return 0 chars — the script uses
the Discourse .json API instead (free, structured, richer). It captures the latest N×20 posts
(recent sentiment is what matters); raise --max-vp-pages for more history.
- Transcript PDFs are hosted off-site (investor-relations / primeinfobase / BSE). Reachable ones are
pdftotext-extracted (free); unreachable hosts are recorded as links in the file for you to fetch
(browser, or the capture_web Apify fallback) — never silently dropped.
STEP 2 — Reddit sentiment (AGENT-ONLY, Reddit MCP)
A standalone script has no MCP, so you run the Reddit MCP directly (mcp__reddit-search__*):
mcp__reddit-search__search_reddit(query="<TICKER> stock", limit=10, sort="relevance")
mcp__reddit-search__search_reddit(query="<company name>", subreddit="IndiaInvestments")
# then for the best DD/sentiment hits:
mcp__reddit-search__get_post_comments(post_id="<id>")
Useful India subs: IndiaInvestments, IndianStockMarket, DalalStreetTalks. Capture a 3–5 bullet
sentiment gist: net bullish/bearish, recurring concerns, any on-ground channel checks.
- Source-weighting (apply to every forum/Reddit/concall voice): rank credibility inversely to how
hard the voice talks its book (
[[loudest-promoter-is-least-credible-source]], do-not-talk-up-your-investments).
Down-weight the loudest promoters by default; prefer skin-in-the-game, specific, disconfirmable claims over
costless cheerleading. A confident price target is the weakest kind of signal; a verifiable on-ground
fact (a closed store, a lost client, a delayed payment) is the strongest.
- If the MCP rate-limits (HTTP 403/429 — common): retry with backoff, narrow the query, or fall back
to
WebSearch over reddit.com. Confirm the server with mcp__reddit-search__test_reddit_mcp_server.
- Reddit Responsible-Builder policy: corroboration only — no de-anonymising users, no model-training
use, no cross-posting. Read-only.
STEP 3 — Management-call red/green flags (screener transcripts)
Read the extracted transcript(s) in data/apify_runs/_primary_research/<TICKER>/ (or fetch the recorded
links). Pull:
- RED: guidance cuts, evasive/non-answers, pricing-power erosion, churn, rising receivables/promoter
pledge, related-party deals, "growth at any cost" tone, blaming macro for everything.
- GREEN: candid acknowledgement of misses, durable pricing power, capital discipline, owner-operator
language, consistent multi-year framing.
This is the input that most usefully overlaps with
forensic-accounting-redflags. The top tripwire is
not generic "earnings-quality concern" — it is cash conversion: does the concall narrative of profit
show up as cash? Route any growth-without-cash, rising-receivables, or aggressive-revenue-recognition signal
straight to the CFO/PAT check ([[channel-check-as-forensic-tripwire]], owner-earnings-as-quality-proof:
high, stable CFO/PAT corroborates management integrity; a widening gap is the lead to chase against the
filings in the forensic screen).
STEP 4 — Employee sentiment (optional, low weight)
Check ambitionbox.com / glassdoor.co.in for the company: overall rating, attrition, leadership churn,
culture flags. An execution-quality proxy only — weight near zero unless it corroborates a
transcript/forum concern.
STEP 5 — Synthesise into the capture file (hedged)
Fill the "Synthesis for the dossier" block: ValuePickr bull/bear (+ open questions), Reddit gist,
mgmt-call red/green flags, employee-sentiment note, and a hedged net read ("corroborates /
disconfirms the dossier because …, BUT this is the weakest leg — verify independently"). Then point the
Stage-1 dossier author and the forensic screen at this file. Do not translate any of it into a
conviction/verdict/MoS number — that is the vault's job.
- Read the crowd contrarily (
[[crowd-sentiment-read-inversely]], be-fearful-when-others-are-greedy):
record the net sentiment as a contrarian datum — unanimous euphoria is a yellow flag (froth, already
priced), capitulation/disgust is a potential window. Subordinate to the gates: a capitulation signal is
a window only after the binding moat + owner-earnings checks pass; contrarianism on a genuinely broken
business is just catching a falling knife. This datum never overrides the fundamental verdict.
How it plugs into the onboarding pipeline
- Stage 0/1 (dossier & understanding): run this harvester for each NEW stock alongside the
Substack-article capture; the dossier's "Comment-thread red flags" / ground-truth context section
cites it. It is context for understanding, parallel to — never above — the binding circle-of-
competence consult.
- Forensic screen: transcript red flags + ValuePickr fraud/governance chatter feed
forensic-accounting-redflags as leads to verify against filings.
- It changes no grade. After running, the normal binding consult (
--corpus binding) and the v2
conviction/MoS/inversion gates proceed unchanged.
Hard rules
- Output is LIVE DD context, never binding. Write only to
extracted/research/source_captures/<TICKER>_primary_research.md. Never write vault atomics, never
touch the brain index, never set/adjust conviction, verdict or MoS.
- Reddit is agent-only (MCP). The script cannot do it; you must. Honour the Responsible-Builder
policy and handle 403/429 gracefully (retry/backoff/WebSearch fallback).
- Reuse, don't rebuild. Generic web URLs route through
capture_web (60_ingest_external.py);
prefer free paths (Discourse .json, pdftotext) so Apify spend stays ≈ $0. Never write empty
captures — record a blocked source as a TODO link instead.
- State the weakest-leg caveat in every capture. Community quality varies; this is corroboration /
disconfirmation, requiring human judgment to weight — not a thesis, and not a substitute for the
Munger/Buffett CIO.
- Attribute, quote sparingly, never fabricate. Quote ValuePickr/Reddit by username and date; if a
source returns nothing, say so and count it — never invent sentiment or a transcript quote.
- Disconfirm or surface a hard fact — don't echo. The edge is disconfirmation
(
[[primary-research-earns-edge-only-by-disconfirming]]); a pure confirmation of a crowded long is
already priced and worthless. But disconfirmation-first must NOT tip into motivated bear-hunting: a
manufactured red flag is no more binding than a manufactured bull case (rule 5 still governs). Weight
voices inversely to how hard they talk their book. The desk atomics
(vault/desk/primary-research/atomic/…) are connective tissue you cite via [[slug]] — you do not
create or edit them, and they never cast a verdict vote.
1---2name: primary-research-sentiment3description: Use when onboarding/grading an Indian stock and you need LIVE ground-truth — retail due-diligence, management-call commentary, and community sentiment — to corroborate or disconfirm a dossier. This is the finance-desk "channel-checker / primary-research harvester" (role #4, the weakest leg). Harvests ValuePickr forum DD, Reddit sentiment (via the Reddit MCP), screener.in earnings-call transcripts, and optional employee sentiment into extracted/research/source_captures/<TICKER>_primary_research.md. It is LIVE DD CONTEXT for the Stage-1 dossier + the forensic screen — NOT vault atomics, and it NEVER sets verdict/conviction/MoS (the Munger/Buffett vault is the binding arbiter). Triggers: "channel check <ticker>", "what does ValuePickr/Reddit say about <ticker>", "primary research on <ticker>", "harvest sentiment", "ground-truth this dossier", "management call red flags".4---56# Primary-Research / Channel-Check Harvester (finance-desk role #4 — the *weakest leg*)78The desk's job here is **ground-truth**: what do people who actually use the product, attend9the concalls, and dig into the filings say — does it *corroborate* or *disconfirm* the dossier?10This is the only finance-desk role with **no canonical free data source** (no Bloomberg/Refinitiv11equivalent for retail), so it is the *weakest leg by design*. Treat its output as **questions to12verify**, never as fact, and never let it move a grade.1314**This leg earns its keep ONLY by disconfirming** (`[[primary-research-earns-edge-only-by-disconfirming]]`).15Because markets aggregate public information efficiently, a harvest that *confirms* a popular long adds16nothing — that view is already priced. The only durable contribution is (a) a fact that **disproves** a17pillar of the thesis (a moat-bust, a channel breakdown), or (b) a checkable **hard fact / forensic lead**.18Frame every run as an attempt to break the thesis, not to cheer it.1920## What this is / isn't (read before running)21- **Output = LIVE DD CONTEXT**, written to `extracted/research/source_captures/<TICKER>_primary_research.md`22 — exactly like the existing dossier/source captures. It feeds **Stage 1 (dossier / understanding)**23 of `stock-onboarding-pipeline` and the `forensic-accounting-redflags` screen as *corroboration /24 disconfirmation*.25- **It is NOT vault atomics.** Do **NOT** write to `vault/canon` or `vault/perspectives`, do **NOT**26 touch the brain index. Munger/Buffett (the binding CIO via `32_consult_brain.py`) remain the **sole**27 arbiter of verdict, conviction and MoS. This skill supplies *context*, never a *verdict*.28- **Weakest-leg honesty (state it in every capture).** Indian retail community quality varies wildly;29 ValuePickr & Reddit are self-selected and often talk-their-book; concalls are management's own framing.30 Weight every signal with human judgment and down-weight it hard against the vault.31- **Epistemic ceiling (the EMH limit — state it too).** Public chatter about a well-followed name is mostly32 *already in the price*. So this harvest's only durable output is a **disconfirmation** or a **checkable hard33 fact** — never a confirmation of a crowded long. A glowing forum consensus is not a buy signal; at most it is34 a sentiment-froth datum (see STEP 5). This is the binding resolution of the efficiency tension: Damodaran's35 efficiency view is cited here to *limit* the skill's claims, never to license acting on crowd information.3637## Division of labour: the SCRIPT does the cheap scrapes, YOU do the MCP + judgment38- **Script** (`data/scripts/61_harvest_primary_research.py`) does the parts that are scriptable and39 cheap: paginated ValuePickr capture (Discourse `.json` API), screener.in transcript-PDF discovery +40 `pdftotext` extraction, and a generic-web fallback that **reuses `capture_web` from41 `60_ingest_external.py`** (defuddle → Apify). Apify spend ≈ $0 (defuddle/JSON first).42- **You (the agent)** do what a standalone script *can't*: the **Reddit step (Reddit MCP)** and the43 final **synthesis**. A script has no MCP access, so the Reddit pull is agent-only — this is explicit44 in the generated file.4546## STEP 0 — Frame the harvest as disconfirmation (+ pull the standing arbiter frame)47Before scraping, **write down the dossier's core bull thesis in one line**, then run the whole harvest as an48explicit attempt to *disprove* it. Anchoring to the existing view is the failure mode here49(`avoid-anchoring-and-destroy-previous-ideas`); a harvest that only confirms is flagged as anchoring and50**re-run with bear-case queries** ("<company> problems / fraud / churn / competition / promoter").5152Then pull the standing arbiter frame from the desk/binding layer via `--corpus blended` — it admits the53desk atomics alongside the binding mentors, kept on relevance to the query:54```bash55set -a && source /Users/Dhiraj/dev/invest/.env && set +a && /Users/Dhiraj/dev/invest/.venv/bin/python \56 /Users/Dhiraj/dev/invest/data/scripts/32_consult_brain.py \57 --company "<name> primary research disconfirming channel checks promoter credibility" --model general --step understanding --corpus blended \58 --json-out extracted/grilling/<TICKER>_primary.json59```60This surfaces `[[primary-research-earns-edge-only-by-disconfirming]]` and `[[loudest-promoter-is-least-credible-source]]`61ALONGSIDE the binding arbiter atoms (`beware-fraudulent-information-sources`, `do-not-talk-up-your-investments`).62The desk atomics are connective tissue, not a vote — they **never** set verdict/conviction/MoS.6364## STEP 1 — Run the harvester (ValuePickr + screener, scriptable)65First find the ValuePickr thread URL (web-search `forum.valuepickr.com <company>` — the thread id is the66number in `/t/<slug>/<id>`). The screener URL is derivable from the ticker. Then:67```bash68set -a && source /Users/Dhiraj/dev/invest/.env && set +a && /Users/Dhiraj/dev/invest/.venv/bin/python \69 /Users/Dhiraj/dev/invest/data/scripts/61_harvest_primary_research.py \70 --ticker <TICKER> \71 --valuepickr-url "https://forum.valuepickr.com/t/<slug>/<id>" \72 --screener-url "https://www.screener.in/company/<TICKER>/consolidated/"73```74This writes `extracted/research/source_captures/<TICKER>_primary_research.md` with the ValuePickr75bull/bear raw signal + the discovered transcript links, and leaves clearly-marked TODOs for the Reddit76and synthesis steps. It is **idempotent** — re-runs read the cache under77`data/apify_runs/_primary_research/<TICKER>/` and re-spend nothing (use `--force` to re-fetch).78Notes:79- ValuePickr topic pages are JS-rendered, so `defuddle`/`capture_web` return 0 chars — the script uses80 the **Discourse `.json` API** instead (free, structured, richer). It captures the *latest* N×20 posts81 (recent sentiment is what matters); raise `--max-vp-pages` for more history.82- Transcript PDFs are hosted off-site (investor-relations / primeinfobase / BSE). Reachable ones are83 `pdftotext`-extracted (free); unreachable hosts are **recorded as links** in the file for you to fetch84 (browser, or the `capture_web` Apify fallback) — never silently dropped.8586## STEP 2 — Reddit sentiment (AGENT-ONLY, Reddit MCP)87A standalone script has no MCP, so **you** run the Reddit MCP directly (`mcp__reddit-search__*`):88```text89mcp__reddit-search__search_reddit(query="<TICKER> stock", limit=10, sort="relevance")90mcp__reddit-search__search_reddit(query="<company name>", subreddit="IndiaInvestments")91# then for the best DD/sentiment hits:92mcp__reddit-search__get_post_comments(post_id="<id>")93```94Useful India subs: `IndiaInvestments`, `IndianStockMarket`, `DalalStreetTalks`. Capture a **3–5 bullet95sentiment gist**: net bullish/bearish, recurring concerns, any on-ground channel checks.96- **Source-weighting (apply to every forum/Reddit/concall voice):** rank credibility **inversely** to how97 hard the voice talks its book (`[[loudest-promoter-is-least-credible-source]]`, `do-not-talk-up-your-investments`).98 Down-weight the loudest promoters by default; prefer skin-in-the-game, specific, disconfirmable claims over99 costless cheerleading. A confident price target is the *weakest* kind of signal; a verifiable on-ground100 fact (a closed store, a lost client, a delayed payment) is the strongest.101- **If the MCP rate-limits (HTTP 403/429 — common):** retry with backoff, narrow the query, or fall back102 to `WebSearch` over `reddit.com`. Confirm the server with `mcp__reddit-search__test_reddit_mcp_server`.103- **Reddit Responsible-Builder policy:** corroboration only — no de-anonymising users, no model-training104 use, no cross-posting. Read-only.105106## STEP 3 — Management-call red/green flags (screener transcripts)107Read the extracted transcript(s) in `data/apify_runs/_primary_research/<TICKER>/` (or fetch the recorded108links). Pull:109- **RED:** guidance cuts, evasive/non-answers, pricing-power erosion, churn, rising receivables/promoter110 pledge, related-party deals, "growth at any cost" tone, blaming macro for everything.111- **GREEN:** candid acknowledgement of misses, durable pricing power, capital discipline, owner-operator112 language, consistent multi-year framing.113This is the input that most usefully overlaps with `forensic-accounting-redflags`. The **top tripwire** is114not generic "earnings-quality concern" — it is **cash conversion**: does the concall narrative of profit115show up as cash? Route any growth-without-cash, rising-receivables, or aggressive-revenue-recognition signal116straight to the **CFO/PAT** check (`[[channel-check-as-forensic-tripwire]]`, `owner-earnings-as-quality-proof`:117high, stable CFO/PAT corroborates management integrity; a widening gap is the lead to chase against the118filings in the forensic screen).119120## STEP 4 — Employee sentiment (optional, low weight)121Check `ambitionbox.com` / `glassdoor.co.in` for the company: overall rating, attrition, leadership churn,122culture flags. An **execution-quality proxy only** — weight near zero unless it corroborates a123transcript/forum concern.124125## STEP 5 — Synthesise into the capture file (hedged)126Fill the "Synthesis for the dossier" block: ValuePickr bull/bear (+ open questions), Reddit gist,127mgmt-call red/green flags, employee-sentiment note, and a **hedged net read** ("corroborates /128disconfirms the dossier because …, BUT this is the weakest leg — verify independently"). Then point the129Stage-1 dossier author and the forensic screen at this file. **Do not** translate any of it into a130conviction/verdict/MoS number — that is the vault's job.131- **Read the crowd contrarily** (`[[crowd-sentiment-read-inversely]]`, `be-fearful-when-others-are-greedy`):132 record the net sentiment as a **contrarian** datum — unanimous euphoria is a yellow flag (froth, already133 priced), capitulation/disgust is a potential window. **Subordinate to the gates:** a capitulation signal is134 a window *only after* the binding moat + owner-earnings checks pass; contrarianism on a genuinely broken135 business is just catching a falling knife. This datum never overrides the fundamental verdict.136137## How it plugs into the onboarding pipeline138- **Stage 0/1 (dossier & understanding):** run this harvester for each NEW stock alongside the139 Substack-article capture; the dossier's "Comment-thread red flags" / ground-truth context section140 cites it. It is *context for understanding*, parallel to — never above — the binding circle-of-141 competence consult.142- **Forensic screen:** transcript red flags + ValuePickr fraud/governance chatter feed143 `forensic-accounting-redflags` as leads to verify against filings.144- It changes **no** grade. After running, the normal binding consult (`--corpus binding`) and the v2145 conviction/MoS/inversion gates proceed unchanged.146147## Hard rules1481. **Output is LIVE DD context, never binding.** Write only to149 `extracted/research/source_captures/<TICKER>_primary_research.md`. Never write vault atomics, never150 touch the brain index, never set/adjust conviction, verdict or MoS.1512. **Reddit is agent-only (MCP).** The script cannot do it; you must. Honour the Responsible-Builder152 policy and handle 403/429 gracefully (retry/backoff/WebSearch fallback).1533. **Reuse, don't rebuild.** Generic web URLs route through `capture_web` (`60_ingest_external.py`);154 prefer free paths (Discourse `.json`, `pdftotext`) so Apify spend stays ≈ $0. Never write empty155 captures — record a blocked source as a TODO link instead.1564. **State the weakest-leg caveat in every capture.** Community quality varies; this is corroboration /157 disconfirmation, requiring human judgment to weight — not a thesis, and not a substitute for the158 Munger/Buffett CIO.1595. **Attribute, quote sparingly, never fabricate.** Quote ValuePickr/Reddit by username and date; if a160 source returns nothing, say so and count it — never invent sentiment or a transcript quote.1616. **Disconfirm or surface a hard fact — don't echo.** The edge is disconfirmation162 (`[[primary-research-earns-edge-only-by-disconfirming]]`); a pure confirmation of a crowded long is163 already priced and worthless. But disconfirmation-first must NOT tip into motivated bear-hunting: a164 *manufactured* red flag is no more binding than a manufactured bull case (rule 5 still governs). Weight165 voices inversely to how hard they talk their book. The desk atomics166 (`vault/desk/primary-research/atomic/…`) are connective tissue you cite via `[[slug]]` — you do **not**167 create or edit them, and they never cast a verdict vote.