Skip to content

detect: the Nickel probe matches RSR template boilerplate, silencing the zero-denominator refusal on 9 of 24 sampled repos #976

Description

@hyperpolymath

The finding

The detect job's Nickel probe matches RSR template boilerplate, so the
zero-denominator refusal — the pipeline's central anti-vacuity guard — does not
fire on 9 of 24 sampled repositories it was built for.

ci-pipeline.yml's detect step counts *.ncl into TOTAL. Every repo seeded
from the RSR template carries the same six-file k9 Nickel set, so TOTAL
is non-zero for a reason that has nothing to do with the repository's ecosystem.
The nickel job then runs, lints six template config files, and the pipeline
reports success while the repo's actual language is never examined.

The workflow's own comment states the standard this violates:

Folding them into TOTAL would lift it above zero and SILENCE the
zero-denominator refusal below while nothing whatsoever had been checked.
That is a vacuous gate, and a vacuous gate is worse than an honest blind
spot: the blind spot reports nothing, the vacuous gate reports success.

That reasoning is correct and is exactly what happens here — the boilerplate
does the lifting instead of the unsupported probes.

Evidence

Deterministic sample: every 5th live repo whose primary language is one the
pipeline detects but cannot check (Julia, Elixir, Idris, Zig, Ada, Agda,
Gleam, Lean, Isabelle, Ruby, PHP) — 24 repos of 134 such. Probes replicated
exactly from detect, run against real default-branch trees via
gh api repos/<r>/git/trees/<default>?recursive=1, not a local grep.

verdict repos
RUNS-ncl-only (denominator is Nickel alone) 14
RUNS-real 6
REFUSE-unsupported 3
REFUSE-none 1

Of the 14, 9 have zero repo-owned Nickel — every matched .ncl is template:

hyperpolymath/candy-crash                 template_ncl=6   own_ncl=0  unsupported_markers=2
hyperpolymath/Cliometrics.jl              template_ncl=12  own_ncl=0  unsupported_markers=3
hyperpolymath/fireflag                    template_ncl=6   own_ncl=0  unsupported_markers=1
hyperpolymath/julia-ecosystem             template_ncl=6   own_ncl=0  unsupported_markers=62
hyperpolymath/ochrance                    template_ncl=6   own_ncl=0  unsupported_markers=7
hyperpolymath/polyglot-formalisms-gleam   template_ncl=6   own_ncl=0  unsupported_markers=1
hyperpolymath/resource-record-fluctuator  template_ncl=7   own_ncl=0  unsupported_markers=1
hyperpolymath/SMTLib.jl                   template_ncl=6   own_ncl=0  unsupported_markers=2
hyperpolymath/volumod                     template_ncl=6   own_ncl=0  unsupported_markers=2

The worst case is hyperpolymath/julia-ecosystem: it would lint 6
template files, report success, and leave 62 Julia markers unexamined. The
refusal added in #970 never fires.

The boilerplate is identical across unrelated repos — same six basenames, only
the directory prefix differs:

julia-ecosystem          .machine_readable/self-validating/{template-hunt,template-kennel,template-yard}.k9.ncl + examples/{ci-config,project-metadata,setup-repo}.k9.ncl
SMTLib.jl                .machine_readable/self-validating/  ... identical six
polyglot-formalisms-gleam contractiles/k9/                   ... identical six

Across the sample: 134 .ncl files in 19 repos, of which only 13 (9.7%) are
repo-owned
; in 12 of the 19, every single .ncl is template.

Why this is not cosmetic

This is the failure mode #970 was written to prevent, reintroduced through a
different door. #970 correctly refused to fold unsupported markers into
TOTAL; but TOTAL was already being lifted by files that are equally not a
check of the repository. The guard is intact and simply never reached.

It also silently mis-scopes the planned rollout: these 9 repos would receive a
blocking caller and go green, when the honest outcome is a
detected-unsupported refusal and a ledger entry.

Cure options (owner's call — not implemented here)

  1. Exclude the template set from the probe (.machine_readable/,
    contractiles/, *.k9.ncl) — narrow, matches the existing
    manifests-not-extensions doctrine.
  2. Count only .ncl outside those paths toward TOTAL, still linting all of
    them if the job runs.
  3. Treat "denominator is template-only" as equivalent to zero.

Acceptance criteria

  • On hyperpolymath/julia-ecosystem, the pipeline REFUSES with the
    detected-unsupported message instead of running the nickel job.
  • Re-running the 24-repo sample census yields 0 repos in the
    own_ncl=0 && nonncl=0 && unsupported>0 class (currently 9).
  • Positive control — the cure must not zero out real Nickel repos:
    hyperpolymath/laminar (3 repo-owned .ncl of 4) still reports
    has_nickel=true and still runs the nickel job. Likewise
    hyperpolymath/zerotier-k8s-link (4 own of 11).
  • The step-summary denominator distinguishes template from repo-owned
    .ncl, so the number printed cannot be mistaken for a real one.

Scope note

Found while censusing candidates for the #967 adoption rollout. This blocks
seeding the adoption ledger by detection
, because the detector currently
reports "checkable" for repos where nothing meaningful is checked — the ledger
would record the wrong debt.

Refs #967, #970, #956.

🤖 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