Skip to content

docs: replace the fabricated NC State affiliation with URI, and gate the class - #297

Merged
Gavin-Borges merged 6 commits into
mainfrom
docs/fix-fabricated-nc-state-affiliation
Aug 27, 2026
Merged

docs: replace the fabricated NC State affiliation with URI, and gate the class#297
Gavin-Borges merged 6 commits into
mainfrom
docs/fix-fabricated-nc-state-affiliation

Conversation

@Gavin-Borges

Copy link
Copy Markdown
Owner

README.md's academic acknowledgement, the last line of the file, asserted "bioinformatics coursework at NC State". SESTRAV has no connection of any kind to NC State.

The institution was fabricated, not mis-copied. The line it replaced named no institution at all:

-*Academic affiliations: BPS 542 / CMB 522 / CSC 522 / STA 522: Bioinformatics I | CMB 523: Bioinformatics II*
+*Developed by Gavin Borges. Academic acknowledgements: bioinformatics coursework at NC State (...)*

A documentation-hygiene pass titled "de-course-ify the docs layer" invented a proper noun that had never appeared in this repository. It reached main as ee780a5 (PR #147, 2026-07-23) and stood in the public README for roughly five weeks.

Evidence, from two independent instruments

Every affiliation record in the repo already said University of Rhode Island, and all of them predate the fabrication: CITATION.cff (all six author entries), MAINTAINERS.md, LICENSE, SECURITY.md, docs/zenodo_deposition.md, and README's own "Original SESTRAV 1.0 Foundation Team (University of Rhode Island)" heading seven lines above the false line.

Second instrument, per .claude/rules/git-instruments.md ("is there a second, independent instrument that should agree?") — using the unmapped form, since git shortlog silently applies .mailmap:

git log --no-use-mailmap --format='%ae' --all   ->  12 commits from @uri.edu, 0 from any NC State domain

Why no existing gate could see it

It carried no number and no retracted token, so the retracted-token sweep, the reconcile check and the citation gate were all blind by construction. Recorded as D35, and as instance #7 in .claude/rules/third-party-claims.md, which it extends twice over:

  1. It is a claim about SESTRAV's own affiliation, so a sweep for competitor names could never have found it.
  2. It is a fabricated proper noun, not a distortion of something real — the previous six all misrepresented a fact that existed.

It also repeats the class's most durable pattern for the third time (after #4 and #6): the false claim was authored by a correction pass. And the direction-of-error test holds — NC State is a larger, better-known institution, so the fabrication flattered the project.

The failure was one of detection, not knowledge: _local/notes/authorship_analysis_2026-08-21.md recorded the contradiction explicitly five days before the fix, but filed it as a question to ask rather than a live false claim, and _local/ is gitignored so no gate or reader could see it.

Closed by a gate, not by vigilance

scripts/check_affiliation_claims.py fails on any US-style institution name in a tracked file that is not on an explicit allowlist. Wired into CI (.github/workflows/affiliation_claims.yml) and pre-push Check 3 — which ran and passed live on this very push.

An allowlist, not a denylist: a denylist only catches fabrications someone already thought of. This class is gateable where a false number is not, because an institution is a proper noun from a closed set — the check is "has this name been reviewed once", which needs only a list, not "is this number right", which needs a source.

Retracted names are permitted per-file, not per-line: NC State is a record in the claims register and a failure in README.md. A line suppression would have blinded that row to any other name added to it.

Three defects fixed in the gate before shipping it

  1. A coverage overclaim. Its docstring said it fails on any unallowlisted institution. Probing it directly showed Universite de Geneve, Universitat Heidelberg, institut pasteur (lowercase) and Rutgers-Newark all pass silently. Scope is now stated honestly as US-style forms with the measured misses named — an unexercised gate that reads as broader than it is becomes a false all-clear (GOV-1).
  2. A rotting citation. It cited a4543bf, which is the authoring commit and is not an ancestor of main. Corrected to ee780a5, matching D35.
  3. A bootstrapping failure — the gate blocked its own commit. Its test suite was not exempt, so the first push attempt failed with 17 findings, every one a fixture. This was undiscoverable before the file was tracked, because untracked files are not scanned by default. Both the gate's source and its suite are now exempt, and the narrowness is pinned by a test: a different test file must still be scanned, so a later "simplify to a test_ prefix" cannot silently blind all of tests/. Mutation-verified — that exact over-broad rewrite fails the test.

Verification

  • Gate catches the exact original published string when reintroduced in a scratch copy; README.md still caught while the register is not — both directions checked.
  • Low false-fail risk confirmed on realistic prose: MIT License, Current State, finite State machine all correctly suppressed.
  • 12 tests pass; ruff check clean; no non-ASCII introduced.
  • Integrity harness restored to 151 PASS / 0 WARN / 2 FAIL / 7 SKIP. The transient third FAIL was this script being cited by a tracked register row while itself untracked; the remaining two are the standing C1/D20 and C2/D21 owner rulings, untouched here.

…the class

README.md's academic acknowledgement asserted "bioinformatics coursework at
NC State". SESTRAV has no connection of any kind to NC State. The institution
was fabricated rather than mis-copied: the line it replaced named no
institution at all, so a documentation-hygiene pass titled "de-course-ify the
docs layer" invented a proper noun that had never appeared in this repository.
It reached main as ee780a5 (PR #147, 2026-07-23) and stood in the public
README for roughly five weeks.

Every affiliation record in the repo already said University of Rhode Island
and all of them predate the fabrication: CITATION.cff (all six author
entries), MAINTAINERS.md, LICENSE, SECURITY.md, docs/zenodo_deposition.md,
and README's own foundation-team heading seven lines above the false line.
Second independent instrument, per .claude/rules/git-instruments.md: the
unmapped git log --no-use-mailmap --format='%ae' --all returns 12 commits
authored from @uri.edu and zero from any NC State domain.

Recorded as D35 in docs/claims_register.md. This is instance #7 of the class
in .claude/rules/third-party-claims.md and extends it twice over: it is a
claim about SESTRAV's OWN affiliation, so a sweep for competitor names could
never have found it, and it is a fabricated proper noun rather than a
distortion of something real. It also repeats the class's most durable
pattern for the third time - the false claim was authored BY a correction
pass.

Closed by a gate rather than by vigilance. scripts/check_affiliation_claims.py
fails on any US-style institution name in a tracked file that is not on an
explicit allowlist, wired into CI (.github/workflows/affiliation_claims.yml)
and pre-push Check 3. An allowlist, not a denylist: a denylist only catches
fabrications someone already thought of. Retracted names are permitted
per-FILE rather than per-line, so "NC State" is a record in the claims
register and a failure in README.md.

Three defects were fixed in the gate before shipping it.

1. Its docstring claimed it fails on any unallowlisted institution. Probing
   it directly showed "Universite de Geneve", "Universitat Heidelberg",
   "institut pasteur" (lowercase) and "Rutgers-Newark" all pass silently.
   The scope is now stated honestly as US-style forms, with the measured
   misses named, rather than reading as coverage it does not provide.
2. It cited a4543bf, which is the authoring commit and is NOT an ancestor of
   main. Corrected to ee780a5, matching the D35 row.
3. Its own test suite was not exempt, so the gate blocked the very commit
   introducing it - 17 findings, every one a fixture. Undiscoverable before
   the file was tracked, since untracked files are not scanned by default.
   The gate's source and its suite are now both exempt, and the narrowness
   is pinned by a test: a DIFFERENT test file must still be scanned, so a
   later "simplify to a test_ prefix" cannot silently blind all of tests/.

Verified: the gate catches the exact original string when reintroduced in a
scratch copy; README.md is still caught while the register is not; 12 tests
pass; ruff clean; the exemption's narrowness mutation-tested. Integrity
harness restored to 151 PASS / 0 WARN / 2 FAIL / 7 SKIP - the third FAIL was
this script being cited by a tracked register row while itself untracked; the
remaining two are the standing C1/D20 and C2/D21 owner rulings.

Signed-off-by: Gavin Borges <gavinmborges1104@gmail.com>
…c-state-affiliation

# Conflicts:
#	docs/claims_register.md
…e-cite D35

Two defects found by an independent audit of the affiliation branch, both in
the supporting evidence rather than in the correction itself.

1. The "12 commits authored from @uri.edu" figure overstated the
   corroboration threefold, and it was measured with the wrong instrument.
   `--all` counts pre-v1-archive and release/2.0-rc1, which mirror main's
   early history under different SHAs, so four distinct commits by a single
   collaborator were counted three times each. `git log --no-use-mailmap
   --format='%ae' origin/main` returns 4.

   Both the script docstring and the D35 row now state the INVARIANT instead
   of an absolute, per .claude/rules/git-instruments.md rule 7: every commit
   in this repository authored from an institutional address is from
   @uri.edu, and none is from any NC State domain, wherever it is measured.
   The conclusion is unaffected - zero NC State commits exist at any count -
   but the error direction is the flattering one, and it was made inside the
   row documenting a flattering-direction fabrication.

2. D35 and the gate's docstring broke a REQUIRED status check. Between them
   they added four line-number citations (MAINTAINERS.md:15, LICENSE:3,
   SECURITY.md:6, and the authorship-analysis note), taking the exempt
   ledgers' ratchet from 63 to 66 against a ceiling of 63, and two of them
   were UNPINNED with no baseline entry. All four are now prose or
   heading references - the MAINTAINERS.md maintainer table, the LICENSE
   copyright line, SECURITY.md's opening paragraph - which is what the gate
   asks for and what does not rot. The ratchet is back at exactly 63; no
   ceiling was raised.

Verified: line-citation gate and commit-ref gate both clean, affiliation gate
clean, 12 tests pass, integrity harness 151 PASS / 0 WARN / 2 FAIL / 7 SKIP.

Signed-off-by: Gavin Borges <gavinmborges1104@gmail.com>
@Gavin-Borges

Copy link
Copy Markdown
Owner Author

Post-review corrections (pushed as f5bad36)

An independent audit of this branch found two further defects, both in the supporting evidence rather than in the correction itself. The README fix and the gate are unchanged.

1. The @uri.edu corroboration was overstated threefold, using the wrong instrument

The original claim - in the commit message, the D35 row, and this PR's description - was "12 commits authored from @uri.edu". That number came from --all, which counts pre-v1-archive and release/2.0-rc1 mirroring main's early history under different SHAs:

$ git log --no-use-mailmap --format='%H|%ae|%ad|%s' --date=short --all | grep uri.edu
      3  2026-04-06 | Adding result samples
      3  2026-04-06 | Adding documentation, conda env configuration file
      3  2026-03-23 | Adding Initial snakemake pipeline & run sample
      3  2026-03-04 | Adding Initial Implementation & Results

Four distinct commits, by one collaborator, each counted three times. git log --no-use-mailmap --format='%ae' origin/main returns 4.

Both the script docstring and D35 now state the invariant rather than an absolute, per .claude/rules/git-instruments.md rule 7 ("prefer stating the invariant over any absolute"): every commit in this repository authored from an institutional address is from @uri.edu, and none is from any NC State domain - which is true wherever it is measured.

The conclusion is untouched (zero NC State commits exist at any count), but the error direction is the flattering one, and it was made inside the row documenting a flattering-direction fabrication. Worth naming rather than quietly fixing.

2. This branch broke a REQUIRED status check

D35 and the gate's docstring between them introduced four line-number citations (MAINTAINERS.md:15, LICENSE:3, SECURITY.md:6, and the authorship-analysis note). That pushed the exempt ledgers' ratchet from 63 to 66 against a ceiling of 63, and two were UNPINNED with no baseline entry:

ERROR scripts/check_affiliation_claims.py:37: UNPINNED - citation 'MAINTAINERS.md:15' has no baseline entry
ERROR scripts/check_affiliation_claims.py:37: UNPINNED - citation 'SECURITY.md:6' has no baseline entry
ERROR docs/line_citations.json: RATCHET - ... 66 line citation(s), above the recorded ceiling of 63

All four are now prose or heading references - the MAINTAINERS.md maintainer table, the LICENSE copyright line, SECURITY.md's opening paragraph. The ratchet is back at exactly 63 and no ceiling was raised, which is the correct resolution: --update would have widened a documented blind spot to accommodate citations that rot anyway.

There is a small irony worth recording: a row about a claim that no gate could see was itself blocked by two gates it did not anticipate - first the affiliation gate refusing its own test fixtures, now the line-citation ratchet.

Verification after the corrections

Line-citation gate clean (63/63, 0 missing, 0 out-of-range) · commit-ref gate clean (205 citations resolve) · affiliation gate clean · 12 tests pass · integrity harness 151 PASS / 0 WARN / 2 FAIL / 7 SKIP, the two FAILs being the standing C1/D20 and C2/D21 owner rulings.

…thmetic again

Two register-integrity defects found by an independent audit, both in the
table these affiliation rows live in.

1. D34 and D35 rendered as raw pipe-delimited text, not as table rows. A
   stray blank / --- / blank sequence sat between D11 and D34, which ends a
   markdown table, so every row after it fell out of the table entirely. On
   main that orphaned D34 alone; adding D35 would have orphaned it too.
   Removing the three separator lines rejoins them. The Section 1 table is
   now 35 contiguous rows, D27 through D35, with zero arity mismatches
   against its 9-column header - which also matches the heading's "(D1-D35)"
   range for the first time.

2. D34's disposition arithmetic was wrong a second time, and the first
   correction is what left it wrong. PR #294 moved "twenty-nine confirmed"
   to twenty-seven but left "seven cells were corrected" standing, when the
   row's own "-> corrected" enumeration lists EIGHT changed cells: PredIG x2
   (open-source/pip, pan-allele), PRIME x3 (open-source/pip,
   antigen-processing, pan-allele), NetMHCpan x1 (end-to-end), pVACtools x2
   (end-to-end qualifier, antigen-processing). The corrected split is
   8 + 26 + 1 unresolved + 1 excluded = 36.

   The row now records that it was corrected twice and names the check that
   catches this class - count the enumeration, which is one grep. A
   correction pass is itself a claim-making pass
   (.claude/rules/third-party-claims.md rule 2), and this is the third time
   in this repository that the fix for a false claim carried a fresh one.

Verified: table contiguity and per-row arity re-measured escape-aware (35
rows, 0 mismatches); line-citation gate 63/63 at ceiling; commit-ref gate
205 citations resolve; affiliation gate clean; integrity harness
151 PASS / 0 WARN / 2 FAIL / 7 SKIP.

Signed-off-by: Gavin Borges <gavinmborges1104@gmail.com>
Section 4's monitored-claim row read "12 viruses trained". Every other
surface says nine: README.md ("nine viral pathogens", and "9 viruses
(v5 active)" in its field-comparison table) and this file's own Section 2.
Twelve is a v4-era figure.

This column holds the claim to be MONITORED going forward, not a historical
record, so a stale figure aims the next re-verification at the wrong target.
It also puts the register three viruses out of step with the README while
that README's "Start here" table directs readers here as the scope
authority - a reader checking the evidence scope finds the two documents
disagreeing.

Corrected to the nine v5-active viruses, named explicitly so the next drift
is visible rather than a bare count, with the correction and its reasoning
recorded in the row.

Signed-off-by: Gavin Borges <gavinmborges1104@gmail.com>
@Gavin-Borges

Copy link
Copy Markdown
Owner Author

Register-integrity repairs folded in (6ee1c84, 97a8850)

Three further defects, all in docs/claims_register.md. They are here rather than in a follow-up PR because two of them affect how D35 itself renders, so shipping D35 without them would ship it broken.

1. D34 and D35 rendered as raw text, not table rows

A stray blank / --- / blank sequence sat between the last in-table row (D11) and D34. A thematic break ends a markdown table, so everything after it fell out and rendered as literal pipe-delimited text on the rendered page:

75 | | D11 | CLOSED | Corrected clean mean leave-one-virus-out ...
76 | (blank)
77 | ---            <- ends the table
78 | (blank)
79 | | D34 | PARTIAL | ...     <- renders as raw text

On main this orphaned D34 alone; adding D35 would have orphaned it too. Removing the three separator lines rejoins them. Section 1 is now 35 contiguous rows, D27 through D35, zero arity mismatches against its 9-column header - which also makes the heading's (D1-D35) range true for the first time.

Verified escape-aware, since these rows contain escaped pipes and a naive split('|') miscounts them.

2. D34's arithmetic was wrong a second time - and my own earlier fix is why

PR #294 corrected "twenty-nine confirmed" to twenty-seven but left "seven cells were corrected" standing. The row's own -> corrected enumeration lists eight changed cells:

Tool Corrected cells
PredIG open-source/pip, pan-allele
PRIME open-source/pip, antigen-processing, pan-allele
NetMHCpan end-to-end
pVACtools end-to-end qualifier, antigen-processing

8 corrected + 26 confirmed + 1 unresolved + 1 excluded = 36. The row now records that it was corrected twice and names the check that catches this class - count the enumeration, which is one grep -c.

Worth stating plainly: this is the third time in this repository that the fix for a false claim carried a fresh one (.claude/rules/third-party-claims.md rule 2), and the previous instance was mine, one PR ago.

3. Section 4 monitored a v4-era virus count

The row read "12 viruses trained". Every other surface says nine - README.md ("nine viral pathogens", and "9 viruses (v5 active)" in the field-comparison table) and this file's own Section 2.

That column holds the claim to be monitored going forward, so a stale figure aims the next re-verification at the wrong target - and it left the register three viruses out of step with the README while README's "Start here" table directs readers here as the scope authority. Corrected to the nine v5-active viruses, named explicitly so the next drift is visible rather than hiding in a bare count.

Verification

Section 1 contiguity and per-row arity re-measured escape-aware (35 rows, 0 mismatches) · line-citation gate 63/63 at ceiling, no raise · commit-ref gate 205 citations resolve · affiliation gate clean · 12 tests pass · integrity harness 151 PASS / 0 WARN / 2 FAIL / 7 SKIP · zero failing checks on this PR.

@Gavin-Borges
Gavin-Borges merged commit 6713604 into main Aug 27, 2026
21 checks passed
@Gavin-Borges
Gavin-Borges deleted the docs/fix-fabricated-nc-state-affiliation branch August 27, 2026 04:45
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.

1 participant