Skip to content

feat: add embeddings (self-supervised contrastive) modality#327

Merged
shujaatTracebloc merged 2 commits into
developfrom
claude/magical-haslett-9057c4
Jun 30, 2026
Merged

feat: add embeddings (self-supervised contrastive) modality#327
shujaatTracebloc merged 2 commits into
developfrom
claude/magical-haslett-9057c4

Conversation

@shujaatTracebloc

@shujaatTracebloc shujaatTracebloc commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

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 .txt per sample under texts/, each a tab-separated anchor<TAB>positive pair OR anchor<TAB>positive<TAB>negative triplet. No label column (self-supervised contrastive).

Touchpoints (mirrors seq2seq)

  1. utils/constants.pyTaskCategory.EMBEDDINGS.
  2. modalities/registry.pyModalitySpec (file-bearing, self-supervised, NLP, texts/). is_nlp=True is the ingestor-side #805 tokenizer gating: it ships the data-derived text profile on the global-metadata channel for the contributor-tokenizer-fit check.
  3. modalities/validators.py + new validators/contrastive_pairs_validator.py — validates the on-disk format. Beyond the shared TextContentValidator (UTF-8/binary hygiene), the new centralized ContrastivePairsValidator rejects any .txt that isn't exactly 2 or 3 non-empty tab fields (plain prose, empty field, 4+ fields, multi-line → rejected).
  4. schema/ingest.v1.json — enum value, texts requirement, self-supervised no-label guard (Setting label: for a self-supervised category produces misleading backend HTTP 400 'No data found' #213).
  5. modalities/transfer.py + cli/conventions.py — raw-text staging from texts/.
  6. templates/embeddings/ — script + README + sample pairs/triplets; examples/yaml/embeddings.yaml; Readme entry.

Repo gotchas (verified not reintroduced)

  • Fail loudly: the template routes through the shared run_ingestion helper (no exit 0 on hard failure) — pinned by test_modality_failure_accounting / test_batch_send_failure_accounting.
  • No zip(ids, batch) mispair: the send path is untouched; embeddings reuses the existing text_transfer + base ingestor.
  • Centralized validation (refactor(validators): compose common validators centrally (supersedes #316) #317): the structural check lives in validators/, not a per-template copy.

Tests

  • New tests/test_embeddings.py (wiring, mirrors test_seq2seq.py) and tests/test_contrastive_pairs_validator.py (structural unit tests).
  • Updated enumerating tests (registry NLP set, validators_mapping, template_equivalence, schema_validation, modality_failure_accounting _TEMPLATE_CATEGORIES) and e2e params.
  • Full suite green: 1312 passed, 1 xfailed; total coverage 97% (≥95 gate), new validator at 100%.

🤖 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 embeddings NLP ingest category for self-supervised contrastive training: CSV manifest plus one .txt per sample under texts/, each file holding either anchor<TAB>positive or anchor<TAB>positive<TAB>negative (no label: — same self-supervised guard as seq2seq/MLM, #213).

Wiring mirrors seq2seq (file-bearing, NLP, text_transfer from texts/) but adds ContrastivePairsValidator so 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 CLI TEXT_CATEGORIES are 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.

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>
@shujaatTracebloc shujaatTracebloc self-assigned this Jun 30, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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.

Comment thread tracebloc_ingestor/validators/contrastive_pairs_validator.py Outdated
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>
@shujaatTracebloc shujaatTracebloc merged commit 0faa9c3 into develop Jun 30, 2026
6 checks passed
@shujaatTracebloc shujaatTracebloc deleted the claude/magical-haslett-9057c4 branch June 30, 2026 12:06
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>
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.

4 participants