# research/ — where candidates come from now (decision 018, wake 069)

Julio's trusted-channel note of 2026-08-15 07:47 ended the standby of
017 and set the mode: **push from research.** Find friction people
have written down in public; decide what is worth making; only then
design and propose. This directory is the instrument for that.

## The rule that governs everything here

**No CAD until provenance is on disk.** A candidate is admitted only
with: the observed ask (link, date, who), what fails today, why a
printed object is the right answer and not a bought one, and *useful to
whom.* Then a written forecast with a falsifier (BRIM-005 discipline),
then design, then the prediction page, then `outbox/`.

**Who is asking is part of provenance (wake 070).** An issue is an
*outside* ask only if its `author_association` is `NONE` (or `CONTRIBUTOR`
with no commits on the hardware). OWNER / MEMBER / COLLABORATOR asks are
the project's own roadmap — a real gap sometimes, but not a person waiting.
`bin/issue_survey.py '<q>' --repo-meta` prints this per hit; use it, never
the bare API dump. C-01 was mis-graded at 069 exactly here.

Not admissible, ever: anything from Julio's business or its research
(IDENTITY.md); anything previously denied (print-014, rung-4, spring
scale); instruments pointed at my own process unless someone outside
this room asked for one.

## Sources verified callable from a headless wake (069)

| Source | How | Signal quality (first run) |
|---|---|---|
| GitHub issue search | **`python3 bin/issue_survey.py '<q>' [--max N] [--repo-meta]`** (curl under the hood; no auth, search 10 req/min, REST 60/hr — `--repo-meta` spends one REST call per repo) | Real, dated, linkable asks with `author_association`; one quoted noun phrase + `comments:0 created:>…` is the recipe; best at hardware repos |
| Prior-art check | yeggi.com/q/<term> (aggregates Printables/Thingiverse/MakerWorld/Cults) via firecrawl_scrape; then the model page itself | Cheap and decisive — C-02's "what fails today" came from here |
| eBay listing read | firecrawl_scrape with `proxy: "stealth"` + json schema (curl gets a 1.8 kB stub) | price / sold / available — quantifies "useful to whom" |
| firecrawl_search | MCP tool, reaches reddit.com | Works; loose queries return coupon spam — use `site:` + a quoted phrase; `tbs=qdr:m` for last month |
| Reader mail (`/say`) + `/call` | already logged | One intake among several now, not the queue |
| Printables comments | GraphQL `searchPrints2` + `print(id){comments{text created}}` (072; introspection off, shapes in `003`) | **Retired (004, two passes):** every real ask is a variant request to an active author — supply-side, not "nobody has made this" |
| Reddit RSS | `www.reddit.com/r/<sub>/new/.rss` or `/search/.rss?q=…&restrict_sr=1&sort=new` (072) — `.json` 403s, firecrawl refuses reddit outright | Rationed: 429 after ~6 fetches/min. `r/3Dprintingrequests` is dead (one 2023 post); `r/functionalprint` search is a show sub (004). **Retired** |
| GitHub by **population** (004, 005) | `language:"KiCad Layout"` (tiny: ~7 issues/mo, all electronics) · `search/repositories?q=topic:… pushed:>…` → `repo:a repo:b …` OR-list census | Works — surfaces real outsider asks about printed parts, but almost all are *supply-side* to an active author (release CAD, missing STL). **005: abandonment filter (`pushed:<` a year) tried on 97 repos → 13 unanswered outsider issues, 0 object asks — abandoned repos don't receive asks; retired as a route.** Tool now `bin/repo_census.py` |
| **Stack Exchange** (006) | **`python3 bin/se_census.py fetch <site> [--days N]` → `research/data/se-<site>.jsonl`; `grep <regex> <files>`** — public API, 300 req/day anonymous, 25-page cap per query | **The first DEMAND-side source**: outsiders by construction, dated, `is_answered`, score + views. Thin (~15 print-plausible asks / 10,635 Qs / yr across 26 sites; 3dprinting.SE = 69 Qs/yr, the asks live on diy / bicycles / lifehacks / mechanics). Product-specific asks found were **all answered by prior art the asker never found** (Magicshine EVO 1700, X-ACTO cap, downspout adapter). Re-run quarterly. | **007: READ-ONLY, permanently** — diy + mechanics ban AI content outright; bicycles/lifehacks allow it only "referenced" (a rule for humans citing tools); Inauthentic Usage = one account per *individual person*; AUP bars automated systems. Three bars, `decisions/020`. The API read stays sanctioned. |
| **MakerWorld comment threads** (007) | firecrawl `proxy: "stealth"` + JSON schema on the model page, ~9 credits, returns ~40 comments with make/like/download counts | **Not a demand source** — ~90 % make testimonials, native ask = variant/scale request to the author (same verdict as Printables, 004). **Keep as a VALIDATION instrument**: make count + fit-complaint ratio answer "does the prior art actually hold?" (C-05: 304 makes, 3/41 fit complaints → holds; C-02's Printables shell: 0 makes → F1 is the only test). One read per candidate, not browsing. |
| **r/3Drequests** (008) | `curl -A "brim-agent/0.1 (AI agent; research feed reader, 1 fetch/4.5h; https://brim.thestudiolab.dev)" https://www.reddit.com/r/3Drequests/new/.rss` → 25 newest (Atom), served to an identified AI UA (200 at 078); a second fetch a minute later = 429. **Rule (009/021 C2): ONE identified fetch per wake, no browser-UA masquerade, until the Data API is the read path.** Rules at `old.reddit.com/r/3Drequests/about/rules/` (archived 08-16) | **ADMITTED — the densest demand-side source found**: 25 posts / 10 d, 6 of 25 are "functional part for a named product", budgets $10–100. Yields BOTH classes: discoverability failures (Skådis holder — ≥20 designs, 2 parametric) and a genuine gap (C-07 Wahl 5-Star Legend). **Delivery there DECIDED at 078: deliverable, conditionally (`decisions/021`, read in `009`)** — no sitewide AI/bot ban, bots are a named Developer-Terms App class, Data API + OAuth is the sanctioned path; eight conditions (disclosed, API-only, solicited-only, deliver-don't-promote, free, no votes/alts, sub rules, low rate). **`other-005` FILED at 079** (account + script app; terms = 021's eight conditions; NOT for C-07 — four humans DM'd it within 6 d, no prior art exists; first act gated on a thread with prior art in hand; fallbacks A read-only app / B deny). Why filed on the class, not an instance: threads here close in hours-to-a-day (Skådis <1 d; C-07 first DM at 2 h 27 min) and proposal→account is ≥ half a day. Zero new posts at 078; C-07 thread read at 079. **080: feed re-pulled (one identified fetch, 200, `data/reddit-3Drequests-new-2026-08-16c.rss`), diffed against 078: ONE new post in ~9 h — `1vq3zbf`, a 3.5" HDD + 92 mm fan enclosure with a clip for a Dell OptiPlex 7060 SFF top-cover lip → C-08 NOTED in SHORTLIST (no exact prior art on either half; chassis not here; delivery pending). Rate holds at ~2.5 posts/day. Diff tool: `python3 bin/reddit_feed_diff.py OLD.rss NEW.rss [--full]` (tags LATE/AGE/REMOVED since 091). Rate model: `python3 bin/feed_rate.py [W_hours]` (093) — union of all archives → rate, gap quantiles, P(zero in a W-h window) Poisson + empirical; at 093: 2.74/day, P(flat 4.6 h) = 0.60.** **081: re-pulled (200, `data/…-2026-08-16d.rss`), diffed vs 080: ONE new in ~4.5 h — `1vq9n2d`, a fantasy-football trophy from a ChatGPT image (decorative, personalised; not a candidate). C-08 unchanged in-window; C-07 aged out of the 25-window. Window tally: 3 of 25 posts name an AI-generated image as their spec — a count to keep, not yet a finding.** **085: `other-005` APPROVED then WALLED — app registration blocked by Reddit's Responsible Builder gate (`011`); reading unchanged, delivery by proposal to Julio's hand; per-wake feed status continues in SHORTLIST.** |

| **Other request boards** (010, wake 082) | WebSearch for the class + one identified `curl` per hit + Discourse `categories.json` | **NULL — the class has ONE live member, r/3Drequests.** Pinshape forum = 301 loop (dead); 3dprintdood = 2024 static shell; 3dprintboard = 403 to the honest UA; Thingiverse groups = 404; Bambu forum = live Discourse with no request category (supply side). Not on a schedule; only if a board is named. |
| **Reddit app-registration surface** (011, wake 085) | Julio, by hand at `/prefs/apps`, both a new account (script app) and an established one (web app); my own reads of the two cited sources under the honest UA | **CLOSED — Reddit's Responsible Builder Policy (self-serve app creation ended 2025-11-11) blocks new apps regardless of account age; manual approval only.** u/brim-agent exists, disclosed, app-less. `021` C2's API post path is closed, not pending: **read = one RSS fetch/wake (unchanged); deliver = draft the comment to `outbox/` for Julio's hand.** Not an 018 falsifier. Primary source 403s to me (Cloudflare); secondary is a scraping vendor (bias flagged). Reopens only if `REDDIT_*` appears in the env. |
| **The widened slate** (014, wake 225) | Julio's three 09-27 notes: 13 candidate sources (iFixit Answers, BGG, Brave-as-feed, MMC/e-NABLE, GitHub Discussions/Hackaday, NHTSA, CPSC, Lemmy/Mastodon, RV/RC forums, HN Algolia, patents, YouTube-with-a-key, more subreddits) + **the 021 one-fetch cap LIFTED** (ceiling to be fixed by the cold judge; UA text changes before the rate does) | **JUDGED 226:** ceiling fixed (≤3 distinct subs/wake, per-sub ≤1/4.5 h, UA text updated first — 021 wake-226 addendum); survey #1 iFixit Answers PASSED 012's bar, ADMITTED for discovery (row below); rotation next: Brave-as-feed, then BGG; one survey per wake; NULL is a finding. |
| **iFixit Answers** (014, wake 226) | `curl -A "brim-agent/0.1 (AI agent; research feed reader; https://brim.thestudiolab.dev)" https://www.ifixit.com/Answers/RSS` → 50 newest activity items (questions carry the device name in the title; `Answer to:`/`Comment on:` prefixes are not questions). robots.txt: `ai-input=yes, ai-train=no`, `Disallow: /api/*` → RSS is the read path, never the API. One fetch per full wake. | **ADMITTED for discovery (226)** — 26 questions/10.6 h ≈ 59/day, every one names its device (cures 012's r/fixit failure); bar half 1 PASS (~2.3/day print-plausible, strictest count), half 2 PASS (`974113` JBL Xtreme 2 charge-port cover: Printables specific `[]` beside live broad control, broad Brave adjacent-parts only). Archive `data/ifixit-answers-rss-2026-09-27a.xml`. **Delivery NOT decided** — rules+account = future proposal; gaps feed the Workshop (018 provenance). |
| **Widening the RSS class** (012, wake 088; surveyed 089) | Julio's 08-18 offer (r/functionalprint / r/fixit / r/AskEngineers). r/fixit surveyed: one identified fetch (12:31 slot, archived …fixit-new-2026-08-18.rss), read cold at 089 | **NULL — NOT ADOPTED (089).** r/fixit ≈ 40 posts/day, ~20/25 photo-only specs, 2–3/25 print-plausible in kind but zero name an object → the C-07/C-08 failure class at 17× the rate; nothing gradable by presence (window ~15 h). No decisions/022. Superseded text follows: brief for the cold judge (089). Constraints measured: r/3Drequests' 25-window is ~10 d deep, so fetching it every other wake loses nothing and frees a fetch for a survey; multireddit merges are the wrong shape (shared window); C3 makes non-request subs discovery-only. Protocol proposed: one survey fetch on r/fixit, admit only on ≥1 print-plausible object-specific ask/day incl. one yeggi can't answer; else NULL. Not a reversal of 010 (different class). |

Untested list from 069 is now EMPTY (007): MakerWorld characterized (row above), product-review complaint mining
(**Amazon `/product-reviews/` is sign-walled even via stealth — 006 addendum;**
only `/dp/` top reviews or profile-page snippets remain) ("missing bracket", "no
mount for"), open-hardware issue trackers by label.

## Files

- `NNN-<slug>.md` — one dated survey per file: queries run verbatim,
  what came back, what was admitted to the shortlist and why, what was
  rejected and why. Append-only, like the wake log.
- `SHORTLIST.md` — the living list of admitted candidates with their
  provenance blocks. Rewritten as candidates enter, advance, or die.
