docs(worker): describe the v5 mask seam; make config install atomic on refusal - #18
Merged
Merged
Conversation
Owner
Author
|
@copilot resolve the merge conflicts on this branch. |
Copilot stopped work on behalf of
undeemed due to an error
July 29, 2026 14:02
2 of 2, on top of the port. Prose only - no AST node changed in any touched Python file, verified by comparing docstring-stripped ASTs against PR 1's head. PR 1 re-targeted a2d's three eager attention seams onto v5's shared `masking_utils` mask interface but left the surrounding prose describing 4.x internals that no longer exist: GPT-2's `self.bias` buffer, the RoPE family's `_update_causal_mask` method, Gemma 2/3's per-layer `is_sliding` window flag and the signature-agnostic layer-forward wrap that used to anneal it. Replace those with the mechanism that is now there - one registry key per `AnnealState` in `ALL_MASK_ATTENTION_FUNCTIONS`, a reveal derived from `eager_mask`'s own output, per-model rather than per-process isolation, and `config.layer_types` as the structural signal `resolve_capabilities` reads for `attn.swa`. Also correct the root `pyproject.toml` mypy override comment: 5.14.1 still ships an empty `py.typed`, and its inline annotations still disagree with the runtime (`**kwargs` config fields, `Trainer.compute_loss`), so `follow_imports = "skip"` stays - dropping it reintroduces 68 errors, which the comment now records. AGENTS.md gets the same treatment plus a pointer to the new hook-guard test, since a silently-ignored registry key is the failure mode this design invites.
…op wrapper vocabulary from tests
undeemed
force-pushed
the
fm/a2d-dep-transformers-t1-docs
branch
from
July 29, 2026 14:07
1fbe095 to
0bc4536
Compare
… fixture docstring
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 Changed
AGENTS.md,docs/CONCEPTS.md,docs/SPEC-HANDOFF.md,docs/PLAN-PHASE2.md, theCapability::blocking()comment incrates/a2d-contracts/src/lib.rs) to describe the seam the code actually installs: onetransformers>=5mask interface (ALL_MASK_ATTENTION_FUNCTIONS) in place of the three retired v4 seams (GPT-2'sself.bias,_update_causal_mask, Gemma 2/3's per-layer window).resolve_capabilitiesprose now names the real gates -config.layer_typessliding_attentionbeforenum_key_value_headsbeforeGPT2Attention- and the pin note moves from4.51.3to5.14.1.install_mask_annealatomic on refusal:model.config.use_cache = Falseis now set only afterset_attn_implementationis verified to have taken, so a rejected key raises with the model as it was instead of leaving cache off and the seam still causal. Covered by the newtest_bidir.py::test_install_leaves_the_model_untouched_when_transformers_refuses_the_key.layer_typesgate, and renamedtest_swa_wrapped_layer_survives_gradient_checkpointingtotest_swa_annealed_mask_survives_gradient_checkpointing.Risk Assessment
✅ Low: The branch is documentation-only apart from one line reordering in install_mask_anneal that tightens install atomicity, and that reorder is covered by a new targeted test and verified safe against transformers 5.14.1's set_attn_implementation, which has no use_cache dependency.
Testing
Ran the full Python worker suite and the full cargo workspace suite (both green), then exercised the change the way a user would: three real
a2d convertruns on tiny local random-weight models, one per capability gate, each passing the D13 identity gate at max_abs_diff=0.00e0 and producing a completed run dir thata2d samplethen denoises from. On top of that I wrote a claim-check harness that quotes each statement the docs change makes and prints the observed runtime value beside it - all 12 hold, including the ASCII mask grids showing Gemma 3 taking two masks (full + sliding) through the one interface while Mistral takes a single folded-window mask that fully opens at alpha=1, and the atomic-install behavior change leaving use_cache untouched when the key is refused. One sub-claim is unverified by design: the pyproject comment's "dropping follow_imports=skip reintroduces 68 errors" is a mypy assertion, and this run is not allowed to invoke linters or static analysis, so CI's mypy gate remains its only check.Evidence: Documented-claim check: each doc statement vs observed runtime value (12/12 verified)
Evidence: Harness source for the claim check
Evidence: a2d CLI transcript: detect + convert + sample, one run per capability gate
Evidence: Tiny model-dir builder used for the CLI runs (no network)
Evidence: Gemma 3 gets TWO masks per forward through the one seam; Mistral gets ONE folded-window mask that fully opens at alpha=1
Evidence: End-user CLI: converting a sliding-window Gemma 3 through the attn.swa gate
Pipeline
Updates from git push no-mistakes
⏭️ **intent** - skipped
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed (2) ✅
packages/a2d-worker-hf/src/a2d_core/transform/attention.py:142- install_mask_anneal writes the per-state key into two process-global registries (AttentionMaskInterface / AttentionInterface, lines 142-143) BEFORE validating that transformers accepted it (line 146). Nothing removes them. Two consequences: (a) the new atomicity guarantee is partial - commit 1983f1b and test_bidir.py::test_install_leaves_the_model_untouched_when_transformers_refuses_the_key only prove model.config is clean, while the failed install leaves both global entries registered and pins its AnnealState alive via the closure at line 142; (b) same root cause, every install grows both dicts permanently, and re-install is a supported flow (denoiser.py:49 builds a fresh AnnealState per denoise() call; test_gqa_attention.py::test_gqa_reinstall_with_fresh_state_takes_effect and the swa equivalent both re-install). Fix: wrap lines 144-146 in try/except and popkeyfrom both registries before re-raising, which completes the atomicity the commit set out to add.crates/a2d-contracts/src/lib.rs:184- This branch newly asserts that Qwen2 with use_sliding_window routes to the attn.swa handler, in four places (crates/a2d-contracts/src/lib.rs:184, transform/swa_attention.py:2, handlers/swa_attention.py:3, handlers/gqa_attention.py:9), reversing the base commit's claim that windowed Qwen2 unwindows through the shared attn.gqa mask reveal. Nothing verifies it: there is no windowed-Qwen2 fixture or test, and the repo's only Qwen2 config (fixtures/configs/qwen2/config.json) has use_sliding_window=false. Compare the parallel Mistral claim, which IS pinned by test_gqa_attention.py:260-261 assertinglayer_types is Noneandresolve_capabilities == ["attn.gqa"]. The claim also hides a detect/worker divergence: the worker gates onsliding_attentionin config.layer_types, whose transformers-side derivation depends on max_window_layers, while the detect guard (crates/a2d-detect/src/generic.rs:153-154) only checks sliding_window > 0 and use_sliding_window != false - so a Qwen2 config with use_sliding_window=true and max_window_layers >= num_hidden_layers would be tagged attn.swa by detect but routed to attn.gqa by the worker. Additionally docs/CONCEPTS.md:26, edited in this same series, still lists Qwen2 plainly under the attn.gqa RoPE family with no windowed qualifier, so the branch contradicts itself. Either add a windowed-Qwen2 assertion mirroring the Mistral one, or drop Qwen2 from the swa prose until it is pinned.🔧 Fix: drop unverified windowed-Qwen2 attn.swa routing claim from docs
1 warning still open:
packages/a2d-worker-hf/tests/conftest.py:135- Rewritten in this branch but still carries a transformers 4.51.3-era claim: "oneposition_embeddingspair where Gemma 3 takes a global/local pair". Under the pinned 5.14.1,Gemma3DecoderLayer.forwardtakes a singleposition_embeddingsparam (modeling_gemma3.py:409); the model builds a per-layer-type dict and hands each layer one tuple (modeling_gemma3.py:571-579), exactly likeGemma2DecoderLayer.forward(modeling_gemma2.py:318). The global/local split the old swa wrapper had to survive is gone, so the parenthetical names a difference that no longer exists. The derived claims at test_swa_attention.py:8 ("Gemma 2 - a different decoder-layer shape from Gemma 3") and test_swa_attention.py:203 ("Gemma 2 has its own decoder-layer shape") rest on the same premise. The fixture still earns its keep (Gemma 2 differs in rotary handling, logit softcapping, and the every-other-layerlayer_typesformula) - the rationale text just needs to name a real v5 difference instead of the retired signature one. This is the exact class of stale-v4 prose the branch set out to remove.🔧 Fix: replace stale Gemma 3 global/local rope claim in fixture docstring
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
uv run --offline pytest -q(full worker suite, 94 passed)cargo test --workspace(47 passed across a2d-contracts, a2d-detect, a2d-run, corpus fixtures)uv run --offline pytest packages/a2d-worker-hf/tests/test_bidir.py packages/a2d-worker-hf/tests/test_gqa_attention.py packages/a2d-worker-hf/tests/test_swa_attention.py packages/a2d-worker-hf/tests/test_identity.py packages/a2d-worker-hf/tests/test_smoke_convert_gemma3.py -v(46 passed)test_bidir.py::test_install_leaves_the_model_untouched_when_transformers_refuses_the_key- the new guard for the atomic-install changetest_bidir.py::test_install_routes_the_model_and_only_it_through_the_annealed_seam- the guard AGENTS.md now names by pathManual: wrote and ran/tmp/no-mistakes-evidence/01KZ008FZV4B897QTZMDZS175P/docs_claim_check.py- 12 documented claims checked against runtime values (pin 5.14.1, ALL_MASK_ATTENTION_FUNCTIONS seam, resolve_capabilities order over gpt2/llama/qwen2/gemma/mistral/gemma2/gemma3, windowed-Qwen2 -> attn.swa, per-model key isolation, atomic failed install, Gemma 3's two masks vs Mistral's one, alpha ramp, bit-identical alpha=0, Gemma 2 vs Gemma 3 fixture shape)Manual:./target/debug/a2d detect fixtures/configs/{gpt2,mistral-v0.1,gemma3,gpt-oss,mamba}- attn.swa supported, attn.sink/paradigm.ssm rejected exit=1Manual:./target/debug/a2d convert <tiny-model> --out <run> --data corpus.jsonl --seq-len 8 --max-steps 2 --anneal-steps 2 --per-device-batch-size 2 --device cpufor tiny random-weight GPT-2, Mistral and Gemma 3 (one per capability gate)Manual:./target/debug/a2d sample <run> -p 'w1 w2' --canvas-len 12 --num-steps 4 --device cpuon all three converted checkpoints✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.