Skip to content

docs: sync miner guide to recipe 1.4.0 - #4

Open
echobt wants to merge 1 commit into
mainfrom
docs/recipe-1.4.0-sync
Open

docs: sync miner guide to recipe 1.4.0#4
echobt wants to merge 1 commit into
mainfrom
docs/recipe-1.4.0-sync

Conversation

@echobt

@echobt echobt commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Sync public miner docs with BASE docs/external-miner/prism.md on prism-better @ 02c1fd89 (recipe 1.4.0).
  • Document miner-chosen tokenizer (build_tokenizer / tokenizer/; gpt2 is fallback only), source-tree ZIP caps, and G5 pretrain-only long-context (RULER + BABILong + natural MCQ/HELMET RAG).
  • Update examples/baseline to use ctx["tokenizer"] / ctx["vocab_size"] instead of hardcoding hub gpt2 as the challenge rule.

Test plan

  • Skim README + docs/getting-started for recipe 1.4.0 / tokenizer / source-tree consistency
  • Confirm examples/baseline no longer presents GPT-2 as mandatory
  • Confirm no control-plane / secrets / spike research leaked into this repo

Summary by CodeRabbit

  • Documentation
    • Updated the recipe and submission guidance for v1.4.0, including source-tree ZIPs, JSON payloads, training-only submissions, and validation limits.
    • Expanded API, scoring, troubleshooting, and getting-started documentation with v3 metrics, shadow evaluation, Zone B, attribution, anchors, and health checks.
    • Clarified tokenizer requirements, offline behavior, vocabulary handling, model-size limits, and terminal zero-score conditions.
  • Examples
    • Updated the baseline recipe to use harness-provided tokenizers and vocabulary size, with optional custom tokenizer support.
    • Added guidance for multi-file source-tree submissions and tokenizer usage.

Mirror BASE docs/external-miner/prism.md: miner-chosen tokenizer,
source-tree ZIP caps, G5 pretrain-only (RULER/BABILong/natural), and
baseline use of ctx["tokenizer"] / vocab_size (gpt2 remains a fallback
choice, not a challenge rule).
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates Prism documentation and the baseline example for recipe v1.4.0. It documents source-tree submissions, injected tokenizers, v3 scoring and API routes, Zone B reporting, G5 evaluation, intake limits, and terminal cap outcomes.

Changes

Recipe 1.4.0 contract

Layer / File(s) Summary
Submission and tokenizer contract
README.md, docs/README.md, docs/getting-started.md, docs/submit.md, docs/troubleshooting.md
The documentation defines source-tree and two-script submissions, tokenizer injection, source-tree limits, recipe inspection, offline requirements, and terminal CAP_EXCEEDED outcomes.
v3 scoring and API reference
docs/api.md, docs/scoring.md
The references document v3 metrics, Zone A and Zone B evaluation, G5 requirements, additional endpoints, tokenizer-neutral bits_per_byte, and finalized-score emission.
Baseline tokenizer integration
examples/baseline/README.md, examples/baseline/architecture.py, examples/baseline/training.py
The baseline uses ctx["tokenizer"] and ctx["vocab_size"], supports tokenizer resolution, sizes TinyGPT from context, and handles missing padding IDs.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • BaseIntelligence/prism#3: Directly extends the same Prism v3 documentation and source-tree, scoring, and tokenizer guidance.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: synchronizing miner documentation with recipe 1.4.0.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/recipe-1.4.0-sync

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/getting-started.md`:
- Around line 48-58: The tokenizer contract in build_tokenizer must cover the
baseline’s batch call and BatchEncoding behavior, including batched text input,
truncation, padding, return_tensors="pt", .to(device), and enc.input_ids.
Document and enforce these requirements, or update the baseline to use only the
currently documented single-text interface; keep the chosen contract consistent
throughout the baseline and getting-started guide.

In `@docs/scoring.md`:
- Around line 3-12: In docs/scoring.md, explicitly define measured_bpb as the
tokenizer-neutral bits_per_byte value used for live scoring, while
distinguishing it from the legacy per-token bpb key. In README.md lines 29-30,
replace the “bits-per-byte (bpb)” wording with the canonical
measured_bpb/bits_per_byte name and preserve the distinction from legacy bpb.

In `@docs/submit.md`:
- Line 96: Update the training-only intake description near the two-script
layout statement to identify it as the legacy training seam: training.py is
submitted with arch_id, while the architecture is retrieved from the registry.
Remove the claim that the payload is limited to a two-script layout and keep the
surrounding table and follow-up paragraph consistent.
- Around line 55-56: Add the normative ≤ 8 MiB compressed ZIP limit to the
source-tree cap summary in docs/submit.md:55-56. Also update the 400-error
checklist in docs/troubleshooting.md:5 to include both the compressed limit and
the tokenizer/ sub-cap, preserving the existing intake limits.
- Around line 35-52: Update the packaging example so the Python snippet reads
the ZIP from the path actually created by the preceding zip command, and write
its JSON output to submission.json for the subsequent curl command instead of
stdout. Keep the existing archive contents, payload fields, and submission
endpoint unchanged.

In `@examples/baseline/training.py`:
- Around line 61-62: Update the tokenizer setup around tok.pad_token assignment
so EOS is not aliased as padding when it is the only available special token.
Keep padding unset in that case and adjust the batching/loss path to use
padding=False or mask only attention-mask padding positions with
ignore_index=-100 before cross_entropy, preserving EOS targets in the loss.

In `@README.md`:
- Around line 48-50: Update the README instructions around the baseline example
so only prism_telemetry.report is described as required; identify
finish_evaluation as an optional early-stop signal while retaining the
ctx["tokenizer"] requirement.
- Line 39: Update the recipe summaries to replace the vague “natural docs” label
with the exact natural G5 pack names, “natural MCQ” and “HELMET RAG”; apply this
change in README.md lines 39-39 and docs/README.md lines 12-14 so both summaries
use identical naming.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6354e155-91e7-43da-8f7c-34e9916afd30

📥 Commits

Reviewing files that changed from the base of the PR and between 794e258 and efe2652.

📒 Files selected for processing (10)
  • README.md
  • docs/README.md
  • docs/api.md
  • docs/getting-started.md
  • docs/scoring.md
  • docs/submit.md
  • docs/troubleshooting.md
  • examples/baseline/README.md
  • examples/baseline/architecture.py
  • examples/baseline/training.py

Comment thread docs/getting-started.md
Comment on lines +48 to +58
```python
# architecture.py
def build_tokenizer(ctx):
"""Anything offline: train a BPE on ctx["dataset_path"], wrap a vendored
implementation, or hand-roll a byte-level tokenizer. Must satisfy:

tok(text, add_special_tokens=False)["input_ids"] -> list[int]
tok.decode(ids) -> str # roundtrips plain ASCII
len(tok) or tok.vocab_size -> int # 256 .. 262144
tok.eos_token_id -> int | None
"""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C 3 'def build_tokenizer|ctx\["tokenizer"\]|return_tensors|padding|input_ids|attention_mask|\.to\(device\)' \
  docs/getting-started.md examples/baseline/training.py

Repository: BaseIntelligence/prism

Length of output: 4343


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf '--- docs/getting-started.md relevant section ---\n'
sed -n '1,90p' docs/getting-started.md
printf '\n--- examples/baseline/training.py relevant section ---\n'
sed -n '48,105p' examples/baseline/training.py

Repository: BaseIntelligence/prism

Length of output: 251


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf '%s\n' '--- docs/getting-started.md relevant section ---'
sed -n '1,90p' docs/getting-started.md
printf '%s\n' ''
printf '%s\n' '--- examples/baseline/training.py relevant section ---'
sed -n '48,105p' examples/baseline/training.py

Repository: BaseIntelligence/prism

Length of output: 6191


Document the full baseline tokenizer contract.

docs/getting-started.md only specifies single-text tokenization, decode, vocab size, and eos_token_id. The baseline passes a list of texts and calls tok(batch_txt, return_tensors="pt", truncation=True, max_length=block, padding=True).to(device) before reading enc.input_ids. Either document and enforce the batch / BatchEncoding / padding contract, or change the baseline to use the documented minimum.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/getting-started.md` around lines 48 - 58, The tokenizer contract in
build_tokenizer must cover the baseline’s batch call and BatchEncoding behavior,
including batched text input, truncation, padding, return_tensors="pt",
.to(device), and enc.input_ids. Document and enforce these requirements, or
update the baseline to use only the currently documented single-text interface;
keep the chosen contract consistent throughout the baseline and getting-started
guide.

Comment thread docs/scoring.md
Comment on lines +3 to +12
## Pure bpb (live leaf)

`final_score = score_from_bpb(measured_bpb)` on the integer lattice `[0, SCORE_MAX]` —
lower bpb, higher score. The LLM reviews are **gates, not graders**: they verify the
submission is coherent and not cheating; their quality notes never move the score.

**Fairness across tokenizers.** `bits_per_byte` (bits over UTF-8 bytes of the scored
region) is the tokenizer-neutral anchor reported in `METRICS_JSON`. The legacy `bpb`
key is bits per *token* and is only comparable across submissions that share a
tokenizer.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files:\n'
git ls-files | rg '(^|/)(README\.md|docs/(scoring|README|submit|troubling|.*\.md)$)' || true

printf '\nRelevant docs excerpts:\n'
sed -n '1,80p' README.md 2>/dev/null || true
printf '\n--- docs/scoring.md ---\n'
sed -n '1,60p' docs/scoring.md 2>/dev/null || true

printf '\nSearch for exact identifiers:\n'
rg -n "score_from_bpb|measured_bpb|bits_per_byte|bits-per-byte|bits per|METRICS_JSON|bpb" README.md docs 2>/dev/null || true

Repository: BaseIntelligence/prism

Length of output: 8656


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'docs/getting-started.md excerpts:\n'
sed -n '1,90p' docs/getting-started.md 2>/dev/null || true

printf '\nFull occurrences of relevant terms with filenames:\n'
rg -n -C 2 "measured_bpb|score_from_bpb|bits_per_byte|METRICS_JSON|bits-per-byte|bits per (token|byte)|bpb" README.md docs 2>/dev/null || true

printf '\nExact source-line probe for current claimed occurrences:\n'
python3 - <<'PY'
from pathlib import Path
files = ["README.md", "docs/scoring.md", "docs/getting-started.md"]
terms = ["measured_bpb", "score_from_bpb", "bits_per_byte", "METRICS_JSON", "bits-per-byte", "bits per token"]
for path in files:
    try:
        text = Path(path).read_text(encoding="utf-8")
    except FileNotFoundError as e:
        print(f"{path}: MISSING\n")
        continue
    lines = text.splitlines()
    print(f"\n--- {path} ({len(lines)} lines) ---")
    hits, term_hits = [], {t: [] for t in terms}
    for i, line in enumerate(lines, 1):
        if any(t in line for t in terms):
            hits.append(i)
        for t in terms:
            if t in line:
                term_hits[t].append(i)
    print("term hits:", {t: hits_ for t, hits_ in term_hits.items() if hits_})
    for i in (1,29,30,39,43,50,13,63,67,68) if path=="docs/getting-started.md" else (1,5,6,9,11):
        if 1 <= i <= len(lines):
            print(f"{i}: {lines[i-1]}")
PY

Repository: BaseIntelligence/prism

Length of output: 11122


Use one canonical name for the live-score input.

docs/scoring.md introduces measured_bpb without saying it equals the tokenizer-neutral bits_per_byte value, and README.md says live score is “bits-per-byte (bpb)” without distinguishing the legacy per-token bpb key. Define whether measured_bpb is bits_per_byte and replace the README equivalence with the canonical metric name.

📍 Affects 2 files
  • docs/scoring.md#L3-L12 (this comment)
  • README.md#L29-L30
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/scoring.md` around lines 3 - 12, In docs/scoring.md, explicitly define
measured_bpb as the tokenizer-neutral bits_per_byte value used for live scoring,
while distinguishing it from the legacy per-token bpb key. In README.md lines
29-30, replace the “bits-per-byte (bpb)” wording with the canonical
measured_bpb/bits_per_byte name and preserve the distinction from legacy bpb.

Comment thread docs/submit.md
Comment on lines +35 to +52
```bash
# pack the tree (paths relative to project root)
cd my-submission
zip -r ../tree.zip . -x '*.pyc' -x '__pycache__/*' -x '.git/*'

python3 - <<'PY'
import base64, json, pathlib
raw = pathlib.Path("tree.zip").read_bytes()
print(json.dumps({
"miner_hotkey": "<64 lowercase hex>",
"zip_base64": base64.b64encode(raw).decode(),
"label": "optional",
}))
PY

curl -sS -X POST "$GATEWAY/challenge/prism/v1/submissions" \
-H 'content-type: application/json' \
-d @submission.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix the source-tree packaging example before publishing it.

After cd my-submission, the ZIP is written to ../tree.zip, but the Python snippet reads tree.zip from my-submission. The snippet also prints JSON to stdout, while the next command reads submission.json, which the snippet never creates.

Proposed fix
-python3 - <<'PY'
+python3 - <<'PY' > submission.json
 import base64, json, pathlib
-raw = pathlib.Path("tree.zip").read_bytes()
+raw = pathlib.Path("../tree.zip").read_bytes()
 print(json.dumps({
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```bash
# pack the tree (paths relative to project root)
cd my-submission
zip -r ../tree.zip . -x '*.pyc' -x '__pycache__/*' -x '.git/*'
python3 - <<'PY'
import base64, json, pathlib
raw = pathlib.Path("tree.zip").read_bytes()
print(json.dumps({
"miner_hotkey": "<64 lowercase hex>",
"zip_base64": base64.b64encode(raw).decode(),
"label": "optional",
}))
PY
curl -sS -X POST "$GATEWAY/challenge/prism/v1/submissions" \
-H 'content-type: application/json' \
-d @submission.json
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/submit.md` around lines 35 - 52, Update the packaging example so the
Python snippet reads the ZIP from the path actually created by the preceding zip
command, and write its JSON output to submission.json for the subsequent curl
command instead of stdout. Keep the existing archive contents, payload fields,
and submission endpoint unchanged.

Comment thread docs/submit.md
Comment on lines +55 to +56
Caps: ≤ 128 files, ≤ 4 MiB/file, ≤ 16 MiB total uncompressed; `tokenizer/` ≤ 12
files / ≤ 8 MiB. The validated tree is staged on the pod under `submission/`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Keep all intake cap summaries complete.

The normative cap table includes an 8 MiB compressed ZIP limit, but these intake summaries omit it.

  • docs/submit.md#L55-L56: Add ≤ 8 MiB compressed to the source-tree caps.
  • docs/troubleshooting.md#L5-L5: Mirror the compressed limit and tokenizer-directory sub-cap in the 400-error checklist.
📍 Affects 2 files
  • docs/submit.md#L55-L56 (this comment)
  • docs/troubleshooting.md#L5-L5
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/submit.md` around lines 55 - 56, Add the normative ≤ 8 MiB compressed
ZIP limit to the source-tree cap summary in docs/submit.md:55-56. Also update
the 400-error checklist in docs/troubleshooting.md:5 to include both the
compressed limit and the tokenizer/ sub-cap, preserving the existing intake
limits.

Comment thread docs/submit.md

Training-only entries are **separate slots**: one accepted entry per `(hotkey, arch_id)`
— you may train on many published architectures, one script per arch.
Training-only intake accepts the **two-script** layout only (not a full source tree).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Correct the training-only layout description.

Training-only intake sends training.py with arch_id; the architecture is pulled from the registry. “Two-script layout only” conflicts with the table and the next paragraph. Describe this as the legacy training seam, not as a two-script payload.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/submit.md` at line 96, Update the training-only intake description near
the two-script layout statement to identify it as the legacy training seam:
training.py is submitted with arch_id, while the architecture is retrieved from
the registry. Remove the claim that the payload is limited to a two-script
layout and keep the surrounding table and follow-up paragraph consistent.

Comment on lines +61 to +62
if getattr(tok, "pad_token", None) is None and getattr(tok, "eos_token", None) is not None:
tok.pad_token = tok.eos_token

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C 3 'eos_token|pad_token|pad_token_id|attention_mask|ignore_index' \
  examples/baseline/training.py

Repository: BaseIntelligence/prism

Length of output: 928


🏁 Script executed:

#!/bin/bash
set -euo pipefail
wc -l examples/baseline/training.py
sed -n '1,130p' examples/baseline/training.py

Repository: BaseIntelligence/prism

Length of output: 4423


🌐 Web query:

Transformers TokenizerBase __init__ pad_token_id eos_token padding attribute source

💡 Result:

In the Hugging Face Transformers library, PreTrainedTokenizerBase serves as the foundational class for all tokenizer implementations [1][2]. It defines and manages special tokens and padding behavior through several key attributes and properties [3][4]. Special Token Attributes The base class maintains a list of special token names in the class attribute SPECIAL_TOKENS_ATTRIBUTES, which includes bos_token, eos_token, unk_token, sep_token, pad_token, cls_token, and mask_token [1][5]. When a tokenizer is initialized, these are often set via keyword arguments [2][6]. Properties and IDs The class provides property methods to retrieve the integer ID for these tokens, such as pad_token_id and eos_token_id [4][7]. These properties dynamically look up the token's ID in the tokenizer's vocabulary [4]. Specifically: - pad_token_id: Returns the ID of the pad_token [4]. If the token has not been set, it returns None [4]. - eos_token_id: Returns the ID of the eos_token [4]. Similarly, it returns None if not set [4]. - pad_token_type_id: An integer attribute (defaulting to 0) used in conjunction with padding logic [5][6][4]. Padding and Configuration Padding configuration is managed at the tokenizer level using several attributes: - padding_side: Defines whether padding is applied to the left or right of the sequence (defaults to right) [1][6][8]. - Padding Logic: The actual padding process (e.g., during tokenizer.call or via the pad method) utilizes the pad_token_id, pad_token_type_id, and padding_side configuration to create uniform tensors for batching [3][8][9]. During init, the base class processes keyword arguments, ensures no conflicts occur between user-provided arguments and class methods, and handles backward compatibility for special token configuration [2][5][6].

Citations:


🌐 Web query:

Transformers calling tokenizer padding=True raises RuntimeError pad_token_id is None source

💡 Result:

The RuntimeError or ValueError indicating that pad_token_id is None occurs because many modern Transformer models (such as GPT-2, LLaMA, and others) are not pre-configured with a designated padding token [1][2][3]. When you call a tokenizer with padding=True, the library attempts to pad the sequences using a specific token ID, but if that ID is not set in the tokenizer or the model configuration, the process fails [1][4][3]. To resolve this issue, you must explicitly define a padding token for your tokenizer. A common and standard practice is to use an existing special token, such as the End-of-Sentence (EOS) token, as the padding token [3][5]. Recommended Fix: You can set the pad_token and update the model configuration as follows: # Set the pad_token to the eos_token tokenizer.pad_token = tokenizer.eos_token # If you are fine-tuning, it is often necessary to resize the model's token embeddings # to account for any new tokens added to the tokenizer model.resize_token_embeddings(len(tokenizer)) # Ensure the model configuration also has the pad_token_id set model.config.pad_token_id = tokenizer.pad_token_id Alternatively, if you prefer to use a specific padding token (e.g., [PAD]), you can add it directly: tokenizer.add_special_tokens({'pad_token': '[PAD]'}) model.resize_token_embeddings(len(tokenizer)) model.config.pad_token_id = tokenizer.pad_token_id Note: Always ensure that your attention masks are correctly applied when processing padded sequences to prevent the model from attending to the padding tokens, which can otherwise lead to incorrect hidden states [6][7].

Citations:


🌐 Web query:

Transformers tokenizer padding=True tokenizers backends check pad_token_id is None source fast tokenizer

💡 Result:

When using the Hugging Face Transformers library, setting padding=True instructs the tokenizer to pad sequences to the longest sequence in the batch [1][2]. If your tokenizer's pad_token_id is None (common in many base models like Llama or GPT-2), the library will raise a ValueError during batch encoding because it cannot determine which token to use for padding [3]. The ValueError typically states: "Asking to pad but the tokenizer does not have a padding token" [3]. To resolve this, you must explicitly assign a padding token to the tokenizer before performing the batch operation. Common approaches include: 1. Setting the pad token to an existing special token (e.g., the EOS token): tokenizer.pad_token = tokenizer.eos_token 2. Adding a new, dedicated padding token: tokenizer.add_special_tokens({'pad_token': '[PAD]'}) If you are using a fast tokenizer (the default TokenizersBackend), these settings are shared and propagated to the underlying Rust-based implementation [4][5]. After setting the pad_token, you should also ensure your model's configuration reflects this change if necessary (e.g., model.config.pad_token_id = tokenizer.pad_token_id), especially if you are performing generation tasks [6]. Using the call method on your tokenizer is recommended for performance, as it handles the fast backend execution efficiently [7].

Citations:


🌐 Web query:

"hugging face tokenizers" "pad token" "padding is enabled but the tokenizer does not have a padding token"

💡 Result:

The error "Asking to pad but the tokenizer does not have a padding token" occurs in Hugging Face Transformers when you attempt to pad sequences (e.g., in a batch) using a tokenizer that was not configured with a dedicated pad token [1][2][3]. This is common with models that do not have a default padding token defined, such as LLaMA or GPT-2 [3]. To resolve this issue, you must explicitly define a padding token for the tokenizer [1][2][4]. You can do this using one of the following methods: Option 1: Assign an existing special token as the pad token (commonly the EOS token) [1][3]. tokenizer.pad_token = tokenizer.eos_token Option 2: Add a new, dedicated pad token to the tokenizer's vocabulary [1][2][3]. tokenizer.add_special_tokens({'pad_token': '[PAD]'}) After setting the pad token, you should ensure that your tokenizer's padding configuration is correct [4]. If you are using the underlying Tokenizers library directly, you can use the enable_padding method [5][6]: tokenizer.enable_padding(pad_token='[PAD]', pad_id=0) Important considerations: - When using the EOS token as a pad token, be mindful of whether the model's architecture or training data expects a distinct padding behavior [3]. - If you add a new special token, ensure that the model itself is aware of it, often requiring you to resize the model's token embeddings if you are continuing pre-training or fine-tuning [3]. - If you are training a tokenizer from scratch, you can include [PAD] in the special_tokens list during the initial training phase to avoid this issue later [4].

Citations:


🌐 Web query:

HuggingFace Tokenizers Rust Padded padding enabled but tokenizer does not have a padding token source pad_token_id

💡 Result:

The error "padding enabled but tokenizer does not have a padding token" typically occurs when using the Hugging Face transformers library, which requires an explicit pad_token to be set on the tokenizer instance for its padding-related functions to work [1][2][3]. While the lower-level tokenizers (Rust) library allows you to configure padding parameters (like pad_id and pad_token) via enable_padding() [4][5][6], these settings are not always automatically recognized as the designated pad_token when the tokenizer is loaded into the higher-level transformers PreTrainedTokenizerFast class [1][2]. To resolve this error, you must explicitly assign a pad token to the tokenizer object [7][8]. Common solutions include: 1. Setting an existing token as the pad token (e.g., if using a model like GPT-2 that lacks a default pad token) [7][8]: tokenizer.pad_token = tokenizer.eos_token 2. Adding a new special token for padding [1][2][3]: tokenizer.add_special_tokens({'pad_token': '[PAD]'}) If you are working with the tokenizers (Rust) library directly, you configure padding by calling enable_padding() with the desired parameters [4][5][6]: tokenizer.enable_padding( direction=PaddingDirection::Right, // or Left pad_id=0, pad_token="[PAD]".to_string, //... other parameters); The disconnect often arises because transformers maintains its own pad_token property to manage vocabulary and model embedding consistency, which must be explicitly synced when transferring configurations from the Rust tokenizers library [1][2]. If you are loading a custom tokenizer from a file, ensure that any padding configuration saved in the JSON file is correctly mapped to the pad_token attribute upon initialization in transformers [1][2].

Citations:


🌐 Web query:

tokenizer.py tokenizers_tokenizer RustTokenizer padding pad_token_id None source PreTrainedTokenizerFast fast

💡 Result:

When using PreTrainedTokenizerFast in the Hugging Face Transformers library, encountering a pad_token_id of None is a common occurrence because the underlying Rust-based tokenizer object does not automatically infer or map special token concepts from its configuration [1][2]. Key points regarding this behavior include: 1. Manual Configuration Required: Unlike standard Transformers tokenizers that might be pre-configured for specific models, a PreTrainedTokenizerFast instantiated directly from a tokenizer object (or loaded from a file without a complete tokenizer_config.json) does not automatically recognize which token in the vocabulary is intended for padding [1][2]. You must manually assign the pad_token and other special tokens during initialization or by using methods like add_special_tokens [1][3][2]. 2. Handling pad_token_id is None: If pad_token_id is None, any attempt to perform padding operations—such as calling the tokenizer with padding=True—will fail or trigger warnings because the tokenizer does not know which ID to use for the padding operation [2][4]. 3. Technical Context: The PreTrainedTokenizerFast acts as a Python wrapper around the Rust-based tokenizers library [5][6]. While the Rust Tokenizer struct has a with_padding method to set padding parameters [7][8], these must be explicitly configured and synchronized with the Transformers wrapper's special token attributes [1][2]. To resolve this, you should explicitly set the pad_token after initialization [1][2]: tokenizer = PreTrainedTokenizerFast(tokenizer_object=rust_tokenizer) tokenizer.pad_token = "[PAD]" # Or your specific padding token tokenizer.pad_token_id = tokenizer.convert_tokens_to_ids("[PAD]") Additionally, ensure your tokenizer's post-processor is configured correctly if you are building the tokenizer manually [1]. If you are seeing warnings even when not using padding, it is often due to legacy issues where the tokenizer checks for the pad_token_id property unnecessarily; this is generally handled by the library, but ensuring the token is defined is the best practice [9][10].

Citations:


🌐 Web query:

GPT2TokenizerFast from_pretrained "gpt2" pad_token padding behavior

💡 Result:

The GPT-2 tokenizer, including GPT2TokenizerFast, does not have a default pad_token when loaded via from_pretrained("gpt2") [1][2][3]. Because GPT-2 was not trained with a padding token, it lacks this attribute by default [3][4]. If you attempt to use padding (e.g., by calling the tokenizer with padding='max_length' or passing a batch of sequences to the model) without first setting a pad_token, the Hugging Face Transformers library will raise a ValueError [3][4][5]. To resolve this behavior, you must manually assign a pad_token [3][4]. The common recommended practice is to set the pad_token to the existing eos_token [3][4]: tokenizer = GPT2TokenizerFast.from_pretrained("gpt2") tokenizer.pad_token = tokenizer.eos_token When using this for batching, it is also standard practice to set the padding side to 'left' to avoid issues with the model's causal language modeling objective [4]: tokenizer.padding_side = 'left' This configuration allows the tokenizer to perform padding without requiring you to add a new special token to the model's vocabulary, which would otherwise necessitate resizing the model's embedding layer [4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C 4 'tokenizer_contract|tokenizer contract|eos_token_id|pad_token|pad_token_id|build_tokenizer|padding_side|return_tensors="pt"|padding=' . -g '!*.pyc' -g '!node_modules' -g '!dist' -g '!build'

Repository: BaseIntelligence/prism

Length of output: 10877


🏁 Script executed:

#!/bin/bash
set -euo pipefail
python3 - <<'PY'
class Tok:
    def __init__(self, eos_token=None, pad_token=None):
        self.eos_token = eos_token
        self.pad_token = pad_token

tok = Tok(eos_token="<|endoftext|>")
if getattr(tok, "pad_token", None) is None and getattr(tok, "eos_token", None) is not None:
    tok.pad_token = tok.eos_token
print(tok.pad_token, getattr(tok, "pad_token_id", None), getattr(tok, "eos_token", None) is not None)

tok2 = Tok(pad_token=None, eos_token=None)
same_pad_token_id = getattr(tok2, "pad_token", None) is None and getattr(tok2, "pad_token_id", None) is None
print(same_pad_token_id)
PY

Repository: BaseIntelligence/prism

Length of output: 189


Avoid aliasing EOS as the padding token before loss masking.

Lines 61-62 let any eos_token become pad_token, so pad_token_id becomes the real EOS ID. If ids[:, 1:] contains EOS targets, ignore_index=pad_id drops their loss. Keep padding unset when EOS is the only special token, and then batch with padding=False, or mask only attention-mask padding positions with ignore_index=-100 before calling cross_entropy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/baseline/training.py` around lines 61 - 62, Update the tokenizer
setup around tok.pad_token assignment so EOS is not aliased as padding when it
is the only available special token. Keep padding unset in that case and adjust
the batching/loss path to use padding=False or mask only attention-mask padding
positions with ignore_index=-100 before cross_entropy, preserving EOS targets in
the loss.

Comment thread README.md
| Staging gateway | `http://staging.api.joinbase.ai` |
| Submit path | `/challenge/prism/v1/submissions` |
| Recipe | v1.2.0telemetry hooks required |
| Recipe | **v1.4.0**miner-chosen tokenizer; G5 = RULER + BABILong + natural docs (**pretrain-only**) |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use exact names for the natural G5 packs.

“Natural docs” does not identify the two separate scored packs.

  • README.md#L39-L39: Name natural MCQ and HELMET RAG explicitly.
  • docs/README.md#L12-L14: Use the same exact G5 names in the recipe summary.
📍 Affects 2 files
  • README.md#L39-L39 (this comment)
  • docs/README.md#L12-L14
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 39, Update the recipe summaries to replace the vague
“natural docs” label with the exact natural G5 pack names, “natural MCQ” and
“HELMET RAG”; apply this change in README.md lines 39-39 and docs/README.md
lines 12-14 so both summaries use identical naming.

Comment thread README.md
Comment on lines +48 to +50
2. Copy [`examples/baseline/`](examples/baseline/) — required telemetry hooks
(`prism_telemetry.report` + `finish_evaluation`) and `ctx["tokenizer"]`.
3. Zip and submit — see [Submit](docs/submit.md).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Mark finish_evaluation() as optional.

prism_telemetry.report(...) is required. finish_evaluation() is an optional early-stop signal. Grouping both under “required telemetry hooks” gives miners an incorrect contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 48 - 50, Update the README instructions around the
baseline example so only prism_telemetry.report is described as required;
identify finish_evaluation as an optional early-stop signal while retaining the
ctx["tokenizer"] requirement.

@echobt

echobt commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Prod audit note: live GET /challenge/prism/v1/recipe today is still recipe 1.2.0 with pin_hex=cba5280d64e9586a89c7316ca94f9281db64d476db69ffa770e198bacc1d09ab and train_rows: 2048. Docs that advertise 1.4.0 / v3 / source-tree / G1–G8 describe prism-better (unreleased) — merging this before that control-plane ships will widen the public/prod mismatch miners are already hitting. Prefer holding until prod rolls the new recipe pin, or retarget to clearly mark “upcoming.”

@echobt

echobt commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Hold — do not merge yet.

Production still runs recipe 1.2.0 (pin_hex=cba5280…, train_rows=2048 / val_rows=256, 6h cap). This PR documents 1.4.0 / v3 control-plane work that is not what prod executes today.

Please leave open until after a prod pin cutover to 1.4.0; merging earlier would contradict the live recipe miners hit at GET /challenge/prism/v1/recipe.

Docs-only clarity for current prod (train_rows vs full-shard streaming) shipped separately in #5.

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.

1 participant