Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/feedthejoe / README.md |
| Date | Not specified in source |
| Repository | Janady13/feedthejoe |
| Revision | 0e608a2b515a959bf35d2783428766624400ca3c |
| Branch | main |
| Path or archive member | README.md |
| Original SHA-256 | 378a49976b1aeeb14367aec2b97a1c07a3dd447585a3236e3d3ef197e53d0a97 |
| Git blob SHA | efc3c0fbced74ff389c8fa9ee4d561ab31b5b33c |
| Reading-copy SHA-256 | 378a49976b1aeeb14367aec2b97a1c07a3dd447585a3236e3d3ef197e53d0a97 |
Recovered source transcript
Download complete source text ↓92 lines · 3.7 KB
# feedthejoe.com
The personal site of **Joseph W. Anady** — software engineer, retired U.S. Army
Sergeant First Class (1st Infantry Division, Iraq), founder of ThatDeveloperGuy,
a service-disabled veteran-owned firm.
It is also a working recommender. The list of work reorders itself against what
you actually read, and it shows you why.
## What is unusual about it
**The ranking is the lighting.** Every entry carries an illumination value
derived from its current rank, and the stylesheet spends it on colour, weight
and size at once. The model's opinion arrives as light rather than as a number.
Nothing is ever removed — an entry it has set aside is dimmer, not gone.
**It shows its working.** Every row exposes the four terms that produced its
score, including the penalty. Recommenders do not usually let you see this.
**Nothing leaves your machine.** No cookies, no account, no telemetry, no server
call. Session state lives in `sessionStorage` and is discarded when the tab
closes. There is no endpoint to send anything to.
**Semantics are precomputed.** Item embeddings are generated at build time with
Transformers.js and ship as a 25 KB int16 sidecar, so the browser needs no model
to use the feed.
## The algorithm
A faithful reduction of the published mechanics of TikTok's ranker to a corpus of
a few dozen items with no server:
| Signal | Weight | Web analogue |
|---|---|---|
| completion | 1.00 | dwell ÷ estimated read time |
| rewatch | 0.85 | returning to something already read |
| share | 0.70 | copying the link |
| expand | 0.55 | opening the full piece |
| save | 0.35 | explicit save |
| contact | 1.20 | reaching the contact surface |
| **skip** | **−0.60** | scrolling past faster than reading allows |
```
score(i) = w₁·Thompson(Beta(α,β) per topic) ← exploration, cold start
+ w₂·cos(interest, item) ← semantic match
+ w₃·freshness(i) − w₄·fatigue(i) ← recency, anti-repetition
```
Selection is Maximal Marginal Relevance, so a confident model still cannot
collapse the feed into a single topic — the characteristic failure of a
small-corpus recommender.
Completion is measured against estimated read time rather than in raw seconds,
so a long item cannot win by being long. Dwell does not accrue while the tab is
backgrounded. Skips carry real negative weight: a model that only learns from
positive signals drifts toward whatever it happened to show first.
## Architecture
```
src/core/ pure functions — no clock, no I/O, no DOM, no global random
src/ports/ contracts only; imports nothing
src/adapters/ the impure edge: fetch, storage, DOM observation
src/ui/ rendering; no business logic
src/app/ composition root — the only place wiring happens
```
The arrow never points from `core/` outward. That is enforced mechanically by
`dependency-cruiser` on every `npm run verify`, not by convention.
Because the ranker is pure and its randomness is injected, a given
`(corpus, state, config, nowMs, seed)` always produces the same order — which is
why the ordering itself can be a test fixture.
## Build and verify
```bash
npm run verify # lint, architecture, cycles, tests
node build/extract-corpus.mjs .source content/corpus.json
node build/embed-corpus.mjs content/corpus.json content/embeddings.bin
node build/build.mjs # -> dist/
```
The build content-hashes the asset tree, subsets the variable font to the glyphs
actually used (643 KB → 46 KB, both axes preserved), and pre-compresses every
text asset with zopfli for nginx `http_gzip_static`.
## Licence
MIT for the code. Prose and the body of work are © Joseph W. Anady.
Archivo is licensed under the SIL Open Font License.