Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
81b2f3f
Add soulcap-cl-pro: document CL→PR marker relationships from Ubergraph
dosumis Jun 29, 2026
d6c8880
cl_pro: drop unasserted PR-hierarchy generalisations from the report
dosumis Jun 29, 2026
46bcec7
cl_pro: drop root protein, True/False booleans, scope-aware CD detection
dosumis Jun 29, 2026
f1ca943
cl_pro: prune property-hierarchy redundancy (keep most specific relat…
dosumis Jun 29, 2026
4d48a0a
feat: add soulcap-lookup, soulcap-tokens, type checking, and CI impro…
s28ale-maker Jul 4, 2026
d4f6dd1
feat: add soulcap-match CLI for scoring CL candidates against marker …
s28ale-maker Jul 6, 2026
400e7c2
feat: add soulcap-hgnc — HGNC gene symbol mapping for CL PR markers
s28ale-maker Jul 6, 2026
eaebb85
docs: track CL term corrections in reports and ROADMAP
s28ale-maker Jul 14, 2026
398667d
feat: Milestone 1 — marker_protein_gene.csv mapping table
s28ale-maker Jul 15, 2026
da183b1
feat: Milestone 2 — NK cell marker literature report
s28ale-maker Jul 15, 2026
422d7aa
feat: Milestone 2 — ILC, DC, iNKT, and T cell marker literature reports
s28ale-maker Jul 16, 2026
fcd3951
feat: Milestone 2 — B cell and gdT+MAIT marker literature reports
s28ale-maker Jul 19, 2026
eb28a0f
docs: record upstream CL issues filed for #13 NKT cell naming
s28ale-maker Jul 19, 2026
58bedd0
docs: record upstream CL issue filed for #12 monocyte corrections
s28ale-maker Jul 19, 2026
cb6993f
fix: strip UniProt isoform suffixes before Monarch lookup in soulcap-…
s28ale-maker Jul 21, 2026
7862cc8
Add batch/lexical CL matching, OR-group scoring, and Milestone 4 cand…
s28ale-maker Jul 22, 2026
93bf6d0
Add OAK matching, SSSOM export, gap tracking, and ROBOT ontology QC CI
s28ale-maker Jul 24, 2026
7520c5b
Add Monocyte family, Neutrophil, Eosinophil, and B cell candidate map…
s28ale-maker Jul 24, 2026
27f933a
Add T cell tree candidate mappings (core lineage, CD56+ family, memor…
s28ale-maker Jul 24, 2026
c4e56ef
Fix CI: pin setuptools<81 (pkg_resources removal breaks eutils on Pyt…
s28ale-maker Jul 29, 2026
5a4040b
Fix remaining ROBOT QC failures found from the real CI run
s28ale-maker Jul 29, 2026
6005bbc
fix: remove CI job that merges candidate mappings into CL and reasons…
s28ale-maker Jul 29, 2026
03cfdd4
feat: scope CL PRO markers needing species-specificity literature sup…
s28ale-maker Jul 30, 2026
bde6ecb
feat: add keyless Europe PMC fallback and compile PRO marker species-…
s28ale-maker Aug 4, 2026
4b0c9cf
docs: add pro-marker-species-support skill (issue #11, Step 7)
s28ale-maker Aug 4, 2026
f1e0772
feat: registry-backed mapping engine, audit dashboard, and matcher ev…
s28ale-maker Sep 11, 2026
4dfc726
feat: fingerprinted marker-resolution policies, regression triage, an…
s28ale-maker Sep 18, 2026
8a1094e
docs: add Fall 2026 sprint-level backlog
s28ale-maker Sep 18, 2026
c6343c1
fix: don't hard-fail benchmark reserve test on missing gitignored dat…
s28ale-maker Sep 18, 2026
aa4743b
chore: refresh marker_validation.md from latest sheet sync
s28ale-maker Sep 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .claude/hooks/validate_report_quotes.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ def main() -> int:
try:
from soulcap_cl_mapping import report_validator
except Exception as exc: # pragma: no cover - defensive
print(f"validate_report_quotes: import failed ({exc}); allowing", file=sys.stderr)
print(
f"validate_report_quotes: import failed ({exc}); allowing", file=sys.stderr
)
return 0

run_id = path.parent.name
Expand All @@ -104,7 +106,10 @@ def main() -> int:

evidence = snippet_cache.load_snippet_texts(run_id, qid, None)
except Exception as exc: # pragma: no cover - defensive
print(f"validate_report_quotes: cache read failed ({exc}); allowing", file=sys.stderr)
print(
f"validate_report_quotes: cache read failed ({exc}); allowing",
file=sys.stderr,
)
return 0

if not evidence:
Expand Down
115 changes: 115 additions & 0 deletions .claude/skills/gap-issue-filing/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
name: gap-issue-filing
description: Turn unfiled rows in reports/gaps.tsv into GitHub issues using the mapping_gap template, without duplicating existing issues, then update the row's status/repo_issue columns. Invoke when asked to file logged mapping gaps as issues, clear the gaps.tsv backlog, or check which gaps still need one.
---

You take rows already logged in `reports/gaps.tsv` — cases where matching a
SOULCAP cell type to CL broke down — and turn the ones that aren't tracked on
GitHub yet into real issues, using the existing `mapping_gap` template so they
stay consistent with issues #12–#14. See [CLAUDE.md](../../../CLAUDE.md) for
repo conventions and [ROADMAP.md](../../../ROADMAP.md) for how gaps relate to
the CL term corrections table.

`gaps.tsv` is the durable record; GitHub issues are the actionable, triageable
copy. This skill keeps the two in sync — it never replaces `gaps.tsv` as the
source of truth.

## When to invoke

The user asks to file gaps as issues, clear the `gaps.tsv` backlog, or check
how many logged gaps still lack a tracking issue.

## Tools

- `reports/gaps.tsv` — the source rows. Columns: `soulcap_abbreviation`,
`soulcap_full_name`, `gap_type`, `description`, `related_cl_ids`,
`evidence`, `status` (`open` / `filed_as_issue`), `repo_issue`,
`date_logged`.
- `.github/ISSUE_TEMPLATE/mapping_gap.yml` — the template whose fields map
directly onto `gaps.tsv` columns: `soulcap_abbreviation` → title, `gap_type`
→ the dropdown, `description` + `related_cl_ids` + `evidence` → the
matching body fields.
- `gh issue list` / `gh issue create` — via Bash. This repo is
`Cellular-Semantics/SOULCAP_CL_Mapping` (confirm with `gh repo view` if the
remote is ever ambiguous).
- `Edit` — to update `gaps.tsv`'s `status`/`repo_issue` columns once an issue
is filed.

## Step 1 — find what's actually unfiled

Read `reports/gaps.tsv` and list every row where `status` is `open` (not
`filed_as_issue`). Note two rows sharing a `soulcap_abbreviation` group (e.g.
`NK1 / NK3`) file as **one** issue, matching how the row itself is structured
— don't split a single row into multiple issues.

## Step 2 — check for an existing issue first

Before filing, search for a plausible duplicate:

```bash
gh issue list --search "<soulcap_abbreviation> in:title" --state all
gh issue list --label gap --state all
```

Some gaps already have a related, non-`gap`-labelled issue (e.g. the
monocyte/B-cell axiom-gap rows reference issue #12 in their `description` even
though #12 itself is filed under a different title). Read the row's
`description` and `evidence` columns for an existing issue number before
assuming none exists — filing a duplicate is worse than leaving a row open one
more day.

## Step 3 — confirm the batch with the user before filing

List the rows you intend to file (abbreviation + one-line description) and get
explicit confirmation before running `gh issue create` — this creates public,
visible state (issues, notifications to watchers) that's easy to create but
tedious to clean up if wrong. Do not file silently in a loop.

## Step 4 — file each issue

For each confirmed row, create the issue from the template's own field
structure — reproduce it as a plain markdown body (the `gh issue create
--template` flag targets local `.github/` templates inconsistently across `gh`
versions; writing the body directly from the YAML fields is more reliable):

```bash
gh issue create \
--title "[gap] <soulcap_abbreviation>: <short description, ~8 words>" \
--label gap \
--body "$(cat <<'EOF'
**SOULCAP abbreviation:** <soulcap_abbreviation> (<soulcap_full_name>)

**Gap type:** <gap_type>

**Description:**
<description column, verbatim>

**Related CL ID(s):** <related_cl_ids, or "none">

**Evidence:**
<evidence column, verbatim — turn `;`-separated paths into a bullet list>
EOF
)"
```

## Step 5 — write the result back to gaps.tsv

For each filed issue, edit its `gaps.tsv` row:

- `status`: `open` → `filed_as_issue`
- `repo_issue`: `(not yet filed)` → the issue URL `gh issue create` printed

Do this immediately after each successful `gh issue create` — don't batch it
to the end, so a failure partway through the batch doesn't leave filed issues
unrecorded.

## Known limitations

- This only closes the loop one direction (gap → issue). It does not detect
when a filed issue has since been closed/resolved upstream — that's
`roadmap-status-sync`'s job for the CL term corrections table, and isn't yet
extended to `gaps.tsv` rows with `status=filed_as_issue`.
- A `sheet_data_issue` row (a typo/malformed string in the master Google
Sheet) still can't be *fixed* here — filing the issue documents it, but the
actual correction still has to happen in the Sheet per
[CLAUDE.md](../../../CLAUDE.md)'s data-flow rules.
138 changes: 138 additions & 0 deletions .claude/skills/mapping-audit/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
---
name: mapping-audit
description: Cross-check curated SOULCAP→CL mappings against current CL marker axioms and literature evidence to catch drift, unsupported confidence, or mistyped broad/exact matches — the Milestone 3 deliverable, run today as a drift/evidence audit even though the Sheet hasn't yet gained the broad/exact + comment columns the milestone originally specified. Invoke when asked to audit curated CL mappings, check Milestone 3 progress, or re-verify candidate_cl_mappings.sssom.tsv after a CL or SOULCAP sheet update.
---

You re-verify mappings that were already curated in
[reports/candidate_cl_mappings.md](../../../reports/candidate_cl_mappings.md)
and exported to
[reports/candidate_cl_mappings.sssom.tsv](../../../reports/candidate_cl_mappings.sssom.tsv),
checking whether the evidence that justified each one still holds. See
[ROADMAP.md](../../../ROADMAP.md) Milestone 3, which this implements in
reduced form: the milestone was scoped assuming the Google Sheet would gain
dedicated broad/exact-match and comment columns first, blocking it entirely.
Those columns would sharpen *curator intent* capture, but the audit itself —
"does the evidence for this mapping still check out?" — doesn't strictly need
them. Say explicitly, in whatever you produce, that this is the
evidence/drift half of M3, not the full milestone as originally scoped.

## When to invoke

The user asks to audit curated CL mappings, wants a Milestone 3 progress
check, or just re-ran `soulcap-cl-pro` (CL's marker axioms can change between
Ubergraph syncs) or `soulcap-sync` (the SOULCAP sheet can change too) and
wants to know if any existing mapping is now stale.

## Tools

- `src/soulcap_cl_mapping/sssom_export.py`'s `CURATED_MAPPINGS` table — the
actual curated entries, each with `abbreviation`, `cl_id`, `cl_label`,
`match_type` (`Exact`/`Broad`), optional `evidence_override`, `uncertain`,
and `note`. This is the ground truth for *what was decided*; the generated
`.sssom.tsv` is its rendered output.
- `sssom_export.load_assertion_status()` / `classify_evidence()` — classify a
CL ID's current marker-axiom support as `confirmed` (directly asserted),
`inferred_only`, or `no_marker_axiom`, from
`reports/cl_pro_relationships.tsv`.
- `reports/literature/*.md` and `reports/pro_marker_species_support.tsv` — the
literature side of the evidence a mapping might rely on, especially for
species-specific marker claims.
- `uv run soulcap-match --req-excl ... --ideal-excl ... --req-pheno ...
--ideal-pheno ... --parent "..."` — re-run a SOULCAP profile's marker-axiom
scoring against the *current* CL data to see if the picture has changed
since the mapping was curated.
- `uv run soulcap-lookup --id CL:XXXXXXX` — confirm a term hasn't been
renamed, deprecated, or replaced since curation.

## Step 1 — recompute evidence classification for every curated entry

```bash
uv run python -c "
from soulcap_cl_mapping.sssom_export import CURATED_MAPPINGS, load_assertion_status, classify_evidence
status = load_assertion_status()
for e in CURATED_MAPPINGS:
evidence = e.get('evidence_override') or classify_evidence(e['cl_id'], status)
print(e['abbreviation'], e['cl_id'], e['match_type'], evidence, e.get('uncertain', False))
"
```

This reproduces exactly what `soulcap-sssom` computes today. The audit's job
is to question it, not just print it — for each row, ask:

1. **Does `match_type` still make sense given `evidence`?** An `Exact` match
resting on `no_marker_axiom` (lexical-only) is structurally weaker than its
label implies — flag it, even though `sssom_export.py` already discounts
its numeric confidence (0.55 vs. 0.9 for a confirmed Exact match). The
*label* still reads as "Exact" to anyone skimming `candidate_cl_mappings.md`.
2. **Has the CL side moved?** Re-fetch the CL ID with `soulcap-lookup --id` —
check the label and definition still match what `candidate_cl_mappings.md`
describes. CL is actively maintained (see issues #12–#14, all filed against
terms this project maps to); a maintainer accepting one of those upstream
fixes changes the term's markers/definition/label out from under a mapping
made before the fix landed.
3. **Does literature actually back a species-specific claim the mapping
relies on?** Cross-check against `reports/pro_marker_species_support.tsv`
— if a mapping leans on a marker that TSV records as
`insufficient_evidence` or a different species than SOULCAP's row assumes,
that's a real finding, not noise.
4. **Was it marked `uncertain` for a reason that's since been resolved (or
gotten worse)?** Re-read the `note` field and check whether the ambiguity
it describes is still accurate.

## Step 2 — re-score against current marker axioms for anything suspicious

When Step 1 flags a row, re-run the actual profile (pull the four marker
columns for that `abbreviation` from `data/marker_combinations.csv`) through
`soulcap-match` and compare the result to what's recorded in
`candidate_cl_mappings.md`. A new `contradictions` entry or a `disqualified`
result that wasn't there before is the clearest possible signal something
changed.

## Step 3 — write findings, don't silently fix

This audit's output is a report, not an automatic rewrite of curated mappings
— changing a curated match_type or CL ID is `soulcap-cl-matching`'s job (or a
human decision), not this skill's. Write findings to a new
`reports/mapping_audit.md`, one entry per flagged mapping:

```markdown
## <Abbreviation> — <Full Name> → `CL:XXXXXXX`

**Curated as:** <match_type>, evidence=<evidence tier>, confidence=<value>

**Finding:** <what changed or what doesn't hold up, with the specific
evidence — a soulcap-lookup diff, a soulcap-match re-run, a
pro_marker_species_support.tsv row>

**Suggested action:** <re-curate via soulcap-cl-matching / downgrade
match_type / log as a new gaps.tsv row / no action needed, false alarm>
```

If this is the first run, add `reports/mapping_audit.md` to
[CLAUDE.md](../../../CLAUDE.md)'s repository layout table and to
[ROADMAP.md](../../../ROADMAP.md) Milestone 3 as its (partial) deliverable —
new artifacts get linked from both, per repo convention.

## Step 4 — flag anything that's actually a full M3 blocker

If a finding can't be resolved without the sheet's still-missing broad/exact +
comment columns (e.g. a curator's original *intent* is ambiguous and the
mapping's own `note` doesn't disambiguate it), don't force an answer — log it
as exactly the kind of case that's still blocked, so the roadmap accurately
shows partial progress plus a real remaining blocker rather than looking
either fully done or fully stuck.

## Known limitations

- This audits `CURATED_MAPPINGS` (the signed-off subset, currently 87 of 127
SOULCAP rows) — it says nothing about rows that don't have a curated
mapping yet at all. That's Milestone 4's remaining work, not this skill's.
- `classify_evidence()` only sees `reports/cl_pro_relationships.tsv`, which is
itself a snapshot from the last `soulcap-cl-pro` run against Ubergraph — run
that first if CL upstream has plausibly changed (e.g. one of issues #12–#14
was recently merged) before trusting a "nothing changed" result.
- This is genuinely a reduced version of Milestone 3 as scoped in
`ROADMAP.md` — it catches drift and re-validates evidence, but it cannot
check curator intent (was this *meant* to be broad or exact?) the way the
sheet's planned dedicated columns would. Don't report a clean audit run as
"Milestone 3 done."
Loading
Loading