Include/Coverage Redesign + VocabBoost Implementation Plan¶
For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Replace the flat-boost Include/Coverage mechanism with density-weighted boosting, add VocabBoost, add session-level coverage tracking, and fix 6 governor-wide gaps.
Architecture: Unified boost-with-coverage pattern — one weight function per constraint type, two modes (static LogitBoost or stateful coverage projection). Session-level coverage tracking via CoverageTracker on the session store, priors injected through GovernorContext. New VocabBoostConstraint parallels IncludeConstraint with binary membership weighting.
Tech Stack: Python (diffusion_governors engine, FastAPI dashboard), TypeScript/React (dashboard frontend), PyTest, Vitest
Spec: docs/superpowers/specs/2026-03-17-include-coverage-redesign.md
Chunk 1: Engine Core — Density-Weighted Include + Coverage Unification¶
Task 1: Add prior_coverage to GovernorContext¶
Files:
- Modify: packages/governors/src/diffusion_governors/core.py:12-22
- [ ] Step 1: Add
prior_coveragefield toGovernorContext
# In core.py, add to GovernorContext dataclass:
prior_coverage: dict[str, tuple[int, int]] | None = None # key → (content_count, target_count)
- [ ] Step 2: Run existing tests to verify no regressions
Run: uv run pytest packages/governors/tests/ -v
Expected: All existing tests pass (new field has default None)
- [ ] Step 3: Commit
git add packages/governors/src/diffusion_governors/core.py
git commit -m "feat: add prior_coverage field to GovernorContext"
Task 2: Make _parse_phono importable from constraints.py¶
Files:
- Modify: packages/governors/src/diffusion_governors/constraints.py:75-82
- [ ] Step 1: Rename
_parse_phonotoparse_phono(drop underscore)
In constraints.py, rename the function at line 75 from _parse_phono to parse_phono. Update all call sites within constraints.py (search for _parse_phono and replace with parse_phono).
Also rename _MSH_STAGES to MSH_STAGES and _word_msh_stage to word_msh_stage (these will be needed by _check_compliance in Task 10). Update all internal call sites.
- [ ] Step 2: Run existing tests
Run: uv run pytest packages/governors/tests/ -v
Expected: All pass
- [ ] Step 3: Commit
git add packages/governors/src/diffusion_governors/constraints.py
git commit -m "refactor: make parse_phono public for cross-module use"
Task 3: Write failing tests for density-weighted IncludeConstraint¶
Files:
- Modify: packages/governors/tests/test_include.py
- [ ] Step 1: Replace
TestIncludeConstrainttests with density-aware versions
Replace the entire TestIncludeConstraint class with these tests. The key difference: instead of flat +strength for any matching token, the boost is density * strength where density = count(target ∩ token) / len(token_phonemes).
class TestIncludeConstraint:
"""Tests for density-weighted IncludeConstraint."""
def test_compiles_to_boost_in_static_mode(self):
"""Without target_rate, produces a LogitBoost mechanism."""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
c = IncludeConstraint(phonemes={"k"})
gov = Governor.from_constraints(c, vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
assert len(gov.boosts) == 1
assert len(gov.gates) == 0
assert len(gov.projections) == 0
assert isinstance(gov.boosts[0], LogitBoost)
def test_density_weighting_single_phoneme(self):
"""Boost = (target_hits / total_phonemes) * strength.
Token 0 "cat" [k,æ,t]: density = 1/3, boost = 1/3 * 2.0 ≈ 0.667
Token 1 "rat" [ɹ,æ,t]: density = 0/3, boost = 0.0
"""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
c = IncludeConstraint(phonemes={"k"}, strength=2.0)
gov = Governor.from_constraints(c, vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, VOCAB_SIZE)
ctx = GovernorContext()
out = gov(logits, ctx)
# "cat" [k,æ,t] → density 1/3 * 2.0
assert out[0, 0, 0].item() == pytest.approx(2.0 / 3, abs=1e-5)
# "rat" [ɹ,æ,t] → no /k/ → 0.0
assert out[0, 0, 1].item() == pytest.approx(0.0)
# "the" — no phono → 0.0
assert out[0, 0, 3].item() == pytest.approx(0.0)
def test_density_weighting_multi_occurrence(self):
"""Token with target phoneme appearing twice gets higher density."""
from diffusion_governors.include import IncludeConstraint
# "kick" has /k/ twice: [k, ɪ, k] → density = 2/3
lookup = _make_lookup(**{
"5": TokenFeatures(
word="kick",
phono=PhonoFeatures(phonemes=["k", "ɪ", "k"]),
),
})
c = IncludeConstraint(phonemes={"k"}, strength=3.0)
gov = Governor.from_constraints(c, vocab_size=6, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, 6)
ctx = GovernorContext()
out = gov(logits, ctx)
# "kick" [k,ɪ,k] → density 2/3 * 3.0
assert out[0, 0, 5].item() == pytest.approx(2.0, abs=1e-5)
# "cat" [k,æ,t] → density 1/3 * 3.0
assert out[0, 0, 0].item() == pytest.approx(1.0, abs=1e-5)
def test_multi_target_phonemes(self):
"""Multiple targets: density = count(targets ∩ token) / len(token)."""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
# Targeting {k, t}: "cat" [k,æ,t] → 2 hits / 3 total = 0.667
c = IncludeConstraint(phonemes={"k", "t"}, strength=3.0)
gov = Governor.from_constraints(c, vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, VOCAB_SIZE)
ctx = GovernorContext()
out = gov(logits, ctx)
# "cat" [k,æ,t] → 2/3 * 3.0
assert out[0, 0, 0].item() == pytest.approx(2.0, abs=1e-5)
# "rat" [ɹ,æ,t] → 1/3 * 3.0 (just /t/)
assert out[0, 0, 1].item() == pytest.approx(1.0, abs=1e-5)
def test_no_matching_tokens_gives_zero_boost(self):
"""When no tokens match, all logits unchanged."""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
c = IncludeConstraint(phonemes={"ʒ"})
gov = Governor.from_constraints(c, vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, VOCAB_SIZE)
ctx = GovernorContext()
out = gov(logits, ctx)
assert torch.allclose(out, logits)
def test_mechanism_kind_static(self):
"""Static mode: mechanism_kind is 'boost'."""
from diffusion_governors.include import IncludeConstraint
c = IncludeConstraint(phonemes={"k"})
assert c.mechanism_kind == "boost"
def test_mechanism_kind_coverage(self):
"""Coverage mode: mechanism_kind is 'projection'."""
from diffusion_governors.include import IncludeConstraint
c = IncludeConstraint(phonemes={"k"}, target_rate=0.2)
assert c.mechanism_kind == "projection"
def test_default_strength(self):
"""Default strength is 2.0."""
from diffusion_governors.include import IncludeConstraint
c = IncludeConstraint(phonemes={"k"})
assert c.strength == 2.0
def test_uses_parse_phono(self):
"""Phono access uses parse_phono, not raw dict access."""
from diffusion_governors.include import IncludeConstraint
# Malformed phono dict that parse_phono would reject but raw dict.get would accept
lookup = {"0": {"word": "test", "phono": "not_a_dict", "norms": {}}}
c = IncludeConstraint(phonemes={"k"}, strength=2.0)
# Should not crash — parse_phono returns None for non-dict phono
gov = Governor.from_constraints(c, vocab_size=1, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, 1)
out = gov(logits, GovernorContext())
assert out[0, 0, 0].item() == pytest.approx(0.0)
def test_exported_from_package(self):
"""IncludeConstraint importable from top-level package."""
from diffusion_governors import IncludeConstraint # noqa: F401
- [ ] Step 2: Run tests to verify they fail
Run: uv run pytest packages/governors/tests/test_include.py::TestIncludeConstraint -v
Expected: FAIL — density weighting tests fail against the current flat-boost implementation
- [ ] Step 3: Commit failing tests
git add packages/governors/tests/test_include.py
git commit -m "test: add failing tests for density-weighted IncludeConstraint"
Task 4: Write failing tests for unified coverage mode¶
Files:
- Modify: packages/governors/tests/test_include.py
- [ ] Step 1: Replace
TestCoverageConstraintwith unified coverage tests
Replace the TestCoverageConstraint class. The key change: coverage is now a mode of IncludeConstraint (via target_rate parameter), not a separate class. Also tests prior_coverage on GovernorContext.
class TestIncludeCoverage:
"""Tests for IncludeConstraint in coverage mode (target_rate set)."""
def test_compiles_to_projection(self):
"""With target_rate, produces a projection mechanism."""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
c = IncludeConstraint(phonemes={"ɹ"}, target_rate=0.5)
gov = Governor.from_constraints(c, vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
assert len(gov.projections) == 1
assert len(gov.gates) == 0
assert len(gov.boosts) == 0
def test_boosts_when_below_target_with_density(self):
"""Below target → boost proportional to gap AND density."""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
c = IncludeConstraint(phonemes={"ɹ"}, target_rate=0.8, max_boost=5.0)
mechanism = c.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, VOCAB_SIZE)
# "sat" generated — no /ɹ/ → coverage = 0/1 = 0, gap = 0.8
ctx = GovernorContext(token_ids=torch.tensor([[2]]))
out = mechanism.apply(logits, ctx)
# "rat" [ɹ,æ,t] has density 1/3 for /ɹ/
# boost = density * max_boost * gap = (1/3) * 5.0 * 0.8
expected_rat = (1.0 / 3.0) * 5.0 * 0.8
assert out[0, 0, 1].item() == pytest.approx(expected_rat, abs=1e-4)
# "cat" — no /ɹ/ → 0
assert out[0, 0, 0].item() == pytest.approx(0.0)
def test_no_boost_at_target_rate(self):
"""At or above target → zero boost."""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
c = IncludeConstraint(phonemes={"ɹ"}, target_rate=0.5, max_boost=5.0)
mechanism = c.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, VOCAB_SIZE)
# 1/2 content tokens have /ɹ/ → coverage = 0.5 = target
ctx = GovernorContext(token_ids=torch.tensor([[1, 0]]))
out = mechanism.apply(logits, ctx)
assert torch.allclose(out, logits)
def test_prior_coverage_seeds_gap(self):
"""Prior coverage counts from session shift the gap computation."""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
c = IncludeConstraint(phonemes={"k"}, target_rate=0.5, max_boost=4.0)
mechanism = c.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, VOCAB_SIZE)
# Prior: 10 content, 5 target → rate = 0.5, at target
ctx = GovernorContext(
token_ids=torch.tensor([[2]]), # "sat" — 1 content, 0 target
prior_coverage={mechanism.coverage_key: (10, 5)},
)
out = mechanism.apply(logits, ctx)
# Total: 11 content, 5 target → rate = 5/11 ≈ 0.45 < 0.5 → small boost
expected_gap = 0.5 - (5 / 11)
assert out[0, 0, 0].item() > 0.0 # "cat" has /k/ → boosted
assert out[0, 0, 1].item() == pytest.approx(0.0) # "rat" no /k/
def test_prior_coverage_at_target_suppresses_boost(self):
"""If prior coverage already meets target, no boost even with zero current."""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
c = IncludeConstraint(phonemes={"k"}, target_rate=0.3, max_boost=4.0)
mechanism = c.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, VOCAB_SIZE)
# Prior: 10 content, 5 target → rate = 0.5, above 0.3 target
ctx = GovernorContext(
token_ids=torch.tensor([[2]]), # "sat"
prior_coverage={mechanism.coverage_key: (10, 5)},
)
out = mechanism.apply(logits, ctx)
# Total: 11 content, 5 target → 0.45 > 0.3 → no boost
assert torch.allclose(out, logits)
def test_count_tokens(self):
"""_CoverageMechanism.count_tokens returns content and target counts."""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
c = IncludeConstraint(phonemes={"k"}, target_rate=0.5)
mechanism = c.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
# Tokens: cat(0)=content+target, rat(1)=content, the(3)=not content
content, target = mechanism.count_tokens([0, 1, 3])
assert content == 2 # cat and rat have phonemes
assert target == 1 # only cat has /k/
def test_coverage_key_deterministic(self):
"""Same phonemes produce the same coverage key."""
from diffusion_governors.include import IncludeConstraint
c1 = IncludeConstraint(phonemes={"k", "t"}, target_rate=0.3)
c2 = IncludeConstraint(phonemes={"t", "k"}, target_rate=0.3)
lookup = _make_lookup()
m1 = c1.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
m2 = c2.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
assert m1.coverage_key == m2.coverage_key
def test_empty_generation_full_gap(self):
"""No tokens yet → full gap → full boost."""
from diffusion_governors.include import IncludeConstraint
lookup = _make_lookup()
c = IncludeConstraint(phonemes={"k"}, target_rate=0.5, max_boost=4.0)
mechanism = c.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, VOCAB_SIZE)
ctx = GovernorContext(token_ids=None)
out = mechanism.apply(logits, ctx)
# Full gap = target_rate = 0.5
# "cat" [k,æ,t] density 1/3 * 4.0 * 0.5
expected = (1.0 / 3.0) * 4.0 * 0.5
assert out[0, 0, 0].item() == pytest.approx(expected, abs=1e-4)
- [ ] Step 2: Run tests to verify they fail
Run: uv run pytest packages/governors/tests/test_include.py::TestIncludeCoverage -v
Expected: FAIL — IncludeConstraint doesn't accept target_rate yet
- [ ] Step 3: Commit failing tests
git add packages/governors/tests/test_include.py
git commit -m "test: add failing tests for unified Include coverage mode with priors"
Task 5: Implement density-weighted IncludeConstraint with unified coverage¶
Files:
- Rewrite: packages/governors/src/diffusion_governors/include.py
- [ ] Step 1: Rewrite
include.pywith density weighting and unified dual-mode
Replace the entire file:
"""Include constraint — density-weighted boost with optional coverage tracking.
IncludeConstraint(phonemes={"k"}) → static LogitBoost (density-weighted)
IncludeConstraint(phonemes={"k"}, target_rate=0.2) → stateful coverage projection
"""
from __future__ import annotations
from typing import Any
import torch
from diffusion_governors.constraints import Constraint, parse_phono
from diffusion_governors.core import GovernorContext, Mechanism
from diffusion_governors.lookups import Lookup
def _compute_density_scores(
phonemes: set[str], lookup: Lookup, vocab_size: int,
) -> tuple[dict[int, float], set[int], set[int]]:
"""Compute per-token density scores and identify content/target sets.
Returns:
scores: {token_id: density} for tokens with density > 0
content_ids: all token IDs with non-empty phoneme lists
target_ids: content tokens containing any target phoneme
"""
scores: dict[int, float] = {}
content_ids: set[int] = set()
target_ids: set[int] = set()
for tid_str, entry in lookup.items():
tid = int(tid_str)
if tid >= vocab_size:
continue
phono = parse_phono(entry)
if phono is None or not phono.phonemes:
continue
content_ids.add(tid)
token_phonemes = phono.phonemes
hits = sum(1 for p in token_phonemes if p in phonemes)
if hits > 0:
target_ids.add(tid)
scores[tid] = hits / len(token_phonemes)
return scores, content_ids, target_ids
class _CoverageMechanism:
"""Stateful projection: tracks phoneme coverage and applies density-weighted boost.
At each step, computes running coverage from prior session counts plus
current generation tokens. When below target, boosts target tokens
proportionally to gap and density.
"""
def __init__(
self,
weights: torch.Tensor,
target_ids: set[int],
content_ids: set[int],
target_rate: float,
max_boost: float,
coverage_key: str,
):
self.weights = weights
self.target_ids = target_ids
self.content_ids = content_ids
self.target_rate = target_rate
self.max_boost = max_boost
self.coverage_key = coverage_key
def apply(self, logits: torch.Tensor, ctx: GovernorContext) -> torch.Tensor:
gap = self._compute_gap(ctx)
if gap <= 0.0:
return logits
return logits + self.weights.to(logits.device) * (self.max_boost * gap)
def count_tokens(self, token_ids: list[int]) -> tuple[int, int]:
"""Count content and target tokens for post-generation tracker update."""
content = sum(1 for t in token_ids if t in self.content_ids)
target = sum(1 for t in token_ids if t in self.target_ids)
return content, target
def _compute_gap(self, ctx: GovernorContext) -> float:
"""Compute gap below target rate, incorporating session priors."""
prior_content, prior_target = 0, 0
if ctx.prior_coverage and self.coverage_key in ctx.prior_coverage:
prior_content, prior_target = ctx.prior_coverage[self.coverage_key]
current_content, current_target = self._count_current(ctx.token_ids)
total_content = prior_content + current_content
total_target = prior_target + current_target
if total_content == 0:
return self.target_rate
current_rate = total_target / total_content
return max(0.0, self.target_rate - current_rate)
def _count_current(self, token_ids: torch.Tensor | None) -> tuple[int, int]:
if token_ids is None:
return 0, 0
ids = token_ids.flatten().tolist()
content = sum(1 for t in ids if t in self.content_ids)
target = sum(1 for t in ids if t in self.target_ids)
return content, target
class IncludeConstraint(Constraint):
"""Density-weighted boost for tokens containing target phonemes.
Boost magnitude is proportional to phoneme density:
weight(token) = count(target ∩ token_phonemes) / len(token_phonemes)
Two modes:
Static: boost = weight * strength (mechanism_kind = "boost")
Coverage: boost = weight * max_boost * gap (mechanism_kind = "projection")
Coverage mode is activated by providing target_rate. Session-level coverage
tracking is supported via GovernorContext.prior_coverage.
"""
def __init__(
self,
phonemes: set[str],
strength: float = 2.0,
target_rate: float | None = None,
max_boost: float = 3.0,
):
self.phonemes = phonemes
self.strength = strength
self.target_rate = target_rate
self.max_boost = max_boost
@property
def mechanism_kind(self) -> str:
return "projection" if self.target_rate is not None else "boost"
def build(self, **kwargs: Any) -> Mechanism:
from diffusion_governors.boosts import LogitBoost
vocab_size: int = kwargs["vocab_size"]
lookup: Lookup = kwargs["lookup"]
scores, content_ids, target_ids = _compute_density_scores(
self.phonemes, lookup, vocab_size,
)
# Build weight tensor from density scores
weights = torch.zeros(vocab_size)
for tid, density in scores.items():
weights[tid] = density
if self.target_rate is not None:
# Coverage mode — stateful projection
coverage_key = f"include:{','.join(sorted(self.phonemes))}"
return _CoverageMechanism(
weights=weights,
target_ids=target_ids,
content_ids=content_ids,
target_rate=self.target_rate,
max_boost=self.max_boost,
coverage_key=coverage_key,
)
else:
# Static mode — precomputed LogitBoost
return LogitBoost(weights, scale=self.strength)
- [ ] Step 2: Run the Include tests
Run: uv run pytest packages/governors/tests/test_include.py -v
Expected: All TestIncludeConstraint and TestIncludeCoverage tests pass
- [ ] Step 3: Run all governor tests for regressions
Run: uv run pytest packages/governors/tests/ -v
Expected: All pass
- [ ] Step 4: Commit
git add packages/governors/src/diffusion_governors/include.py
git commit -m "feat: density-weighted IncludeConstraint with unified coverage mode"
Task 6: Remove Density, update exports¶
Files:
- Modify: packages/governors/src/diffusion_governors/constraints.py:235-305 (delete Density class)
- Modify: packages/governors/src/diffusion_governors/__init__.py (remove Density, CoverageConstraint exports)
- [ ] Step 1: Delete
Densityclass fromconstraints.py
Remove the entire Density class (lines 235-305). Also remove its import of CDDConstraint and CDDProjection if those imports become unused (check — they're likely still used by Bound).
- [ ] Step 2: Update
__init__.pyexports
Remove Density and CoverageConstraint from imports and __all__. Keep IncludeConstraint (already exported).
- [ ] Step 3: Update the
Governordocstring example incore.py
In core.py line 50, replace Density("θ", min=0.30) with a valid current constraint example (e.g., IncludeConstraint(phonemes={"θ"}, target_rate=0.3)).
- [ ] Step 4: Run all governor tests
Run: uv run pytest packages/governors/tests/ -v
Expected: All pass
- [ ] Step 5: Commit
git add packages/governors/src/diffusion_governors/constraints.py \
packages/governors/src/diffusion_governors/__init__.py \
packages/governors/src/diffusion_governors/core.py
git commit -m "refactor: remove deprecated Density, update exports for unified Include"
Task 7: Governor.get_coverage_mechanisms()¶
Files:
- Modify: packages/governors/src/diffusion_governors/core.py
- [ ] Step 1: Add
get_coverage_mechanismsmethod toGovernor
def get_coverage_mechanisms(self) -> dict[str, Any]:
"""Return coverage mechanisms keyed by coverage_key.
Used by the route handler post-generation to call count_tokens().
"""
result = {}
for proj in self.projections:
if hasattr(proj, "coverage_key") and hasattr(proj, "count_tokens"):
result[proj.coverage_key] = proj
return result
- [ ] Step 2: Run all governor tests
Run: uv run pytest packages/governors/tests/ -v
Expected: All pass
- [ ] Step 3: Commit
git add packages/governors/src/diffusion_governors/core.py
git commit -m "feat: add Governor.get_coverage_mechanisms() for post-generation counting"
Chunk 2: VocabBoost Engine + Cleanup Fixes¶
Task 8: Write failing tests for VocabBoostConstraint¶
Files:
- Create: packages/governors/tests/test_vocab_boost.py
- [ ] Step 1: Write VocabBoost tests
"""Tests for VocabBoostConstraint."""
from __future__ import annotations
import torch
import pytest
from diffusion_governors.core import Governor, GovernorContext
from diffusion_governors.boosts import LogitBoost
from diffusion_governors.lookups import PhonoFeatures, TokenFeatures
def _make_lookup(**overrides) -> dict[str, dict]:
"""Lookup with vocab memberships for testing."""
entries = {
"0": TokenFeatures(
word="cat",
phono=PhonoFeatures(phonemes=["k", "æ", "t"]),
vocab_memberships={"ogden_basic", "dolch"},
),
"1": TokenFeatures(
word="rat",
phono=PhonoFeatures(phonemes=["ɹ", "æ", "t"]),
vocab_memberships={"ogden_basic"},
),
"2": TokenFeatures(
word="sat",
phono=PhonoFeatures(phonemes=["s", "æ", "t"]),
vocab_memberships=set(),
),
"3": TokenFeatures(
word="the",
vocab_memberships={"dolch", "ogden_basic"},
),
"4": TokenFeatures(
word="bat",
phono=PhonoFeatures(phonemes=["b", "æ", "t"]),
vocab_memberships=set(),
),
}
entries.update(overrides)
return {k: v.to_dict() for k, v in entries.items()}
VOCAB_SIZE = 5
class TestVocabBoostStatic:
"""Tests for VocabBoostConstraint in static mode."""
def test_compiles_to_boost(self):
from diffusion_governors.include import VocabBoostConstraint
lookup = _make_lookup()
c = VocabBoostConstraint(lists={"ogden_basic"})
gov = Governor.from_constraints(c, vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
assert len(gov.boosts) == 1
assert isinstance(gov.boosts[0], LogitBoost)
def test_boosts_list_members(self):
from diffusion_governors.include import VocabBoostConstraint
lookup = _make_lookup()
c = VocabBoostConstraint(lists={"ogden_basic"}, strength=2.0)
gov = Governor.from_constraints(c, vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, VOCAB_SIZE)
out = gov(logits, GovernorContext())
# cat(0)=ogden, rat(1)=ogden, the(3)=ogden → boosted
assert out[0, 0, 0].item() == pytest.approx(2.0)
assert out[0, 0, 1].item() == pytest.approx(2.0)
assert out[0, 0, 3].item() == pytest.approx(2.0)
# sat(2), bat(4) not in ogden → 0
assert out[0, 0, 2].item() == pytest.approx(0.0)
assert out[0, 0, 4].item() == pytest.approx(0.0)
def test_mechanism_kind_static(self):
from diffusion_governors.include import VocabBoostConstraint
c = VocabBoostConstraint(lists={"ogden_basic"})
assert c.mechanism_kind == "boost"
def test_mechanism_kind_coverage(self):
from diffusion_governors.include import VocabBoostConstraint
c = VocabBoostConstraint(lists={"ogden_basic"}, target_rate=0.6)
assert c.mechanism_kind == "projection"
def test_requires_lists_or_words(self):
from diffusion_governors.include import VocabBoostConstraint
with pytest.raises(ValueError):
VocabBoostConstraint()
def test_words_require_tokenizer(self):
from diffusion_governors.include import VocabBoostConstraint
lookup = _make_lookup()
c = VocabBoostConstraint(words={"cat", "bat"})
with pytest.raises(ValueError, match="tokenizer"):
c.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
class TestVocabBoostCoverage:
"""Tests for VocabBoostConstraint in coverage mode."""
def test_boosts_when_below_target(self):
from diffusion_governors.include import VocabBoostConstraint
lookup = _make_lookup()
c = VocabBoostConstraint(lists={"dolch"}, target_rate=0.8, max_boost=4.0)
mechanism = c.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
logits = torch.zeros(1, 1, VOCAB_SIZE)
# Token 2 "sat" not in dolch → coverage = 0/1 = 0
ctx = GovernorContext(token_ids=torch.tensor([[2]]))
out = mechanism.apply(logits, ctx)
# cat(0) in dolch → boosted (weight=1.0 * max_boost * gap)
assert out[0, 0, 0].item() > 0.0
# sat(2) not in dolch → not boosted
assert out[0, 0, 2].item() == pytest.approx(0.0)
def test_coverage_key_deterministic(self):
from diffusion_governors.include import VocabBoostConstraint
c1 = VocabBoostConstraint(lists={"dolch", "ogden_basic"}, target_rate=0.5)
c2 = VocabBoostConstraint(lists={"ogden_basic", "dolch"}, target_rate=0.5)
lookup = _make_lookup()
m1 = c1.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
m2 = c2.build(vocab_size=VOCAB_SIZE, device="cpu", lookup=lookup)
assert m1.coverage_key == m2.coverage_key
def test_exported_from_package(self):
from diffusion_governors import VocabBoostConstraint # noqa: F401
- [ ] Step 2: Run tests — verify they fail
Run: uv run pytest packages/governors/tests/test_vocab_boost.py -v
Expected: FAIL — VocabBoostConstraint doesn't exist yet
- [ ] Step 3: Commit failing tests
git add packages/governors/tests/test_vocab_boost.py
git commit -m "test: add failing tests for VocabBoostConstraint"
Task 9: Implement VocabBoostConstraint¶
Files:
- Modify: packages/governors/src/diffusion_governors/include.py
- Modify: packages/governors/src/diffusion_governors/__init__.py
- [ ] Step 1: Add
VocabBoostConstrainttoinclude.py
Append after IncludeConstraint:
class VocabBoostConstraint(Constraint):
"""Soft vocabulary targeting — boost tokens from target word lists.
Binary membership weighting: tokens in the target vocab get weight 1.0,
others get 0.0. Same dual-mode pattern as IncludeConstraint.
Args:
lists: Named vocab sets (matched against vocab_memberships in lookup).
words: Explicit word strings (single-token resolution via tokenizer).
strength: Static mode boost. Default 2.0.
target_rate: Coverage mode target (0.0-1.0). Activates stateful tracking.
max_boost: Maximum boost in coverage mode. Default 3.0.
"""
def __init__(
self,
lists: set[str] | None = None,
words: set[str] | None = None,
strength: float = 2.0,
target_rate: float | None = None,
max_boost: float = 3.0,
include_punctuation: bool = True,
):
if not lists and not words:
raise ValueError("VocabBoostConstraint requires at least one of 'lists' or 'words'")
self.lists = lists or set()
self.words = words or set()
self.strength = strength
self.target_rate = target_rate
self.max_boost = max_boost
self.include_punctuation = include_punctuation
@property
def mechanism_kind(self) -> str:
return "projection" if self.target_rate is not None else "boost"
def build(self, **kwargs) -> Mechanism:
from diffusion_governors.boosts import LogitBoost
vocab_size: int = kwargs["vocab_size"]
lookup: Lookup = kwargs["lookup"]
tokenizer = kwargs.get("tokenizer")
if self.words and tokenizer is None:
raise ValueError("VocabBoostConstraint with 'words' requires tokenizer in build kwargs")
# Build target token set
target_ids: set[int] = set()
content_ids: set[int] = set()
# From lists: check vocab_memberships
for tid_str, entry in lookup.items():
tid = int(tid_str)
if tid >= vocab_size:
continue
content_ids.add(tid)
if self.lists:
memberships = set(entry.get("vocab_memberships", []))
if memberships & self.lists:
target_ids.add(tid)
# From words: single-token resolution
if self.words and tokenizer is not None:
for word in self.words:
ids = tokenizer.encode(word, add_special_tokens=False)
if len(ids) == 1 and ids[0] < vocab_size:
target_ids.add(ids[0])
# Build weight tensor (binary: 1.0 for target, 0.0 for others)
weights = torch.zeros(vocab_size)
for tid in target_ids:
weights[tid] = 1.0
if self.target_rate is not None:
coverage_key_parts = [
f"vocab_boost",
",".join(sorted(self.lists)) if self.lists else "",
",".join(sorted(self.words)) if self.words else "",
]
coverage_key = ":".join(coverage_key_parts)
return _CoverageMechanism(
weights=weights,
target_ids=target_ids,
content_ids=content_ids,
target_rate=self.target_rate,
max_boost=self.max_boost,
coverage_key=coverage_key,
)
else:
return LogitBoost(weights, scale=self.strength)
- [ ] Step 2: Add
VocabBoostConstraintto__init__.pyexports
Add to imports and __all__.
- [ ] Step 3: Run VocabBoost tests
Run: uv run pytest packages/governors/tests/test_vocab_boost.py -v
Expected: All pass
- [ ] Step 4: Run all governor tests
Run: uv run pytest packages/governors/tests/ -v
Expected: All pass
- [ ] Step 5: Commit
git add packages/governors/src/diffusion_governors/include.py \
packages/governors/src/diffusion_governors/__init__.py
git commit -m "feat: add VocabBoostConstraint with binary membership weighting"
Task 10: Cleanup fixes (MSH compliance, MaxOpp 422, Density docstring)¶
Files:
- Modify: packages/dashboard/server/model.py:33-73 (add MSH to _check_compliance)
- Modify: packages/dashboard/server/governor.py:57-92 (catch MaxOpp ValueError)
- [ ] Step 1: Add MSH to
_check_complianceinmodel.py
After the ComplexityConstraint check block (after line 65), add:
elif isinstance(c, MSHConstraint):
if phono:
from diffusion_governors.constraints import MSH_STAGES
for phoneme in phono.get("phonemes", []):
stage = MSH_STAGES.get(phoneme, 5)
if stage > c.max_stage:
violations.append(f"/{phoneme}/ is MSH stage {stage} > {c.max_stage}")
break
Add MSHConstraint to the imports at the top of model.py.
- [ ] Step 2: Catch MaxOpp ValueError in
governor.py
Wrap the MaxOppositionBoost conversion in _to_dg_constraint:
elif isinstance(c, MaxOppositionBoostConstraint):
try:
return MaxOppositionBoost(target=c.target, contrast=c.contrast, boost=c.strength)
except ValueError as e:
from fastapi import HTTPException
raise HTTPException(status_code=422, detail=str(e))
- [ ] Step 3: Run dashboard server tests
Run: uv run pytest packages/dashboard/server/tests/ -v
Expected: All pass
- [ ] Step 4: Commit
git add packages/dashboard/server/model.py packages/dashboard/server/governor.py
git commit -m "fix: add MSH to compliance check, MaxOpp validation returns 422"
Chunk 3: Dashboard Server — Schema, Governor Bridge, Session Coverage¶
Task 11: Update server schemas¶
Files:
- Modify: packages/dashboard/server/schemas.py
- [ ] Step 1: Modify
IncludeConstraintschema — addtarget_rateandmax_boost
Replace the current IncludeConstraint (lines 38-41) with:
class IncludeConstraint(BaseModel):
type: Literal["include"] = "include"
phonemes: list[str]
strength: float = 2.0
target_rate: float | None = None
max_boost: float = 3.0
@field_validator("target_rate")
@classmethod
def validate_target_rate(cls, v):
if v is not None and not (0.0 <= v <= 1.0):
raise ValueError("target_rate must be between 0.0 and 1.0")
return v
@model_validator(mode="after")
def check_mode_exclusivity(self):
if self.target_rate is not None and self.strength != 2.0:
raise ValueError("Cannot set both strength (non-default) and target_rate")
return self
Add field_validator, model_validator to imports from pydantic.
- [ ] Step 2: Remove
CoverageConstraintschema (lines 44-48)
Delete the class entirely.
- [ ] Step 3: Add
VocabBoostConstraintschema
class VocabBoostConstraint(BaseModel):
type: Literal["vocab_boost"] = "vocab_boost"
lists: list[str] | None = None
words: list[str] | None = None
strength: float = 2.0
target_rate: float | None = None
max_boost: float = 3.0
include_punctuation: bool = True
@field_validator("target_rate")
@classmethod
def validate_target_rate(cls, v):
if v is not None and not (0.0 <= v <= 1.0):
raise ValueError("target_rate must be between 0.0 and 1.0")
return v
- [ ] Step 4: Update
Constraintunion (lines 91-102)
Remove CoverageConstraint, add VocabBoostConstraint.
- [ ] Step 5: Run schema tests
Run: uv run pytest packages/dashboard/server/tests/test_schemas.py -v
Expected: Pass (may need test updates if tests reference CoverageConstraint)
- [ ] Step 6: Commit
git add packages/dashboard/server/schemas.py
git commit -m "feat: unified Include schema, add VocabBoost, remove CoverageConstraint"
Task 12: Update governor bridge (governor.py)¶
Files:
- Modify: packages/dashboard/server/governor.py
- [ ] Step 1: Update imports
Replace:
from diffusion_governors import (
...
IncludeConstraint as DGInclude,
CoverageConstraint as DGCoverage,
...
)
from server.schemas import (
...
IncludeConstraint, CoverageConstraint as SchemaCoverage,
...
)
With:
from diffusion_governors import (
...
IncludeConstraint as DGInclude,
VocabBoostConstraint as DGVocabBoost,
...
)
from server.schemas import (
...
IncludeConstraint, VocabBoostConstraint,
...
)
- [ ] Step 2: Update
_to_dg_constraintfor unified Include
Replace the Include + Coverage cases:
elif isinstance(c, IncludeConstraint):
kwargs = dict(phonemes=set(c.phonemes), strength=c.strength)
if c.target_rate is not None:
kwargs["target_rate"] = c.target_rate
kwargs["max_boost"] = c.max_boost
return DGInclude(**kwargs)
elif isinstance(c, VocabBoostConstraint):
kwargs = {}
if c.lists is not None:
kwargs["lists"] = set(c.lists)
if c.words is not None:
kwargs["words"] = set(c.words)
kwargs["strength"] = c.strength
if c.target_rate is not None:
kwargs["target_rate"] = c.target_rate
kwargs["max_boost"] = c.max_boost
return DGVocabBoost(**kwargs)
Remove the old SchemaCoverage case.
- [ ] Step 3: Update
HFGovernorProcessor.reset()to acceptprior_coverage
def reset(self, total_steps: int | None = None,
prior_coverage: dict[str, tuple[int, int]] | None = None) -> None:
"""Reset step counter for a new generation, optionally inject session priors."""
self._step = 0
self._prior_coverage = prior_coverage
if total_steps is not None:
self.total_steps = total_steps
Update __init__ to initialize self._prior_coverage = None.
Update __call__ to pass prior_coverage into GovernorContext:
ctx = GovernorContext(
step=self._step,
total_steps=self.total_steps,
token_ids=input_ids,
device=scores.device,
prior_coverage=self._prior_coverage,
)
- [ ] Step 4: Add
get_coverage_counters()toHFGovernorProcessor
def get_coverage_counters(self) -> dict:
"""Delegate to Governor.get_coverage_mechanisms()."""
return self.governor.get_coverage_mechanisms()
- [ ] Step 4b: Add
coverage_key_for()utility function
Add a module-level function in governor.py that computes the same deterministic key from schema constraints. This is needed by the route handler for tracker lifecycle (dropping trackers when constraints are removed):
def coverage_key_for(c) -> str | None:
"""Compute coverage key from a schema constraint. Returns None if not a coverage constraint."""
if isinstance(c, IncludeConstraint) and c.target_rate is not None:
return f"include:{','.join(sorted(c.phonemes))}"
elif isinstance(c, VocabBoostConstraint) and c.target_rate is not None:
lists_part = ",".join(sorted(c.lists)) if c.lists else ""
words_part = ",".join(sorted(c.words)) if c.words else ""
return f"vocab_boost:{lists_part}:{words_part}"
return None
- [ ] Step 5: Update
test_governor.pyfor CoverageConstraint removal
In packages/dashboard/server/tests/test_governor.py:
Replace the import (line 7): remove CoverageConstraint, it no longer exists.
Replace test_build_governor_coverage (lines 158-162) with:
def test_build_governor_include_coverage(lookup):
"""Include with target_rate produces a projection."""
constraints = [IncludeConstraint(type="include", phonemes=["s"], target_rate=0.3)]
gov = build_governor(constraints, lookup, VOCAB_SIZE)
assert gov is not None
assert len(gov.projections) == 1
- [ ] Step 6: Run server tests
Run: uv run pytest packages/dashboard/server/tests/ -v
Expected: Pass (update any tests that referenced CoverageConstraint)
- [ ] Step 6: Commit
git add packages/dashboard/server/governor.py
git commit -m "feat: update governor bridge for unified Include, VocabBoost, prior_coverage"
Task 13: Add CoverageTracker and wire into generation route¶
Files:
- Modify: packages/dashboard/server/sessions.py
- Modify: packages/dashboard/server/routes/generate.py
- [ ] Step 1: Add
CoverageTrackertosessions.py
Add after imports:
@dataclass
class CoverageTracker:
"""Tracks phoneme/vocab coverage across session turns."""
content_count: int = 0
target_count: int = 0
Add a coverage tracking dict to SessionStore:
def __init__(self, persistence_path=None):
self._sessions: dict[str, Session] = {}
self._coverage: dict[str, dict[str, CoverageTracker]] = {} # session_id → {key → tracker}
...
def get_coverage(self, session_id: str) -> dict[str, CoverageTracker]:
return self._coverage.get(session_id, {})
def update_coverage(self, session_id: str, key: str, content: int, target: int):
if session_id not in self._coverage:
self._coverage[session_id] = {}
if key not in self._coverage[session_id]:
self._coverage[session_id][key] = CoverageTracker()
tracker = self._coverage[session_id][key]
tracker.content_count += content
tracker.target_count += target
def reset_coverage(self, session_id: str):
"""Drop all coverage trackers for a session."""
self._coverage.pop(session_id, None)
Add from dataclasses import dataclass to imports.
- [ ] Step 2: Wire coverage into
/generateroute
In routes/generate.py, before generation:
# Build prior coverage from session trackers
trackers = session_store.get_coverage(req.session_id)
prior_coverage = {
key: (t.content_count, t.target_count) for key, t in trackers.items()
} if trackers else None
processor = governor_cache.get_processor(
constraints, lookup, vocab_size, tokenizer=model.get_tokenizer(),
)
# Reset processor with priors before generation
if processor is not None:
for p in processor:
if hasattr(p, "reset"):
p.reset(prior_coverage=prior_coverage)
After generation, update trackers:
# Update session coverage trackers
if processor is not None:
for p in processor:
if hasattr(p, "get_coverage_counters"):
for key, mechanism in p.get_coverage_counters().items():
content, target = mechanism.count_tokens(gen_ids)
session_store.update_coverage(req.session_id, key, content, target)
- [ ] Step 2b: Add reset() to
/generate-singleroute
The /generate-single endpoint is sessionless, so prior_coverage=None, but the step counter still needs resetting (the GovernorCache reuses processor instances):
# In generate_single(), before generation:
if processor is not None:
for p in processor:
if hasattr(p, "reset"):
p.reset(prior_coverage=None)
- [ ] Step 3: Run server tests
Run: uv run pytest packages/dashboard/server/tests/ -v
Expected: All pass
- [ ] Step 4: Commit
git add packages/dashboard/server/sessions.py \
packages/dashboard/server/routes/generate.py
git commit -m "feat: session-level coverage tracking with CoverageTracker"
Chunk 4: Frontend — Types, Parser, Compiler, ConstraintBar¶
Task 14: Update frontend types¶
Files:
- Modify: packages/dashboard/frontend/src/types.ts
- [ ] Step 1: Remove
CoverageConstrainttype, updateIncludeConstraint
Replace the IncludeConstraint and CoverageConstraint interfaces (lines 52-62) with:
export interface IncludeConstraint {
type: "include";
phonemes: string[];
strength: number;
target_rate?: number;
max_boost?: number;
}
Delete CoverageConstraint interface.
- [ ] Step 2: Add
VocabBoostConstraintinterface
export interface VocabBoostConstraint {
type: "vocab_boost";
lists?: string[];
words?: string[];
strength: number;
target_rate?: number;
max_boost?: number;
}
- [ ] Step 3: Update
Constraintunion andConstraintType
Remove "coverage" from ConstraintType, add "vocab_boost". Update the Constraint union to include VocabBoostConstraint and remove CoverageConstraint.
- [ ] Step 4: Update
StoreEntryunion
Replace the "include" and "coverage" variants:
| { type: "include"; phoneme: string; strength: number; targetRate?: number }
Add vocab-boost:
| { type: "vocab_boost"; lists?: string[]; words?: string[]; targetRate?: number }
Remove the "coverage" variant.
- [ ] Step 5: Commit
git add packages/dashboard/frontend/src/types.ts
git commit -m "feat: update frontend types — unified Include, add VocabBoost, remove Coverage"
Task 15: Update parser¶
Files:
- Modify: packages/dashboard/frontend/src/commands/parser.ts
- Modify: packages/dashboard/frontend/src/commands/registry.ts
- [ ] Step 1: Update
parseIncludeto emit unified entries
Replace the current parseInclude (lines 111-164). The key change: instead of emitting separate "include" and "coverage" entries, emit "include" entries with optional targetRate.
The changes are minimal — keep the existing structure, just change the entry types:
- Replace
type: "coverage" as constwithtype: "include" as constin the coverage-mode branch (line 142) - Add
strength: 2.0to coverage-mode entries - Keep
targetRateon the entry (renamed from a separate type to an optional field) - Remove the separate coverage branch — both paths emit
type: "include"entries
The existing parseInclude function (lines 111-164) already handles percentage detection correctly. The only change is replacing lines 139-151 (coverage branch):
if (targetRate !== null) {
// Coverage mode — same entry type, with targetRate
const entries: StoreEntry[] = phonemes.map((p) => ({
type: "include" as const,
phoneme: p,
strength: 2.0,
targetRate,
}));
return {
type: "add",
entries,
confirmation: `Include ${formatPhonemeList(phonemes)} ~${targetRate}% (approximate)`,
};
}
The bare-include branch (lines 153-163) stays unchanged.
- [ ] Step 2: Add
parseVocabBoostfunction
// Known vocab list names (from vocab_memberships in the lookup).
// Used by parseVocabBoost to distinguish list names from ad-hoc words.
const KNOWN_VOCAB_LISTS = new Set([
"ogden_basic", "ogden_international", "ogden_all",
"dolch", "fry_1000", "swadesh_207",
"gsl_1000", "gsl_2000", "gsl_all",
"avl_all", "roget_1000",
]);
function parseVocabBoost(args: string[]): ParseResult {
if (args.length === 0) {
return { type: "error", message: "Usage: /vocab-boost <list|word>... [N%] — type /help vocab-boost for syntax" };
}
// Check for percentage suffix
let targetRate: number | undefined;
const lastArg = args[args.length - 1];
const pctMatch = lastArg.match(/^(\d+(?:\.\d+)?)%$/);
if (pctMatch) {
targetRate = parseFloat(pctMatch[1]);
args = args.slice(0, -1);
}
if (args.length === 0) {
return { type: "error", message: "No lists or words specified" };
}
// Distinguish list names from words: known list names or underscored args → lists
const lists: string[] = [];
const words: string[] = [];
for (const arg of args) {
if (KNOWN_VOCAB_LISTS.has(arg.toLowerCase()) || arg.includes("_")) {
lists.push(arg.toLowerCase());
} else {
words.push(arg.toLowerCase());
}
}
const entry: StoreEntry = {
type: "vocab_boost" as const,
...(lists.length > 0 ? { lists } : {}),
...(words.length > 0 ? { words } : {}),
...(targetRate !== undefined ? { targetRate } : {}),
};
const label = [...lists, ...words].join(", ");
const mode = targetRate !== undefined ? ` ~${targetRate}%` : "";
return {
type: "add",
entries: [entry],
confirmation: `Vocab boost: ${label}${mode}`,
};
}
- [ ] Step 3: Add
"vocab-boost"to command dispatch inparseCommand
In the switch statement, add:
case "vocab-boost":
return parseVocabBoost(args);
- [ ] Step 3b: Add vocab-boost to
parseRemove
In the parseRemove switch statement (around line 361), add:
case "vocab-boost":
return { type: "remove", targetType: "vocab_boost", confirmation: "Removed Vocab boost" };
Also: the existing /remove include case (lines 396-411) currently has a comment about removing "coverage" entries too. Remove that comment — after unification, /remove include removes all Include entries (with or without targetRate). The matchFields logic already handles this correctly since it matches on { phoneme: p } only.
- [ ] Step 4: Add
"vocab-boost"toVERBSinregistry.ts
Add to the VERBS tuple and add a help text entry.
- [ ] Step 5: Expand
NORM_COMMANDSinregistry.ts
Add new norm entries to the NORM_COMMANDS array:
// Psycholinguistic norms
{ verb: "dominance", normKey: "dominance", defaultDirection: "min", description: "Dominance rating" },
{ verb: "socialness", normKey: "socialness", defaultDirection: "min", description: "Socialness rating" },
{ verb: "boi", normKey: "boi", defaultDirection: "min", description: "Body-object interaction" },
{ verb: "iconicity", normKey: "iconicity", defaultDirection: "min", description: "Iconicity rating" },
{ verb: "semantic-diversity", normKey: "semantic_diversity", defaultDirection: "max", description: "Semantic diversity" },
{ verb: "contextual-diversity", normKey: "contextual_diversity", defaultDirection: "min", description: "Contextual diversity" },
{ verb: "lexical-decision-rt", normKey: "lexical_decision_rt", defaultDirection: "max", description: "Lexical decision RT (ms)" },
// Sensorimotor dimensions (Lancaster norms)
{ verb: "auditory", normKey: "auditory", defaultDirection: "min", description: "Auditory strength" },
{ verb: "gustatory", normKey: "gustatory", defaultDirection: "min", description: "Gustatory strength" },
{ verb: "haptic", normKey: "haptic", defaultDirection: "min", description: "Haptic strength" },
{ verb: "interoceptive", normKey: "interoceptive", defaultDirection: "min", description: "Interoceptive strength" },
{ verb: "olfactory", normKey: "olfactory", defaultDirection: "min", description: "Olfactory strength" },
{ verb: "visual", normKey: "visual", defaultDirection: "min", description: "Visual strength" },
{ verb: "foot-leg", normKey: "foot_leg", defaultDirection: "min", description: "Foot/leg action strength" },
{ verb: "hand-arm", normKey: "hand_arm", defaultDirection: "min", description: "Hand/arm action strength" },
{ verb: "head", normKey: "head", defaultDirection: "min", description: "Head action strength" },
{ verb: "mouth", normKey: "mouth", defaultDirection: "min", description: "Mouth action strength" },
{ verb: "torso", normKey: "torso", defaultDirection: "min", description: "Torso action strength" },
- [ ] Step 6: Run parser tests
Run: cd packages/dashboard/frontend && npx vitest run
Expected: Some tests may fail due to "coverage" entry type removal — update those next
- [ ] Step 7: Commit
git add packages/dashboard/frontend/src/commands/parser.ts \
packages/dashboard/frontend/src/commands/registry.ts
git commit -m "feat: update parser — unified Include, add vocab-boost, expand norms"
Task 16: Update compiler and ConstraintBar¶
Files:
- Modify: packages/dashboard/frontend/src/commands/compiler.ts
- Modify: packages/dashboard/frontend/src/components/ConstraintBar/index.tsx
- Modify: packages/dashboard/frontend/src/store/constraintStore.ts (if needed)
- [ ] Step 1: Update
compileConstraintsincompiler.ts
Replace the Include and Coverage compilation sections (lines 46-59). Key changes:
- Remove the separate "coverage" case
- "include" entries with targetRate emit target_rate: entry.targetRate / 100 (percentage to rate conversion)
- Add "vocab_boost" compilation
// Include: group by phoneme, each entry becomes one constraint
const includes = entries.filter((e) => e.type === "include");
for (const inc of includes) {
const c: any = { type: "include", phonemes: [inc.phoneme], strength: inc.strength };
if (inc.targetRate !== undefined) {
c.target_rate = inc.targetRate / 100;
c.max_boost = 3.0;
}
result.push(c);
}
// VocabBoost
const vocabBoosts = entries.filter((e) => e.type === "vocab_boost");
for (const vb of vocabBoosts) {
const c: any = { type: "vocab_boost" };
if (vb.lists) c.lists = vb.lists;
if (vb.words) c.words = vb.words;
if (vb.targetRate !== undefined) {
c.target_rate = vb.targetRate / 100;
c.max_boost = 3.0;
} else {
c.strength = 2.0;
}
result.push(c);
}
- [ ] Step 2: Update
chipCategoryandchipLabelin ConstraintBar
Remove all "coverage" cases from chipLabel (line 20-21), chipCategory (line 53), and matchFields (line 76-77). TypeScript will error on unreachable cases once the StoreEntry union drops "coverage".
Update the "include" case in chipLabel to show targetRate when present:
case "include":
return entry.targetRate ? `/${entry.phoneme}/ ~${entry.targetRate}%` : `/${entry.phoneme}/`;
Add "vocab_boost" handling to chipCategory:
case "vocab_boost":
return "vocab";
Add to chipLabel:
case "vocab_boost": {
const items = entry.words?.join(", ") || entry.lists?.join(", ") || "";
return entry.targetRate ? `${items} ~${entry.targetRate}%` : items;
}
Add to matchFields:
case "vocab_boost":
return {}; // Remove all vocab-boost entries at once
- [ ] Step 3: Update
parseRemoveto handlevocab-boost
Add a case for "vocab-boost" in the remove parser that removes entries with type: "vocab_boost".
- [ ] Step 4: Run frontend tests
Run: cd packages/dashboard/frontend && npx vitest run
Expected: All pass (update any tests that reference "coverage" entry type)
- [ ] Step 5: Commit
git add packages/dashboard/frontend/src/commands/compiler.ts \
packages/dashboard/frontend/src/components/ConstraintBar/index.tsx
git commit -m "feat: update compiler and ConstraintBar for unified Include + VocabBoost"
Task 17: Update frontend tests¶
Files:
- Modify: packages/dashboard/frontend/src/commands/__tests__/parser.test.ts
- Modify: packages/dashboard/frontend/src/commands/__tests__/compiler.test.ts
- [ ] Step 1: Update parser tests
Replace any tests that assert type: "coverage" entries with type: "include" entries that have targetRate. Add tests for /vocab-boost.
- [ ] Step 2: Update compiler tests
Replace tests for coverage compilation. Add tests for VocabBoost compilation and percentage-to-rate conversion.
- [ ] Step 3: Run all frontend tests
Run: cd packages/dashboard/frontend && npx vitest run
Expected: All pass
- [ ] Step 4: Commit
git add packages/dashboard/frontend/src/commands/__tests__/
git commit -m "test: update parser and compiler tests for unified Include + VocabBoost"
Chunk 5: Integration + Final Verification¶
Task 18: Integration smoke test¶
- [ ] Step 1: Run all Python tests
Run: uv run pytest packages/governors/tests/ packages/dashboard/server/tests/ -v
Expected: All pass
- [ ] Step 2: Run all frontend tests
Run: cd packages/dashboard/frontend && npx vitest run
Expected: All pass
- [ ] Step 3: Verify package exports
# Quick import check
python -c "
from diffusion_governors import IncludeConstraint, VocabBoostConstraint, Governor, GovernorContext
from diffusion_governors.include import _CoverageMechanism
print('IncludeConstraint:', IncludeConstraint)
print('VocabBoostConstraint:', VocabBoostConstraint)
print('All imports OK')
"
- [ ] Step 4: Verify Density is gone
python -c "
try:
from diffusion_governors import Density
print('FAIL: Density still exported')
except ImportError:
print('OK: Density removed')
"
- [ ] Step 5: Commit any final fixes
Task 19: Update CLAUDE.md and product plan¶
Files:
- Modify: CLAUDE.md
- Modify: docs/product-plan.md
- [ ] Step 1: Update CLAUDE.md
Update the Governed Generation section to reflect: - Density-weighted Include (replaces flat boost) - VocabBoostConstraint (new) - Session-level coverage tracking - Expanded norm allowlist (15+ norms)
- [ ] Step 2: Update product plan
Mark the Include/Coverage redesign as complete. Note VocabBoost as shipped.
- [ ] Step 3: Commit
git add CLAUDE.md docs/product-plan.md
git commit -m "docs: update CLAUDE.md and product plan for Include redesign + VocabBoost"