Skip to content

ci-pipeline detect is blind to 56 code-bearing repos (and probes Deno, not Bun) #967

Description

@hyperpolymath

Census finding — ci-pipeline.yml's detect is blind to 56 code-bearing repos

Measured 2026-09-22. Supersedes the earlier 47/59 extension-keyed split in this file.

Headline

Of the 106 repositories where ci-pipeline.yml's detect job finds a zero
denominator, only 43 are genuinely docs/config only. 56 non-fork repos carry a
build manifest for a language detect cannot see.
Seeding the adoption ratchet at 106
would record those 56 as owing pipeline work they do not owe — 53% of the seeded
"debt" would be detector coverage, not repo debt.

What detect knows

From .github/workflows/ci-pipeline.yml:124-132 at 9c256b67, six probes:

ecosystem probe
Rust Cargo.toml
Nickel *.ncl
ReScript rescript.json, bsconfig.json, *.res
V v.mod alone (the .v extension collides with Coq and Verilog)
Haskell *.cabal, stack.yaml, *.hs
Deno deno.json, deno.jsonc

There is no Bun probe. detect knows the banned JS runtime and not the
sanctioned one, against the owner's standing ruling that the estate is "all bun and
bunx now". Twelve of the undetected repos carry package.json.

Method, and why two measures

Keyed on a manifest, not an extension — the same discipline detect already applies
to V (v.mod alone, never *.v). One git/trees?recursive=1 call per repo; every path
list is saved under tmp/trees/ so later questions cost no API calls.

Run as a cross-check against the earlier extension-keyed pass. Neither is trusted
alone
, because each fails in a different direction: an extension pass counts a curated
list's one stray .rb; a manifest pass counts a scaffolded repo with no source yet.

n=106   rows=107   ERR=0   truncated trees=0
manifest-keyed code-bearing:    59
extension-keyed code-bearing:   62
both agree:                     58     <- the defensible core
manifest only:                   1     hyperpolymath/git-seo (Project.toml, no .jl)
extension only:                  4     ddraig-ssg idr:4 (no .ipkg); homebrew-tap rb:1
                                       (a Homebrew formula); large-language-michelangelo
                                       py:1; reflexive-ai-studio ts:1
forks inside the 58:             2     awesome-gleam (a fork; its gleam.toml is the
                                       upstream list's own tooling), explore (a fork;
                                       Gemfile for Jekyll, 2133 blobs)
FINAL non-fork core:            56

Forks and archived repos were checked because neither should receive a caller workflow:
6 forks estate-wide (3 in the zero set: awesome-zig, awesome-gleam, explore) and
3 archived estate-wide, 0 in the zero set. All 456 census repos appear in the org
listings, so the archived probe has full coverage. The correction is small — it does not
rescue the headline, and saying so is the point.

Per-language mix of the core 58

manifest repos
Julia (Project.toml) 29
Bun/JS (package.json, bunfig.toml, bun.lockb) 12
Zig (build.zig) 10
Idris2 (*.ipkg) 10
Lean (lakefile.*, lean-toolchain) 4
Elixir (mix.exs) 4
Agda (*.agda-lib) 2
Ada (alire.toml, *.gpr) 2
Ruby / PHP / Isabelle / Gleam 1 each

The finding rests on a contradiction inside standards, not on my judgement

.githooks/validate-spdx.sh:37-38 — the estate's own authority on "is this a source
file" — already classes these as source:

*.rs|*.res|*.js|*.ts|*.sh|*.bash|*.zig|*.ex|*.exs|*.gleam|
*.ml|*.mli|*.adb|*.ads|*.ncl|*.toml|*.yaml|*.yml|*.scm

zig, ex, exs, gleam, ml, mli, adb, ads are every one of them invisible
to detect
. So standards simultaneously demands an SPDX header from these files as
source code, and declares the repos containing them to have no ecosystem.

Two arms

Arm A — extend detect first, then seed at ~43. Add manifest probes for Julia, Zig,
Idris2, Elixir, Lean, Agda, Ada, Gleam and Bun. The ledger then records real debt
only. This is the elegant long-term arm: it makes the ratchet's denominator mean what it
says, and it closes the Bun/Deno inversion at the same time.

Arm B — seed at 106 today, pay down by extending detect later. Faster to land, but
the ledger's first entry is 53% wrong, and a shrink-only ledger makes that number the
baseline everything is measured against.

Caveats, stated because they bound the claim

  • Default branches only. A repo whose work lives on a feature branch reads as
    docs-only here.
  • A manifest is evidence of intent, not of a working build. git-seo has a
    Project.toml and no .jl at all.
  • The 43 "docs-only" is a floor, not a proof of emptiness — it means no manifest and
    no source extension in the list above, on the default branch, today.

Acceptance criteria

  • detect gains manifest probes for Julia, Zig, Idris2, Elixir, Lean, Agda, Ada and
    Gleam, each keyed on a manifest (never a bare extension — .v already
    demonstrates why).
  • detect gains a Bun probe (package.json + bunfig.toml/bun.lockb). Today
    it probes Deno, which is banned, and not Bun, which is mandated.
  • Re-running the census reduces zero-denominator repos from 106 to ≤ 50, and
    the per-ecosystem denominator is printed as detect already does for the six it
    knows.
  • The adoption ledger is seeded from the post-extension census, so no repo appears
    in it purely because detect could not see its language.
  • A control repo per newly-probed ecosystem is asserted green (positive control) and
    a docs-only repo still fails detect (negative control) — a probe that matches
    everything is not a probe.

Reproduce

# per-repo path lists (1 API call per repo, cached under tmp/trees/)
gh api "repos/$REPO/git/trees/$BRANCH?recursive=1" \
  | jq -r '(if .truncated then "#TRUNCATED" else "#COMPLETE" end), (.tree[]|select(.type=="blob")|.path)'

# what detect knows, at the base commit
git show 9c256b67:.github/workflows/ci-pipeline.yml | sed -n '124,132p'

# the contradiction
sed -n '35,41p' .githooks/validate-spdx.sh

# forks / archived
awk -F'\t' 'NR>1 && $3=="true"' census.tsv | wc -l          # 6 estate-wide
gh repo list hyperpolymath --limit 600 --json nameWithOwner,isArchived

Cross-refs: #787 (decision surface), #948 (the adoption ratchet this seeds), #956
(blocking requires a required_status_checks ruleset rule, not merely a caller).


🤖 Generated with Claude Code

https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions