Something went wrong. Try again.
Something went wrong. Try again.
9.4 kB · 129 lines
HTML
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130<style>.tg-stats{ --bg:#000000;--card:#0d0605;--rule:#2a1614;--grid:#1c0f0e;--axis:#3a201d; --brand:#ff0000;--accent:#ff2d16;--deemph:#7d6763; --ink:#ffc9c0;--muted:#b8908a;--dim:#8a6a66; --s1:#ffb3a5;--s2:#ff8066;--s3:#ff4d2e;--s4:#e0230a;--s5:#961407; color-scheme:dark;background:var(--bg);color:var(--ink); font-family:"Sometype Mono","Sometype Mono Fallback",ui-monospace,SFMono-Regular,Menlo,monospace; font-size:13.5px;line-height:1.6; padding:26px 22px;border:1px solid var(--rule);border-radius:3px;max-width:880px;margin:0 auto}.tg-stats *{box-sizing:border-box}.tg-stats h2{font-size:19px;margin:0 0 5px;color:var(--brand);font-weight:700;letter-spacing:-.01em}.tg-stats h3{font-size:14px;margin:0 0 3px;color:var(--brand);font-weight:700; text-transform:uppercase;letter-spacing:.07em}.tg-stats h4{font-size:12px;margin:0 0 2px;color:var(--ink);font-weight:700}.tg-stats p{margin:0;color:var(--ink)}.tg-sub{font-size:11.5px;color:var(--muted);line-height:1.55}.tg-sec{background:var(--card);border:1px solid var(--rule);border-radius:2px;padding:16px 16px 15px;margin:12px 0}.tg-hero{display:flex;flex-wrap:wrap;gap:12px 32px;align-items:flex-end;margin:2px 0}.tg-hero b{display:block;font-size:42px;line-height:1;font-weight:700;letter-spacing:-.04em;color:var(--brand)}.tg-hero span{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}.tg-kpi{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:1px; background:var(--rule);border:1px solid var(--rule);border-radius:2px;overflow:hidden;margin-top:14px}.tg-kpi div{background:var(--card);padding:10px 12px}.tg-kpi b{display:block;font-size:18px;font-weight:700;color:var(--ink);letter-spacing:-.02em}.tg-kpi span{font-size:10.5px;color:var(--dim);text-transform:uppercase;letter-spacing:.05em;line-height:1.4;display:block;margin-top:2px}.tg-svg{width:100%;height:auto;display:block;margin-top:12px;overflow:visible}.tg-b-me{fill:var(--accent)}.tg-b-other{fill:var(--deemph)}.tg-row:hover .tg-b-me,.tg-row:hover .tg-b-other{opacity:.75}.tg-blbl{font-size:11px;fill:var(--muted)}.tg-blbl.tg-me{fill:var(--brand);font-weight:700}.tg-bval{font-size:11px;fill:var(--ink);dominant-baseline:middle}.tg-xt{font-size:10px;fill:var(--dim)}.tg-axis{stroke:var(--axis);stroke-width:1}.tg-grid{stroke:var(--grid);stroke-width:1}.tg-vlbl{font-size:10.5px;fill:var(--ink);font-weight:700}.tg-pies{display:grid;grid-template-columns:repeat(auto-fit,minmax(330px,1fr));gap:12px}.tg-pcard{margin:0;background:var(--card);border:1px solid var(--rule);border-radius:2px;padding:14px}.tg-pcard figcaption p{font-size:10.5px;color:var(--dim)}.tg-pbody{display:flex;gap:14px;align-items:center;margin-top:10px;flex-wrap:wrap}.tg-pie{width:150px;height:150px;flex:0 0 auto}.tg-sl{stroke:var(--card);stroke-width:2}.tg-sl:hover{opacity:.85}.tg-s1{fill:var(--s1)}.tg-s2{fill:var(--s2)}.tg-s3{fill:var(--s3)}.tg-s4{fill:var(--s4)}.tg-s5{fill:var(--s5)}.tg-pct{font-size:14px;font-weight:700;text-anchor:middle;dominant-baseline:middle;pointer-events:none;fill:#1a0806}.tg-pct.tg-p4,.tg-pct.tg-p5{fill:#fff2ef}.tg-legend{list-style:none;margin:0;padding:0;flex:1 1 152px;min-width:152px}.tg-legend li{display:flex;align-items:center;gap:7px;padding:3px 0;font-size:11px;border-bottom:1px solid var(--grid)}.tg-legend li:last-child{border-bottom:0}.tg-sw{width:9px;height:9px;border-radius:1px;flex:0 0 auto}.tg-sw.tg-s1{background:var(--s1)}.tg-sw.tg-s2{background:var(--s2)}.tg-sw.tg-s3{background:var(--s3)}.tg-sw.tg-s4{background:var(--s4)}.tg-sw.tg-s5{background:var(--s5)}.tg-lh{flex:1 1 auto;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tg-lh.tg-me{color:var(--brand);font-weight:700}.tg-lv{color:var(--ink);font-weight:700}.tg-lp{color:var(--dim);font-weight:400;margin-left:6px;font-size:10px}.tg-tbl{width:100%;border-collapse:collapse;font-size:11.5px;margin-top:10px}.tg-tbl th{text-align:left;font-weight:700;color:var(--dim);font-size:10px;text-transform:uppercase; letter-spacing:.06em;padding:5px 8px;border-bottom:1px solid var(--axis)}.tg-tbl td{padding:5px 8px;border-bottom:1px solid var(--grid);color:var(--muted)}.tg-num{text-align:right}.tg-me-row td{color:var(--brand);font-weight:700}.tg-stats details{margin-top:11px}.tg-stats summary{cursor:pointer;font-size:11px;color:var(--dim);padding:3px 0; text-transform:uppercase;letter-spacing:.05em}.tg-stats summary:hover{color:var(--brand)}.tg-stats summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.tg-key{display:flex;gap:16px;font-size:10.5px;color:var(--dim);margin-top:10px;flex-wrap:wrap; text-transform:uppercase;letter-spacing:.05em}.tg-key span{display:flex;align-items:center;gap:6px}.tg-key i{width:10px;height:10px;border-radius:1px;display:inline-block}.tg-note{font-size:10.5px;color:var(--dim);line-height:1.7}.tg-note strong{color:var(--muted)}.tg-note code{font-size:10px;background:#180b0a;color:var(--muted);padding:1px 4px;border-radius:2px}.tg-stats.tg-solo{padding:0;border:none;background:none;max-width:none}.tg-stats.tg-solo>.tg-sec{margin:0}.tg-pies.tg-one{grid-template-columns:minmax(0,440px)}</style><section class="tg-stats tg-solo"><div class="tg-sec"> <h3>Method</h3> <p class="tg-note"> Counted from the source records, not from Tangled's index — <code>api.tangled.org</code> was down throughout (every <code>/xrpc/</code> path returning <em>Failed to start container</em>), so these figures were rebuilt from the underlying atproto data. Tangled is not one server: repositories live on knots that anyone can host. Starting from the main knot's repo list, each account's own <code>sh.tangled.repo</code> records were read from its PDS — those records name both the owner and the knot — every knot so discovered was listed in turn, and the cycle repeated until no new accounts appeared. It closed at <strong>182 knots, 14,528 repositories and 17,939 accounts</strong>. Every account's <code>sh.tangled.repo.pull</code> and <code>sh.tangled.repo.pull.status</code> records were then read directly from its PDS; a pull's state is the status of the newest status record pointing at it, the same derivation the appview performs. Commits come from the patch attached to each merged PR — a gzipped <code>git format-patch</code> blob on newer records, an inline string on older ones. Commits pushed straight to a branch without a PR are not counted. Figures as of 4 September 2026. </p> <p class="tg-note" style="margin-top:9px"> <strong>Why not query the pulls directly.</strong> A first attempt asked constellation which pull records pointed at each repo. That undercounts: the record has changed shape three times — an inline <code>patch</code> string, then <code>rounds</code> with a patch blob, now <code>versions</code> with base and head SHAs — and 1,034 records carry no target field at all, so a backlink index cannot see them. Reading each person's repository finds every record whatever its shape. Verified against Tangled's own web interface on 37 sampled pull requests across every generation and all three states, on knot1 and on self-hosted knots alike: 42 agreed, 0 disagreed. </p> <p class="tg-note" style="margin-top:9px"> <strong>How complete is it.</strong> People were found three ways: repository ownership, backlinks in <a href="https://constellation.microcosm.blue">constellation</a>, and Tangled's own social records — follows, knot and spindle memberships, collaborator entries — read from each person's repository, which is the only channel with no index in front of it. 17,939 accounts were read in all. Checked against Tangled's own web interface: <strong>42 of 42</strong> sampled pull requests had the state derived here, and <strong>71 of 73</strong> were present in the data at all — 97% recall. Adding the social channel found 164 authors the first two channels missed, which moved the totals by about 4%. </p> <p class="tg-note" style="margin-top:9px"> <strong>What it still cannot see.</strong> These figures are read from the source records, so a pull request whose author has since deactivated is unreachable even though Tangled still displays it — about 9% of accounts with no records return an error rather than an empty list. 2,172 repository DIDs could not be attributed to an owner, mostly repos whose records were deleted. Only 10 of the 182 knots answer a repo listing at all; the rest run older software, so the repository count is a floor. And the residual gap sits with small contributors, not large ones: every one of the top ten authors was re-counted against their live PDS and matched exactly, give or take pull requests opened while the crawl was running. </p> <p class="tg-note" style="margin-top:9px"> <strong>Not shown: time to merge.</strong> A pull record carries <code>createdAt</code> and its status record carries another — but they are asserted by different people's clients on different machines, and 19.4% of other authors' merged PRs claim to have merged <em>before</em> they were opened. Month bucketing survives this (0.5% of merged PRs land in a different month under either field, and the August ranking is unchanged); a duration does not. </p></div></section>