@@ -185,6 +185,13 @@ def _init_schema(self) -> None:
185185 self ._execute_write (
186186 "CREATE TABLE IF NOT EXISTS dedup_meta (key TEXT PRIMARY KEY, val INTEGER)"
187187 )
188+ self ._execute_write (
189+ "CREATE TABLE IF NOT EXISTS chunk_claims ("
190+ "namespace TEXT NOT NULL, "
191+ "hash BLOB NOT NULL, "
192+ "claim_count INTEGER NOT NULL, "
193+ "PRIMARY KEY(namespace, hash))"
194+ )
188195 # next doc_id counter for near-dup docs.
189196 self ._execute_write (
190197 "INSERT OR IGNORE INTO dedup_meta (key, val) VALUES ('next_doc_id', 0)"
@@ -369,6 +376,44 @@ def seen_near_tokens(self, token_ids: Sequence[int]) -> bool:
369376 self ._mark_pending ()
370377 return False
371378
379+ def claim_chunk_tokens (
380+ self ,
381+ token_ids : Sequence [int ],
382+ * ,
383+ namespace : str = "train_chunk" ,
384+ max_count : int = 1 ,
385+ ) -> bool :
386+ """Claim one semantic training chunk by its tokenized body.
387+
388+ This is separate from the ``exact``/``minhash`` dedup tables. Exact/near
389+ dedup decides whether a function may be emitted as a root document;
390+ chunk claims decide whether that already-tokenized function/class/type
391+ body may appear anywhere in the training stream. The unit of ownership is
392+ still the caller-provided semantic chunk; the hash is only the SQLite key.
393+
394+ Returns True when this call successfully claimed one slot. Returns False
395+ when the tokenized chunk has already reached ``max_count`` in ``namespace``.
396+ The write is committed immediately so concurrent conveyor processes see
397+ the claim before they assemble overlapping 1k/2k/4k/8k buckets.
398+ """
399+ if max_count < 1 :
400+ raise ValueError ("claim_chunk_tokens requires max_count >= 1" )
401+ if not namespace :
402+ raise ValueError ("claim_chunk_tokens requires a non-empty namespace" )
403+ h = _sha1_tokens (token_ids )
404+ cur = self ._execute_write (
405+ "INSERT INTO chunk_claims(namespace, hash, claim_count) "
406+ "VALUES (?, ?, 1) "
407+ "ON CONFLICT(namespace, hash) DO UPDATE SET "
408+ "claim_count = claim_count + 1 "
409+ "WHERE claim_count < ?" ,
410+ (namespace , h , int (max_count )),
411+ )
412+ # Claims are coordination records, not buffered dedup rows. Commit them
413+ # immediately so other WAL connections see the slot before emitting docs.
414+ self .commit ()
415+ return cur .rowcount == 1
416+
372417 # ----------------------------------------------------------------- #
373418 def _load_minhash (self , doc_id : int ):
374419 row = self .conn .execute (
0 commit comments