Repository navigation
Read each SGDP workspace tar's samples from its own callset.json (#724) - #728
Merged
Merged
Conversation
The tar fetcher reads a GenomicsDB workspace's callset.json, after the head walk, for the workspaces header_classifier.CALLSET_FOLDERS declares (ANVIL_T2T_CHRY's SGDP_CHM13v2/ and SGDP_GRCh38/ genomics_db folders), and caches it beside vcfheader.vcf with a looked-for flag (TarEvidence.callset). The pipeline hands the fetcher each record's dataset and folder, since an SGDP tar and a 1000 Genomes tar share names. parse_tar_head parses it with callset_samples, moved from external_lineage into cohort_steps so the producer and the #710 importer share one parser. TAR_CONFIG's sample reader (code_rules.TAR_CALLSET_SAMPLES) takes all the names through sample_identity or none. A tar whose callset was not wanted is not counted; one wanted and not read is unread, its cause counted per dataset under the producer's details.unread_samples. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VF7tbFa5ZTmYWZ6JWKiBBS
…_samples, and simplify (#724) Review round on the SGDP callset reader: - The tar cache is keyed by md5 alone, so a cached callset.json was given to any file of the same bytes, whatever its folder. The fetcher now asks the samples member first and returns no callset for a file it is not wanted for, keeping the entry's text on disk. - Every producer that reads samples writes details.unread_samples, empty or not, as it writes sample_outcomes and unrecognised_samples. - The pipeline binds the file's dataset and folder into samples_member, so no fetcher takes them; one helper picks the cached or fresh callset on both paths; each distinct callset text is parsed once per run; docstrings and CLAUDE.md say only what the code covers. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VF7tbFa5ZTmYWZ6JWKiBBS Co-authored-by: cc-claude-tools <cc-claude-tools@clevercanary.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The cache-upgrade path incorrectly treats plain workspaces named .tar.gz as compressed, preventing sample extraction that succeeds on a fresh fetch.
1 open issue
What changed in this PR
Adds sample extraction from SGDP GenomicsDB workspace tars using each archive’s own callset.json, feeding the existing sample reconciliation process. Donor-link gaps tracked in #718 remain outside this change.
Changes:
- Fetches and caches callsets only for declared SGDP folders, with retries for failed member reads.
- Shares callset parsing with the external lineage importer and records unread-sample causes.
- Adds regression coverage and updates fixtures and documentation.
| File | Description |
|---|---|
| tests/test_fetchers.py | Tests callset fetching, caching, retries, and folder isolation. |
| tests/test_external_lineage.py | Moves shared parser tests to cohort coverage. |
| tests/test_cohort_steps.py | Tests parsing, folder selection, and sample reporting. |
| tests/fixtures/golden/expected_output.json | Updates expected sample metadata. |
| src/meta_disco/sample_identity.py | Adds tar sample reading and unread-cause hooks. |
| src/meta_disco/records.py | Defines the unread-samples metadata key. |
| src/meta_disco/reconcile_samples.py | Documents additional sample sources. |
| src/meta_disco/pipeline.py | Binds folder context and aggregates unread causes. |
| src/meta_disco/header_classifier.py | Declares eligible SGDP workspace folders. |
| src/meta_disco/file_types.py | Enables tar callset and sample readers. |
| src/meta_disco/fetchers.py | Fetches and caches selected callset members. |
| src/meta_disco/external_lineage.py | Uses shared callset parsing and constants. |
| src/meta_disco/evidence.py | Adds callset text and read-state fields. |
| src/meta_disco/cohort_steps.py | Parses callsets and reports failure causes. |
| src/meta_disco/code_rules.py | Registers the tar sample rule. |
| scripts/generate_rules_report.py | Updates sample-rule explanatory text. |
| CLAUDE.md | Documents callset caching and sample extraction. |
Review effort: Balanced
…s decide (#724) The cached path declined a wanted callset.json on the file name's `.gz` alone, while a fresh read checks the gzip magic: a plain workspace misnamed `.tar.gz` with a header-only cache entry never had its callset read. Such an entry is now walked again from its head, as for the kept member, and the walk decides by the bytes. Copilot review, PR #728. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VF7tbFa5ZTmYWZ6JWKiBBS Co-authored-by: cc-claude-tools <cc-claude-tools@clevercanary.com>
…lk (#724) The previous commit walked a cached tar named `.gz` again to learn whether its bytes are compressed before reading its callset; a failed walk raised FetchError and unclassified a tar its cached names and header classify. The question is now one two-byte range read, asked only where the callset is wanted, and a failure of it is the callset's unread cause, retried next run. Copilot review, PR #728. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VF7tbFa5ZTmYWZ6JWKiBBS Co-authored-by: cc-claude-tools <cc-claude-tools@clevercanary.com>
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No blocking issues remain, and the supplied regression coverage addresses scoped fetching, cache isolation, retry behavior, and sample-reader integration.
No open issues 🎉
1 resolved since last review
Review effort: Balanced
…ted paths (#724) From a no-context review of PR #728: the fetcher docstring now says which cached entries have only the callset read, that only a tar named `.gz` is asked by its bytes, and that a file the callset is not wanted for gets none; TarHead's fields are per file; CLAUDE.md says which tars are counted by cause. New tests pin an uncached plain tar named `.gz` (and its bytes counted), an HTTP failure of the gzip check, and a re-walked entry keeping its callset for a file it is not wanted for; each fails under the mutation it guards. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VF7tbFa5ZTmYWZ6JWKiBBS Co-authored-by: cc-claude-tools <cc-claude-tools@clevercanary.com>
…allset.json (#724) The "What is not true yet" bullet on 2.11 said the 62,022 SGDP tars are "not read"; that is still so for the lineage importer, but their samples are now read from each tar's own callset.json. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VF7tbFa5ZTmYWZ6JWKiBBS Co-authored-by: cc-claude-tools <cc-claude-tools@clevercanary.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Closes #724
What changed
callset.jsonfor the foldersheader_classifier.CALLSET_FOLDERSdeclares: ANVIL_T2T_CHRY'sSGDP_CHM13v2/genomics_dbandSGDP_GRCh38/genomics_db. An SGDP tar and a 1000 Genomes tar can share a file name, so the pipeline binds each record's dataset and folder into the newFileTypeConfig.samples_memberhook. The fetcher asks that hook with the member names, as it askskept_member._read_kept). Its text is cached besidevcfheader.vcfasTarEvidence.callset, with a looked-for flag,callset_read.callset_samplesmoved fromexternal_lineageintocohort_steps, so the classifier and the Workaround for #624: link ANVIL_T2T_CHRY's 1000 Genomes workspace tars to the Schatz lab's published sample maps, checked by each tar's callset.json #710 importer share one parser.parse_tar_headparses each distinct text once per run. It givesParsedTarHead.samples, or why there are none:no_callset,callset_unreadableornot_a_callset.TAR_CONFIG.samplesreads through a new rule,code_rules.TAR_CALLSET_SAMPLES(tar_callset_samples). It takes all the names throughrules/sample_namespaces.yaml, or none.SampleReadergains two optional hooks, used only by the tar reader.applieskeeps a tar whose callset was not wanted out of the counts.why_unreadputs the cause on anunreadreading.details.unread_samples, the files per cause per dataset, besidesample_outcomesandunrecognised_samples.unread_sampleskey on the five producers that read samples.Why
The 62,022 SGDP workspace tars in ANVIL_T2T_CHRY had no samples, so they reached no donor. The 1000 Genomes tars get theirs from the published sample maps (#710), but the SGDP maps aren't public (#624). Each tar names its own samples in
callset.json.Assumptions I made
header_classifier, not YAML. Adding the 1000 Genomes tars is Check the 1000 Genomes workspace tars' samples against their own callset.json #725.callset.jsonis not read. The head walk keeps only one member, and a gzip stream can't be entered at its tail. The cause is counted, and the tar's classifications are not failed. No SGDP tar is compressed (measured 0).details. The reconcile report still shows a singleunreadtotal per dataset.callset_unreadableand asked again each run.Range, as AWS and GCP do.vcfheader.vcf(Link T2T's GenomicsDB tars to their cohort: sample maps, the tars' own step, values read through the map #621) behaves the same.How to verify
The run used below is
output/anvil/20261021_172513:make classifyat 60abcef ran the tar producer in about 1 h 54 min, and reconciled its own run.callset.jsonreads failed transiently in that pass.make classify-tar RUN_DIR=output/anvil/20261021_172513re-read just those 43 (2 min, all read), thenmake reconcile RUN_DIR=…ran.make classify-tar RUN_DIR=…(from cache) andmake reconcile RUN_DIR=…ran again. Every number below is unchanged. The run's tar file andreconciled/are now from 4b302eb; its other 13 inference files are from 60abcef, and the later commits change no output for them. The two commits after 4b302eb change only docs and tests.The issue's definition of done, item by item:
make classify, thenmake reconcile. Run as above. To repeat it on a fresh checkout of this branch:make classify(SGDP tars come from the cache ifdata/evidence/anvil/taris shared, otherwise about 2 h of range reads), thenmake reconcile.About 62,022 more files with samples. Count reconciled file records whose
samplesis set: 591,781 in run20261019_225524, 653,803 here, +62,022.20261021_154039), the only change in either artifact issampleson those 62,022 tar records.donors,samplesandexternal_listsare identical.About 62,022 more files reaching a donor (591,045 today). This holds only under a looser count than the one behind 591,045.
20261019_225524simons_data_sample_33,_187,_273and_304. Each chrY tar lists_273.samples.list_idtoreconciled/sample_lists.ndjson.gz, and each member to areconciled/samples.ndjson.gzrecord withcollected_from.The tar producer's samples outcomes per dataset, with every tar not read counted by cause. In
output/anvil/20261021_172513/tar_classifications.json, undermetadata.details:sample_outcomes:{"ANVIL_T2T_CHRY": {"named": 62022}}unread_samples: per cause. The first pass had{"ANVIL_T2T_CHRY": {"callset_unreadable": 43}}; after the re-read it is empty, because every callset was read.Header samples, …andSamples not read, …lines.make test-all(3,264 + 98 passed),make lint-all(Pyright 0 errors),make format-checkandmake validate-metadataall pass.🤖 Generated with Claude Code
https://claude.ai/code/session_01VF7tbFa5ZTmYWZ6JWKiBBS
🐦 Built with cc-claude-tools