Skip to content

Mockup - #1

Open
aruship4 wants to merge 152 commits into
mainfrom
mockup
Open

aruship4 wants to merge 152 commits into
mainfrom
mockup

Conversation

@aruship4

Copy link
Copy Markdown
Collaborator

No description provided.

APRILjcc and others added 17 commits June 23, 2026 15:15
--html-dir given as a relative path crashed filepath.relative_to(BASE_DIR)
(BASE_DIR is absolute), silently producing an empty prices CSV. Resolve the
path first and fall back to the raw string.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 13-recent-manifest.py: select recent-window snapshots (>=2 quarters, anchored
  2024Q3, >=1 snapshot in trailing 12mo), 7 categories.
- 14-recent-ipi.py: matched-model index (Jevons elementary per category,
  review-weighted geometric composite), quarterly + monthly, trailing-12mo headline.
- run-recent-pipeline.sh: idempotent driver (download retry -> extract -> build).
- gitignore: exclude html-recent/ raw HTML (22GB) and transient .out logs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
15,150/15,309 snapshots (99%), 100% price extraction across 7 categories.
Composite IPI flat over the past year (2025Q1->2026Q1: -0.3%); video -11.6%,
coding -6.8%, writing -6.6%, design +2.1%. Includes per-category indices and
volume-proxy weights for client-side recompute.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- code/15-build-site-data.py: reuse step 14's monthly build to emit
  per-category monthly index -> site/data.json (2.2 KB, trailing 12mo,
  rebased to window-start=100).
- site/index.html + site/ipi.js: category checklist drives live in-browser
  composite recompute (matches pipeline's exp(Sum w.ln/Sum w)).
- Verified: client recompute over all categories reproduces composite_all.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Page wasn't working and the user is building their own site. Removed
site/index.html, site/ipi.js, scripts/deploy-site.sh and deleted the
gh-pages branch. Kept code/15-build-site-data.py + site/data.json as the
data layer for the user's own frontend.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebuilt CSRankings-style site now hand-rolls the trend chart and
sparklines as inline SVG — no Plotly/CDN. Validated: JS syntax OK,
data.json contract complete, client composite reproduces composite_all
(headline -2.1% trailing 12mo). Adds deploy-site.sh redeploy helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ting

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Serve the IPI frontend from /docs (branch mode) instead of the site/
subfolder, which Pages branch mode cannot serve. Drop the Actions
workflow; update the data-build script output path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Self-contained faq.html (no external libs): explains the purpose of the
index and documents the exact formulas — price relatives, chained Jevons
category index, weighted-geometric-mean composite, headline 12mo change,
and review-based weights — with CSS-rendered math. Cross-linked from the
main index header.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@haojian
haojian temporarily deployed to github-pages June 30, 2026 18:53 — with GitHub Pages Inactive
Polished, still fully self-contained (no external libs/CDN): Inter/system
font stack, soft canvas with white rounded cards + subtle shadows, indigo
accent, inline-SVG logo + favicon, pill basket toggles, refined table and
tooltip, responsive tweaks. FAQ restyled to match (TOC card, paper card,
boxed formulas). All JS hooks and the data contract are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@haojian
haojian temporarily deployed to github-pages June 30, 2026 19:40 — with GitHub Pages Inactive
…ection

- index.html: add full-sentence IPI definition directly beneath the page title
- index.html: lay out trend chart (left) and category-selection table (right)
  side by side via CSS grid, collapsing to stacked below 900px; widen wrap
- faq.html: matching aesthetic refresh

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@haojian
haojian temporarily deployed to github-pages June 30, 2026 20:29 — with GitHub Pages Inactive
- ipi.js: significantMoves() flags MoM moves past 0.8% plus the biggest
  rise/drop; drawChart overlays a green/red segment + labeled % on the
  composite line, recomputed live as categories are toggled
- index.html: legend caption under the chart (green=rise, red=drop)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@haojian
haojian temporarily deployed to github-pages June 30, 2026 20:53 — with GitHub Pages Inactive
haojian and others added 30 commits August 26, 2026 23:15
The root was hardcoded to /home/exouser, so the notebook ran on exactly one
machine. It is now discovered by walking up for CLAUDE.md + data/, and a
preflight cell reports which of the four tiers are actually present.

Sections degrade instead of raising. The price panel picks the largest file
on hand, falling back from the gitignored balanced-prices.csv (292,447 rows)
to the tracked recent-prices.csv (15,150), so a clone gets a real panel. The
cdx and HTML sections print what they need and skip; duckdb is an optional
import.

Verified both ways: full collection machine, 0 errors, all four tiers OK;
and a `git archive HEAD` tree — 44 MB, exactly what a clone gets — also 0
errors, with three clean SKIPs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… ChatGPT

`balanced-prices.csv` is 88 MB and gitignored, so the notebook could not be run
from a clone -- `first_present()` fell through to the thin `pilot-prices.csv`
without saying so. The panels compress ~11x (88.6 -> 7.9 MB, 25.8 -> 2.9 MB),
smaller than `pilot-prices.csv` which was already tracked, so the "exceeds
GitHub's limits" reasoning held only for the raw CSV. Commit the gzips, keep the
raw files ignored; `pd.read_csv` reads .gz transparently so no analysis code
changed. `balanced-gig-category.csv.gz` (0.9 MB) joins them because the category
source was a 51 MB manifest also ignored, which would have broken the index and
event-study sections on a clone even with prices fixed.

code/64 adds the panel builder and a two-way FE event study -- gig effects
absorbed by within-gig demeaning, SEs clustered on gig, numpy only so a bare
clone can run it. The GEKS index is imported from code/21 unchanged rather than
reimplemented, so the notebook plots the papers' estimator.

On the 16,128 gigs observed both sides of 2022Q4: the pre-trend is +0.047 log
points per quarter (t = 42) and linear to within 0.02 across eleven quarters,
nothing breaks at the launch, and the series ends 2024Q4 at -0.213 log points
against the extrapolated trend, same sign in all seven categories. The last
number is not identified -- no control group, and a linear counterfactual run
eight quarters past its data. Held out of the drafts in plans/todo.md until a
placebo cut or the step 61 niche design clears it.

Verified by cloning the repo and executing the notebook there: 85 s, 0 errors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QfFt4d1Q4AkwPAnNCyYgTf
Section 7 was one chart of seven nominal lines. It is now two: the GEKS-Jevons
matched-model index over 35 narrow buckets, nominal, and the same index deflated
by CPI-U. Both grids share a y-axis, so the gap between them is general inflation.

Nothing is reimplemented. code/66-narrow-real-geks.py wires together the
estimator (step 21), the narrow taxonomy (step 16) and the deflator (step 23);
the notebook imports it.

Two results the broad chart could not show. All 35 buckets clear 20/20 quarters
at pair_density 1.00, so step 16's thin-subcategory warning was about the recent
monthly manifest, not about quarterly matched-model indexing. And deflation --
CPI-U rose 22.3% across the window -- changes no sign: real increases run +3% to
+155%. The only two intervals covering zero are Subtitles & Transcribe (+3.1%
real) and Translation (+5.5%), the most AI-exposed cell on any crosswalk the
project uses. Its own keyword remainder, translation-other, is +51.2%, so the
next move is auditing those keywords rather than reading the result.

Still no break at the ChatGPT line, at either level, nominal or real.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016G3pDU1a5BRbp2udySwGXt
…that name themselves

Working-tree files from the preceding sessions, checked in as they stand:

- code/60,61 -- niche construction and the niche-level event study (design 9)
- code/63,63b -- live-recovery calibration and the reach curve behind it
- code/65 -- the event-study figure, plus its PDF/PNG outputs
- data/pilot/niche-{arrival,assignment}.csv, the 2026-08-21 sitemap snapshot
- docs/ipi.js -- volume and transaction charts label which series each peak
  belongs to, because accrual, buyers, orders and real GMV peak in different
  years and an unqualified "peak" invited the wrong reading

One fix on the way in: the new real-GMV label referenced an undefined C_GMV,
which would have thrown on every render of the transactions chart. It is
TX_COLORS.gmv_real, the colour the series is already drawn in.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016G3pDU1a5BRbp2udySwGXt
A user looked at the fine-grained chart and said the coding line looked
suspiciously high. It is high, and the reason is worth more than the chart.

Two diagnostics in code/66-narrow-real-geks.py, both reusing step 21's walk:
geks_variant() swaps the bilateral aggregator (median-of-logs in place of the
mean Jevons is defined as), floor_shares() reports the cheap end. A cell in §7
runs them. The plotted index is unchanged.

Coding's matched 2020Q1->2024Q4 log changes are 0.00 / 0.69 / 2.07 at the
20th/50th/90th: the typical matched gig exactly doubled, the top decile went
eight-fold, and Jevons averages logs, so the plotted +145% sits far above the
median-of-logs +74%. It is not outlier contamination -- 1% trimming moves it 0.5
index points. And the level is frame-dependent: the same estimator ranks coding
first here and fourth on the panel frame the site publishes, where audio leads.

The explanation that looks obvious fails, and is recorded as failing. Listings
entering at or below $10 reprice 2-3x faster per observed quarter than dearer
ones in every family, so the retiring $5 floor lifts every line -- but it does
not order them: translation is the most floor-heavy family (64.5% at or below $5
in 2020) and the flattest series on the chart.

Opened as findings.test.md R11 (FAIL): the draft reports the mean-of-logs level
on one frame and says the category table is not a ranking. R9 promises that; this
is the evidence, and it is stronger than the overlapping intervals given now.

Untouched by all three checks: the within-family ordering and the nominal/real
gap, including flat translation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016G3pDU1a5BRbp2udySwGXt
A second author appended a composite pre-trend analysis to the notebook, edited
against the pre-section-7 version. GitHub's resolution dropped the deflated chart
and left the new cells calling geks_df, a name section 7 no longer defines.

Kept both sides. The real chart and the robustness cell are back; the new cells
are section 9, verbatim, under a heading saying what the design is and that
section 8 runs the same test with gig fixed effects and clustered SEs. geks_df is
aliased to nom_b in the section 7 build cell so their code needs no edit, and
their statsmodels cell is guarded, since statsmodels is not a project dependency
and this notebook has to run on a bare clone.

39 cells, 0 errors, 7 figures, statsmodels absent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016G3pDU1a5BRbp2udySwGXt
…ises

A user asked why marketing looked so high. It is high, +211% nominal and +172%
real at the broad level, and unlike coding it survives every check.

Marketing's listings are the shortest-lived on the panel -- median 9 quarters
between first and last capture against design's 33 -- so entry composition was
the obvious suspect. It is not: restricting to gigs spanning 8+ quarters moves
marketing 210.79 -> 210.69, and no other domain by more than 0.2 index points,
though 30 of 190 bilaterals change. That test is now a column in section 7's
check cell, because it generalises to any category a reader gets suspicious of.

The rest of the battery agrees. No single gig is worth more than 5% of the
Ads & PPC level under a leave-one-out; the bilaterals are well populated (median
61 matched gigs per quarter pair, minimum 10); and marketing reads +282% on the
published panel frame, higher than here, where coding's rank collapses from first
to fourth. So the two suspicious categories have different diagnoses and only
coding's is a measurement artefact.

What marketing has is width. Email & Funnels reads 373 at 2024Q2 against 321 and
318 either side, 95% band [284, 491]. The spike is inside the noise.

Also opened: section 6 asserts entrants price above incumbents, citing step 57.
Step 57's finding was about AI-labelled entrants. On this panel the general claim
inverts -- marketing entrants list at $15 against incumbents' $30 at 2023Q1 --
so the sentence needs restating or re-deriving.

Verified: 39 cells, 0 errors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016G3pDU1a5BRbp2udySwGXt
Second merge with the same author, from the same stale base, dropping the same
work: section 7's real chart, the check cell, the section 9 heading and the
geks_df alias. Kept her newest cells verbatim except for two fixes -- the
notebook as pushed carries both errors in its own committed outputs.

NameError: geks_df, in cells 32 and 34. Section 7 renamed that table when it went
to 35 categories. geks_df = nom_b is aliased in the section 7 build cell so her
code reads the broad nominal table under its old name and needs no edit.

KeyError: pre_fitted_index, in the section 8 plot. pre and post are copies taken
before the fitted columns are added to g, so those columns do not exist on them.
Now g.loc[pre.index, ...] and g.loc[post.index, ...], which is what the code
intends. Structural fix, not exercised here: statsmodels is absent on this
machine and the guarded cell skips.

39 cells, 0 errors, 7 figures.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016G3pDU1a5BRbp2udySwGXt
Both section 7 charts have been in the file since 4ba13c6, but every output was
stripped, so opening the notebook showed code and no images. That is the repo
convention and it is the wrong one for a notebook whose point is two charts you
are meant to compare.

Committed with outputs: 7 figures, 0 errors. Section 7 cell 24 is the nominal
chart, cell 25 is the same index deflated by CPI-U on the same y-axis. 1.4 MB.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016G3pDU1a5BRbp2udySwGXt
…unning it

§10 fits ln(real price) on the gig fixed effect (task value), quarter effects,
reputation and AI exposure, over 169,337 gig-quarter observations. It imports
code/76-price-model.py rather than restating it — build_panel, design, fe_ols,
qdummies, mde and load_slug_exposure — so the notebook and runs/price-model/model.md
are one fit. Every printed number reproduces the script's to the digit.

What it establishes: reputation, +7.33% real price per doubling of cumulative
reviews (t 26), an independent replication of steps 22/27 in 2020Q1 dollars; and
task value, SD 1.249 log points, seven times the spread of everything time-varying
put together, which is the argument for keeping it a fixed effect rather than a proxy.

What it does not: Exposure x Post is -0.0333 (t -1.35) against an MDE of 0.0689, so
the null rules nothing out — a silence, not a zero — and gate A fails anyway. The
new event-study chart is the clearest statement the project has of why: the exposure
gap opens across 2021, a year before ChatGPT exists, and is flat for the whole
post-period. §10.5 carries the false positive that was caught, +13.76% per 10pp
collapsing to +0.73% under one linear trend per category.

Two of §10's dependencies were untracked, so a clone could not run it: step 76
itself, and runs/ai-slug-diffusion/diffusion.md, which §10.5 reads as its regressor.
Both committed. Step 76 also gained a .csv.gz fallback for PRICES and path arguments
to build_panel, since the 88 MB CSV is gitignored and only the 7.9 MB gzip is in the
repo; its own output is byte-identical after the change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017CZzqPanjxFvPfB9TXK6se
§10 put task value in a gig fixed effect, which is the honest home for it and
also a dead end: a fixed effect that ABSORBS task value can never REPORT it.
`a_i` came back with an SD of 1.249 log points and no way to say what any part
of it was. Worse, a gig fixed effect also absorbs the permanent part of
reputation, so §10 could only ever watch one listing reprice itself and was
structurally blind to the comparison the reputation question is about.

Two new steps replace the gig anchor with a task anchor.

`77-task-taxonomy.py` builds a two-level taxonomy. Domains are step 04's;
subcategories are matched on the DELIVERABLE PHRASE stripped out of the title
(`<seller>: I will <X> for $N on fiverr.com`, 99.99% coverage and far richer
than the slug). Rules are ORDERED and first-match-wins, most specific first, so
`shopify dropshipping store` reaches `ecommerce` before `web_dev` sees `store`;
the order is part of the definition. 65 nodes, 77.5% of gigs named, nodes under
30 gigs folded into `<domain>/other`. Reference task value runs $6.66
(translation/subtitling) to $59.38 (marketing/content_strategy), a spread of
2.188 log points. Domain explains 5.7% of ln(real price), the node 10.9%, the
gig 91.4% — the taxonomy roughly doubles what seven domains name and is still
nowhere near the fixed effect.

`78-reputation-price.py` fits reputation at three levels. Between nodes +6.94%
per doubling; between gigs within a node -9.08% (t -28); within a gig +7.62%
(t 31). B and C have OPPOSITE SIGNS, both precisely estimated on 270,965
observations. Step 25 saw this at category level as "near zero versus positive";
holding the task fixed at node level turns the cross-section significantly
negative. A high review count marks two things at once — a seller who has been
around, which raises price, and one running a cheap high-volume operation, which
lowers it. Between sellers the second dominates; within one listing only the
first can move. Neither number may be quoted without the other.

Per-node slopes are positive in all 58 estimated nodes, 45 significant, +1.84%
(translation/localization) to +27.11% (translation/interpreting). Commodity
translation sits at the bottom, consultative work at the top.

Notebook §11 (15 cells, four charts) imports both steps rather than restating
them, the convention §10 uses for step 76; every printed number reproduces
`runs/taxonomy/*.md`. The chart that carries the argument plots one node twice —
one point per listing (slope -0.038), then each listing centred on its own mean
(+0.091). The reversal is visible without a regression.

Two corrections made while wiring it up. Step 77 was reporting reference values
on the full panel while step 78 fit on rows carrying both reputation columns, so
the project briefly held two different reference task values —
marketing/content_strategy was $67.11 in one and $59.38 in the other; step 77
now computes on the estimation sample and says so. And §11.3's scatter was
captioned as showing the reversal "before any regression", which is false:
`adjusted` comes from the fit containing b1, so the gap is approximately
b1 x (node mean log reviews - grand mean), measured correlation 0.978. The
caption now states this and credits the sign to spec B.

Open, both in todo: the taxonomy has no hand-labelled validation, and
`translation/voiceover_leak` (721 gigs) shows step 04's classifier leak sits
inside the nodes rather than repaired by them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TftqfBPLvNdb4GJYdSKXXe
The incoming commit replaced §7's chart colours with an explicit Okabe-Ito
`DOMAIN_COLORS` map for the seven domains. §11 had landed with its own
seven-colour palette, so a domain would have been one colour in §7 and another
in §11's three charts. §11 now aliases `DOMAIN_COLORS` instead of defining a
competing map, and its figures are re-executed against it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TftqfBPLvNdb4GJYdSKXXe
… approximates

"Price increases 7.7% when review counts double within one gig" was a coefficient
with no picture and two unasked questions behind it. §11.4a asks both.

IS IT A STRAIGHT LINE? The left panel is a Frisch-Waugh partial-residual plot: gig,
quarter and rating are swept out of the price AND out of the review count, so the
plotted line's slope is spec C by construction — the cell asserts the FWL slope
equals bC to 1e-9 — and the only thing free to move is the shape. Fourteen
equal-count bins, gig-clustered 95% CIs.

The answer is mostly, not exactly. A quadratic in ln(1+reviews) is -0.00277
(t -2.51), so strict log-linearity is REJECTED. The departure is small and
monotone: +8.14% per doubling at 10 reviews, +7.23% at 100, +6.29% at 1,000,
+5.63% at 5,000, against the pooled +7.62%. The median gig-quarter carries 111
reviews (p90 965), so the linear coefficient is a fair summary over the mass — but
it is now stated as an approximation rather than a functional form, and the
concavity is visible in the top bin without the parametric test.

WHAT DOES THE RATE BUY? +7.6% per doubling is a rate, not an outcome, and it pays
only if listings accumulate doublings. Most do not: the median listing travels 1.53
doublings over its whole observed life, p90 4.63, and 38% never manage even one. At
spec C's slope the median listing's entire review history is worth +11.9% in real
price. A secondary top axis converts doublings to implied gain directly.

The cells reuse §11.4's y / X / igig / bC rather than refitting, so the section
still holds one spec C. Outputs are executed and embedded, per the convention that
committed charts are visible without running the notebook.

Two reading hazards handled rather than left: the x-axis is doublings, not log
points, so the coefficient is legible off the chart; and the histogram's last bar is
a clipped 6+ tail (3.0% of listings), labelled so it is not misread as a mode.

Logged as U6 (the instruction) and R12 (the functional-form critique, now answered)
in tests/findings.test.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzPM6JZMKR7bpHE5XciSU7
…r's sitemaps taken

Two steps, tested against the live sites rather than the archive.

FIVERR GIG PAGES ARE HARD-BLOCKED, MEASURED NOT ASSUMED. 15 gig pages, 3s apart,
honest browser UA: 15/15 HTTP 403. Retried with complete standard browser headers:
still 403. The homepage 403s on the first request, so it is not a rate limit. The
body is a PerimeterX CAPTCHA wall. Passing it would need CAPTCHA-solving, proxy
rotation or fingerprint spoofing — circumvention of an access control, refused.
This closes todo PRIORITY 0b: its question (1), the paginated reviews endpoint,
cannot be tested at all because no HTML is served, so the archive back-fill is dead
by the plan's own abandonment criteria.

80-fiverr-sitemap-census.py RECOVERS WHAT WAS RECORDED AS IMPOSSIBLE. Step 39 found
n_404 = 0 across 509,339 Wayback captures — the archive stops re-requesting a
delisted URL rather than recording its death, so exit was unmeasurable. Fiverr
publishes its live inventory as sitemaps, listed in its own robots.txt and served
WITHOUT the PerimeterX wall. Eight requests give 291,068 live gig URLs and put
12,720 of the panel's 39,933 gigs (31.9%) still listed. Survival by year of last
panel observation runs 2.2% (2018) to 55.0% (2024). That is an exit hazard, and it
bears on §4.4's survivorship gap and on the objection that the index is computed on
survivors.

Two limits are in the docstring, not the commit only: absence means NOT LISTED, a
lower bound — a gig may be paused, unindexed or rotated out rather than dead; and no
sitemap carries a price, so this cannot extend the index.

79-mercor-board.py NEEDS NO CRAWLER. work.mercor.com/jobs server-renders every open
listing into __NEXT_DATA__, so one GET is the whole cross-section — nothing to
rate-limit. robots.txt allows /jobs/; /apply/, /api/ and /interview/ are untouched.
394 listings, 100% rate coverage, median hourly band $70-$100, plus capacity fields
the archived copies lack (remainingSlots, 11,418 open slots; suppliedSlots;
recentCandidatesCount; hoursPerWeek; postedAt).

Stated in the docstring before anyone reaches for it: Mercor listings are
employer-posted HOURLY RATE BANDS for contract roles, not seller-posted fixed prices
for deliverables. Not comparable to Fiverr gig prices, and not to be spliced into the
IPI. Today's file is a cross-section; the panel accrues only by re-running, where the
version field separates a genuine reprice from a re-crawl.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzPM6JZMKR7bpHE5XciSU7
…res on the table

The panel's right edge is starved -- design falls 7,093 -> 320 matched gigs per
adjacent quarter pair between 2024Q3->Q4 and 2025Q4->2026Q1. This separates the
collapse into two causes with very different remedies.

Irreducible: 38% of 2025+ fiverr.com captures are HTTP 403 and only 19% are 200.
The PerimeterX wall step 80 measured against live gig pages was already turning the
Wayback crawler away through 2025. A 403 capture has a digest and a length, so a
naive census counts it as supply; its body is a CAPTCHA page and carries no price,
so step 81 drops them rather than doubling 2025-2026 supply on paper for nothing.

Ours, and larger than expected: 34,807 gig-days for 2025+ were indexed in March and
never downloaded, against 8,363 that were, because the balanced and expanded
manifests quota over seven domains and drop `uncategorized`. Collecting them roughly
doubles matched-pair supply in every 2025-2026 quarter -- and still leaves ~1,200
matched gigs across all categories against a 1,200-per-category target.

Third pool: Wayback ingests late. Re-querying prefix `q` returns 252 gig-shaped 200s
in 2025+ against the 212 the March pull saw (+19%), with 36 of the new records in
2026Q2-Q3, which the old index does not cover at all.

- 01: the window is now an argument (--from/--to/--out/--prefixes). The refresh goes
  to raw-2025/, not raw/ -- raw/ is the provenance record for every number already in
  the draft, and step 81 unions the two at read time.
- 81: separates the three pools, emits a step-08 manifest (35,030 captures).
- run-refresh-2025-pipeline.sh: waits out the CDX pull, then 81 -> 08 -> 09. Prices
  land in a new file; the pilot paper is mid-submission and nothing here may move a
  published figure. Downloads never run while the pull is live -- both hit
  web.archive.org, and probing the CDX API during it already produced 429s.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KL94gcTBgrhyruuRtutA5Y
Serialising the two bought nothing. 35,030 of the ~35k manifest captures come
from the March 2026 all-time pull and do not depend on the refresh at all -- the
refresh only adds a further ~0.5-19% -- so waiting hours for it before fetching
anything cost time for no data. The download runs at --concurrency 6 --max-rate 6
instead of 10/10, which leaves headroom for the CDX pull; measured 300 captures/min
with 471/473 HTTP 200 and no 429s on either job.

Two correctness fixes the new ordering requires:

- 81 writes the manifest atomically (temp + rename). Step 08 loads its manifest
  once at startup, so a rename swaps safely under a live pass, and the next pass
  picks up the larger set. A plain open(..., "w") would let pass 1 read a
  half-written manifest.
- The driver waits for the in-flight download to exit before starting pass 2. Two
  step-08 processes appending to one checkpoint would interleave and corrupt the
  resume set.

Premise verified before committing to the fetch: three manifest captures parsed
end-to-end. 2025-01 and 2026-07 captures are real gig pages carrying packageList
prices with no px-captcha wall; one 2025-12 capture returned 200 with no price
block, so 35,030 is an upper bound on extraction yield rather than a forecast.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KL94gcTBgrhyruuRtutA5Y
…hausted anyway

The overnight pipeline landed 35,938 pages and 35,925 price rows at 100.0%
extraction. Step 82 replaces yesterday's projection with the realised number,
measured on collected prices rather than on index supply.

The projected level was right; the projected gain was not. All-category matched
pairs at 2025Q1->Q2 go 1,093 -> 1,285 against a projected 702 -> 1,286 -- the
after correct to one gig, the before understated by ~390 already on disk. So
1.12x, not the 1.83x the to-do carried. The seven published domains move
34,164 -> 34,433 (1.01x) and nothing in the draft moves.

The reason is the finding. 22,947 of 24,345 (94.3%) of the refresh's gigs are
priced in exactly one quarter and only 884 carry an adjacent pair; a bilateral
needs two visits, so a one-shot capture is worth nothing however cleanly it
extracts. Not collection loss either -- the manifest holds only 893 such gigs,
so 99.0% of the recoverable pairs were recovered.

Newly measured, and the sharper half: the archive's adjacent-quarter revisit
rate is flat at 74-82% across 2018-2024, then 44.1% (2025) and 34.5% (2026).
Supply is the product of gigs-captured and revisit-rate, so the right edge loses
twice over. The 403 wall was only the first column.

Decided: the recovered supply changes the error bars, not the index window.
Design's best 2025-2026 pair is 337 against a 1,200 target. Ten new families
become differenceable at all but none reach 30 in any pair -- existence, not
measurement.

Also commits steps 67-75 and their run notes, which the to-do already cites but
which had never been tracked. The 11 GB of refresh HTML and the 35,925-row panel
are gitignored; re-querying CDX is still worth it for 2026Q2-Q3, which the March
pull never covered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ArSV92b617GAi1AEY2kZ67
Closes the leftover "re-query CDX for 2026Q2-Q3" with a negative on two
archives, and builds the only route that remains.

Wayback stopped crawling Fiverr after 2026Q1. A fresh pull of prefix z over
20250101 -> 20260907 -- the first look past 2026-03 this project has had --
gives 459/212/393/207/173 captures for 2025Q1..2026Q1 and then 11 and 10 for
2026Q2-Q3, one of them a 200. 403s do not rise, so the captures simply stop.

Common Crawl, never previously tried, is closed too: fiverr.com/* returns one
index block in Aug 2026, Aug 2025 and Aug 2024 alike, and its only status-200
records are robots.txt. Recorded so neither archive is re-tried.

Wayback additionally began refusing connections from this host mid-run
(Connection refused, its only A record) while archive.org answered 200. The
26-prefix refresh was stopped rather than left retrying; checkpoints are intact
and it resumes with one command. It is still worth finishing for 2025, where 14
prefixes were never pulled, and not for 2026.

That leaves live gig pages, which steps 63/63b had already validated on stored
HTML: no price selection in late-fetched pages (+0 USD, CI [+0, +0]) and
displayed orders at median lag 2 months, so a page opened in 2026-09 is mostly a
window onto 2026Q2-Q3 -- at the cost of survivorship, since only 26.2% of the
panel is still listed and skewed rich.

  83  stratified target list: category x panel review-count quartile,
      round-robin under one seed, so ANY prefix of the list is balanced and an
      operator who stops early holds a sample rather than a head.
  84  paste-in browser collector: same-origin in the operator's own session,
      one request per 4-9s, keeps the two JSON blobs (~12 KB) rather than the
      1.3 MB page, and halts on three consecutive 403s. No CAPTCHA solving,
      proxy rotation or fingerprint spoofing -- refused 2026-09-04, still
      refused. Fiverr's robots.txt permits gig pages and advertises them.
  85  ingest: panel rows plus realised-order rows, and a report that always
      prints the three stacked selections -- survivorship, relevancy-ranked
      display, and price bucketing ("$50-$100" is not an amount).

Pilot-before-scale applied to the tooling itself: the chain was dry-run on 60
stored pages before anyone spent a browser session, which caught the reviews
slice matching an inner object (2 bytes for a gig with 368 reviews) and title
taking the package name instead of the gig's og:title.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01163NZVFu7VFmWtZjpUabdT
The operator saw a 429 on web.archive.org, which resolved an ambiguity this
host could not: IA is up and rate-limiting us after yesterday's ~11 GB pull.
The refresh is paused on its checkpoints, not dead.

That prompted a recount which overturns part of the earlier note. The claim
that "the captures simply stop" and "403s do not rise" came off prefix z alone
-- half of one small prefix, 1,465 records. Recounted on the 79,853 records
from the 12 prefixes pulled a day earlier:

  quarter   captures   403 share   200s   distinct gig pages
  2025Q4      12,601        1.0%   2,239                 940
  2026Q1       9,734       18.1%   1,180                 563
  2026Q2       1,204       89.3%       9                   1
  2026Q3       1,209       59.1%     152                  50

So the wall IS the mechanism, quarter by quarter, and 2026Q3 holds ~50 distinct
gig captures in a 14.5% partial pull -- order 350-500 archive-wide, worth
collecting, against the "essentially none" claimed before.

The conclusion survives its own arithmetic being wrong: 2026Q2 holds one
gig-shaped 200 against 2026Q3's 50, so adjacent-quarter matched pairs are ~0
either side and the archives are still no route to a 2026 index. The live-page
plan stands unchanged.

One new signal: 2026Q3 recovers (403 89.3% -> 59.1%, 200s 9 -> 152), the first
non-monotone quarter since the wall began, which makes a later re-query worth
more than this one.

Pacing in step 01 is now configurable (--min-interval, --concurrency) and the
global default slowed 0.75s -> 1.5s.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01163NZVFu7VFmWtZjpUabdT
…t hides them

The wall blocks new fetches. It does not touch the 86 GB already downloaded, and
step 59 had established that a gig page embeds review records dated by ORDER
date carrying what the buyer paid. Nothing after step 09 had read them at scale.

Step 86 scans all 397,698 stored captures, dedupes on encrypted_order_id keeping
the earliest capture that showed each order, and recovers 681,668 distinct
orders. 2025 -- the year the listed-price panel loses -- is thick: 10,236 /
7,360 / 7,233 / 6,602 orders per quarter over 2,250-4,479 gigs. 2026 is
independently confirmed dead, 23 orders across Q2-Q3, because these records come
from captures and the captures stopped.

The obvious analysis would have produced a spectacular false finding. Bucket
shares straight off the published field show sub-$50 orders going from ~0% of
the market in 2022-23 to ~54% in 2025 -- a collapse in what buyers pay, arriving
right on the AI timeline. It is an artefact twice over:

  * sub-$50 orders carried NO price bucket before ~2024Q2 -- in 2022Q3, 46% of
    orders are unpriced and the cheapest bucket that exists is $50-$100, while
    by 2024Q3 missingness is ~0 and $0-$50 alone is 50%. The apparent <$50 share
    tracks coverage almost exactly.
  * the labels changed at the same moment: $5-$20 and $20-$50 vanish, $0-$50
    appears, so bins on published labels straddle a break.

Step 87 conditions on $50+, where the boundaries 50/100/200/400/800 hold across
every era. There the series is flat: median bin $100-200 in all 17 quarters from
2022Q1 to 2026Q1, drifting $50-100 +4.8pp, $100-200 -3.6pp, $200-400 -2.5pp,
$400-800 -0.4pp, $800+ +1.6pp. A mild hollowing of the middle, not a decline.

The cost is stated rather than hidden: the series says nothing about the sub-$50
segment, which is roughly half of all orders and unmeasurable before 2024. And
it is not the IPI -- different price object, no chaining.

The 118 MB order panel is gitignored and regenerable; the distilled quarterly
series and both reports are tracked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01163NZVFu7VFmWtZjpUabdT
Rebuilds both HTML surfaces against the current sections and commits them:
`paper-page.html` (the self-contained reading build, 272 KB, no external
requests, 5 figures inlined, 18 tables) and the dated working draft.

Three defects in `36-build-paper-page.py`, two of them pre-existing and
visible on every build since August:

  - Inline math was capped at 70 characters, so the hedonic model in 3.8
    (~110 chars) never matched and rendered as raw LaTeX source on the
    page. Raised to 200; the guards in repl() -- reject spans containing
    markup or an escaped price, require a backslash/caret/underscore or a
    stat pattern -- are what keep "$50 ... $30" prose literal, not the
    length limit.
  - Display equations outside the hand-mapped DISPLAY set kept their `$$`
    fences in the fallback path, so both equations added to 3.8 rendered
    as "$$ln p...". Fences now stripped before tex_inline.
  - The page had no <title> at all, so it had no name in a browser tab or
    an artifact gallery. Now "Intelligence Price Index", emitted by the
    builder so it survives rebuilds.

Zero raw LaTeX left in the output.

NOTE ON WHAT IS NOT HERE. These HTML files are generated from
`drafts/sections/*.md`, and those edits -- the four weeks of results
folded into paper 1 on 2026-09-08 -- are still uncommitted, along with
the test files, progress.md, plans/todo.md and README.md. So this commit
carries the rendered paper ahead of its own markdown source. The next
commit closes that gap; until it lands, the HTML here is ahead of the
sections in the tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLKKz8r3BziyfpFdXQnJWo
…es against us

drafts/sections/ had not moved since 2026-08-13 while every result from
08-19 on lived only in runs/. With a submission two days out, this folds
that work into paper 1. 20,014 -> 24,555 words; 32-check-draft-numbers.py
passes and all 53 section cross-references resolve.

New in the paper:

  - 4.6 "What Buyers Actually Paid" -- the 681,668 realised orders
    (617,456 in window) recovered from HTML already on disk. Leads with
    the artefact, not the series: the naive read shows sub-$50 orders
    going ~0% -> 54% between 2023 and 2025, and that tracks field
    COVERAGE almost exactly. On bands stable across every era the median
    order sits in $100-200 in all 17 quarters. Full series at A.9.
  - 4.9 "The Observation Window Is Closing" -- 403 share 1.0% -> 89.3%
    across 2025Q4-2026Q2, revisit rate 74-82% -> 34.5%, the 1.01x
    re-collection, Common Crawl never having crawled the site. 6.6 carries
    the limitation half.
  - 4.8 gains the pre-registered exposure model at panel scale: -0.0333
    (t -1.35) on 169,337 gig-quarters, the six-gate table with three
    failures, and the ext2025 extension at -0.0324. Detail at A.8.
  - 4.3 closes findings R11 -- median-of-logs (+74%) beside mean-of-logs
    (+145%), frame dependence stated, and the 35 narrow cells added.
    Translation and subtitling are the only two of 35 whose real change
    covers zero; translation/other at +51.2% is the counter-evidence in
    the same family. Full table at A.10.
  - 3.8 / 4.4 re-base reputation on the balanced panel: +7.33% per
    doubling (beta +0.1021, t 25.95, 169,337 obs), replicating the pilot's
    +7.7% on fifty times the data. The index adjustment still uses the
    pilot beta, so no published figure changes basis.

THE CLAIM THAT CHANGED, AND IT CHANGED AGAINST US. Earlier drafts said the
binding constraint was sample size and collection design, not estimator
choice. Fifty times the pilot's data leaves the estimate below its MDE,
four further quarters move it by 0.0009, and the design LOSES two gates it
passed at pilot scale. 4.8, 6.1, 7 and correction-ledger entry 7 now all
state the failure is one of identification, that more data of the same
kind does not repair it, and that a control group is the binding
requirement. 1's "why publish" argument was rewritten around this rather
than left standing.

Deliberately excluded: the reputation sign reversal (steps 77/78). Its
taxonomy is unvalidated against a hand-labelled sample and
translation/voiceover_leak shows the step-04 classifier leak inside the
nodes. Recorded as findings U7 so the omission is auditable.

Also here: 76-price-model.py gains --prices/--tag so an exploratory run
cannot overwrite the pre-registered model.md (basecheck and ext2025 runs
included); 84-make-collector.py gains --limit/--compact; README gains the
two-paper structure, which it had never described.

Still blocking submission and untouched: related-work R16 (seven
unverified citations) and the 2.2 claim of a Wayback literature citing
three papers that never used a web archive. Both at the top of
plans/todo.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLKKz8r3BziyfpFdXQnJWo
00-explore.ipynb had nothing on the realised-order work. It now carries §12,
"What buyers actually paid", importing step 87 rather than restating it, as
every other section of this notebook does.

It runs from the tracked 1 KB realised-value-series.csv -- which carries
coverage as well as the bands -- so §12 executes on a clean clone. The 123 MB
step-86 order panel is probed with first_present() and reported when present,
never required. Cells are committed with their outputs, so the charts are
visible without running anything.

Two panels:

  - LEFT, the trap: apparent share of orders under $50 against the share of
    orders carrying ANY price band. They correlate at r = 0.995. This project
    did not previously have that number, and it is the sharpest form of the
    point -- the "collapse in realised value" is, to three decimal places,
    Fiverr beginning to label a segment it had left blank.
  - RIGHT, what survives: the $50+ composition, flat, median bin $100-200 in
    all 17 quarters, drift +4.8 / -3.6 / -2.5 / -0.4 / +1.6pp.

r = 0.995 also goes into the paper's 4.6, which previously argued coverage
only by listing three coverage/share pairs.

Also here, from an operator question -- "don't we look at 2018 to 2026?".
The abstract conflated the collection window with the index window: "37,782
snapshots ... covering seven categories over 2020Q1-2026Q1" reads as though
nothing was collected before 2020. Captures reach back to 2018, the estimation
panel opens 2019Q4, and the index is PUBLISHED from 2020Q1 because four
quarters of 2017-2018 hold no captures and 3.7 shows the 2018Q3-2020Q1 leg is
not identified -- its level moves by a third under a change of base quarter
alone. The abstract now separates all three spans and states the reason.
Checked across every section: this was the only occurrence. Recorded as
abstract.test.md U-window.

Notebook normalised to nbformat 4.5 cell ids (the four new cells lacked them).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLKKz8r3BziyfpFdXQnJWo
…this paper"

From an operator question -- "so how many total snapshots do I include?" --
which had no single answer in the draft and exposed a stale claim.

3.2 said the two enlarged collections (25,051 and 39,933 gigs) "contribute no
number to this paper". True on 2026-08-13. FALSE since the panel-scale results
landed: the 39,933-gig balanced collection is exactly what the reputation
elasticity (3.8, 4.4) and the pre-registered exposure model (4.8) are fitted
on, and both are in the abstract. Corrected, and the separation is now stated
as a choice with a reason: the index stays on the pilot corpus so the published
series is not re-based mid-paper onto a different sampling frame, which 3.7's
frame-dependence result shows would move it.

3.2 also gains a corpus table, because three different figures were reachable
from three different sections and nothing reconciled them:

  pilot        37,782 snapshots -> 33,936 after exclusion   the index
  balanced     292,447 obs / 39,933 gigs -> 169,337 gq      reputation, exposure
  captures     397,698 -> 681,668 realised orders           realised values

Stated as non-additive and overlapping, which they are.

Tracked as method.test.md R44 (blocking) and U-corpora.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLKKz8r3BziyfpFdXQnJWo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants