feat: add embeddings (self-supervised contrastive) modality#327
Merged
Conversation
Enable the NLP embeddings / contrastive use case end-to-end on the ingestor side, mirroring how seq2seq is wired. The on-disk contract is one .txt per sample under texts/, each a tab-separated anchor<TAB>positive pair OR anchor<TAB>positive<TAB>negative triplet (no label column). Wiring (mirrors seq2seq — closest sibling): - utils/constants.py: TaskCategory.EMBEDDINGS. - schema/ingest.v1.json: enum value, texts requirement, and the self-supervised no-label guard (#213). - modalities/registry.py: ModalitySpec (file-bearing, self-supervised, NLP, texts/) — is_nlp gates the #805 data-derived text profile (the ingestor side of the federated tokenizer-alignment check). - modalities/transfer.py + cli/conventions.py: raw-text staging from texts/. What's distinct from seq2seq: the on-disk shape is STRUCTURED, so beyond the shared TextContentValidator (UTF-8/binary hygiene) the embeddings factory adds a centralized ContrastivePairsValidator that rejects any .txt that is not exactly 2 or 3 non-empty tab fields (no plain prose, no empty fields, one record per file). Template fails loudly via the shared run_ingestion helper (no exit-0-on-failure); shared validation lives in the centralized validators (#317). Adds templates/embeddings (script + README + sample pairs/triplets), examples/yaml/embeddings.yaml, and full test coverage (new + updated enumerating tests, e2e params). Suite green; new validator at 100% coverage. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit eef0dff. Configure here.
ContrastivePairsValidator joined the manifest filename onto SRC_PATH/texts with plain os.path.join, so an absolute / `..` manifest value could be validated and read from outside texts/ even though text_transfer rejects it (#239) — preflight could disagree with copy behavior. Resolve with _safe_join and skip on ValueError, exactly as TextContentValidator does. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
aptracebloc
approved these changes
Jun 30, 2026
shujaatTracebloc
added a commit
that referenced
this pull request
Jun 30, 2026
Cuts v0.5.4 to ship the embeddings (self-supervised contrastive) modality (#327), which merged after v0.5.3. release-image.yml builds 0.5.4 and repoints the floating 0.5 tag, the first image to contain embeddings. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shujaatTracebloc
added a commit
that referenced
this pull request
Jul 3, 2026
…mmary flow The embeddings (#327) and sentence_pair (#329) suites branched before the #325 global-meta refactor, which removed the per-batch send_batch publish in favour of one send_ingest_summary call after commit. Their `*_api_send_failure_counts_every_record` tests still asserted the removed per-record `api_send_failed` accounting (send_batch is never called now), so they failed `assert 0 == 2`. Rewrite both to the post-refactor contract, mirroring the passing sibling test_ingest_summary_failure_raises_out_of_ingest: a failing send_ingest_summary raises out of ingest() so the run still exits non-zero. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

What
Enables the NLP embeddings / contrastive use case ("shape #5") on the data-ingestors side, mirroring the seq2seq wiring (closest sibling). The training container (tracebloc-engine #302) is already done; this is the ingestor half of the cross-repo wiring. Prerequisite for staging an embeddings dataset.
On-disk contract: one
.txtper sample undertexts/, each a tab-separatedanchor<TAB>positivepair ORanchor<TAB>positive<TAB>negativetriplet. No label column (self-supervised contrastive).Touchpoints (mirrors
seq2seq)utils/constants.py—TaskCategory.EMBEDDINGS.modalities/registry.py—ModalitySpec(file-bearing, self-supervised, NLP,texts/).is_nlp=Trueis the ingestor-side #805 tokenizer gating: it ships the data-derived text profile on the global-metadata channel for the contributor-tokenizer-fit check.modalities/validators.py+ newvalidators/contrastive_pairs_validator.py— validates the on-disk format. Beyond the sharedTextContentValidator(UTF-8/binary hygiene), the new centralizedContrastivePairsValidatorrejects any.txtthat isn't exactly 2 or 3 non-empty tab fields (plain prose, empty field, 4+ fields, multi-line → rejected).schema/ingest.v1.json— enum value,textsrequirement, self-supervised no-label guard (Setting label: for a self-supervised category produces misleading backend HTTP 400 'No data found' #213).modalities/transfer.py+cli/conventions.py— raw-text staging fromtexts/.templates/embeddings/— script + README + sample pairs/triplets;examples/yaml/embeddings.yaml; Readme entry.Repo gotchas (verified not reintroduced)
run_ingestionhelper (noexit 0on hard failure) — pinned bytest_modality_failure_accounting/test_batch_send_failure_accounting.zip(ids, batch)mispair: the send path is untouched; embeddings reuses the existingtext_transfer+ base ingestor.validators/, not a per-template copy.Tests
tests/test_embeddings.py(wiring, mirrorstest_seq2seq.py) andtests/test_contrastive_pairs_validator.py(structural unit tests)._TEMPLATE_CATEGORIES) and e2e params.🤖 Generated with Claude Code
Note
Medium Risk
Touches the published ingest schema and modality registry (new category must stay in sync everywhere), but behavior reuses existing text transfer and adds validation-only constraints rather than changing core ingest paths.
Overview
Adds a new
embeddingsNLP ingest category for self-supervised contrastive training: CSV manifest plus one.txtper sample undertexts/, each file holding eitheranchor<TAB>positiveoranchor<TAB>positive<TAB>negative(nolabel:— same self-supervised guard as seq2seq/MLM, #213).Wiring mirrors seq2seq (file-bearing, NLP,
text_transferfromtexts/) but addsContrastivePairsValidatorso ingest rejects malformed shapes (wrong field count, empty fields, multi-line files) that free-form seq2seq/causal LM would allow.TaskCategory.EMBEDDINGS, modality registry,ingest.v1.json, and CLITEXT_CATEGORIESare updated;templates/embeddings/,examples/yaml/embeddings.yaml, and README docs ship sample data.E2E/characterization suites and registry, schema, validator-mapping, template-equivalence, and modality tests are extended so the 14th category stays congruent end-to-end.
Reviewed by Cursor Bugbot for commit 347e52b. Bugbot is set up for automated code reviews on this repo. Configure here.