Hmbown/CodeWhale · error · RuntimeContractError
PROJECT_INSTRUCTION_CANDIDATES missing required entry {candi
Error message
PROJECT_INSTRUCTION_CANDIDATES missing required entry {candidate!r} What it means
From issue #3978: five well-known agent-instruction files must appear among the scanned candidates - .cursorrules, .clinerules, .windsurf/rules, .gemini, .github/copilot-instructions.md. The check is a whole-file substring search, so an entry may live in either PROJECT_INSTRUCTION_CANDIDATES or ADDITIONAL_PROJECT_INSTRUCTION_CANDIDATES; it fails only when the path string is absent or respelled anywhere in fragments.rs.
Source
Thrown at scripts/check-runtime-contract-budget.py:566
if "load_project_instruction_fragment" not in text:
raise RuntimeContractError(
"bounded fragment module must expose load_project_instruction_fragment (project-instruction import as typed fragment)"
)
if "PROJECT_INSTRUCTION_CANDIDATES" not in text:
raise RuntimeContractError(
"bounded fragment module must define PROJECT_INSTRUCTION_CANDIDATES"
)
# Required candidate files from #3978
required_candidates = [
".cursorrules",
".clinerules",
".windsurf/rules",
".gemini",
".github/copilot-instructions.md",
]
for candidate in required_candidates:
if candidate not in text:
raise RuntimeContractError(
f"PROJECT_INSTRUCTION_CANDIDATES missing required entry {candidate!r}"
)
# matches_text recognizer must exist on the fragment trait
if "fn matches_text" not in text:
raise RuntimeContractError(
"bounded fragment module must define a matches_text recognizer on the fragment trait"
)
if "trait ContextFragment" not in text:
raise RuntimeContractError(
"bounded fragment module must define trait ContextFragment with matches_text"
)
# No unbounded fragment — enforce that creation clamps to MAX_FRAGMENT_BYTES
if "MAX_FRAGMENT_BYTES" not in text or "enforce_byte_cap" not in text:
raise RuntimeContractError(
"bounded fragment module must enforce byte caps via enforce_byte_cap and MAX_FRAGMENT_BYTES"
)View on GitHub (pinned to 8880682c63)
Solutions
- Add the missing path (named in the error) back to PROJECT_INSTRUCTION_CANDIDATES or ADDITIONAL_PROJECT_INSTRUCTION_CANDIDATES in crates/core/src/fragments.rs
- Keep candidates as literal strings - the gate matches text, not semantics
- Cross-check against required_candidates in scripts/check-runtime-contract-budget.py:557-563
Example fix
// before (crates/core/src/fragments.rs)
pub const PROJECT_INSTRUCTION_CANDIDATES: &[&str] = &[".cursorrules", ".clinerules", ".gemini"];
// after
pub const PROJECT_INSTRUCTION_CANDIDATES: &[&str] = &[
".cursorrules",
".clinerules",
".windsurf/rules",
".gemini",
".github/copilot-instructions.md",
]; Defensive patterns
Strategy: try-catch
Validate before calling
from pathlib import Path
text = Path("crates/core/src/fragments.rs").read_text(encoding="utf-8")
for candidate in (".cursorrules", ".clinerules", ".windsurf/rules", ".gemini", ".github/copilot-instructions.md"):
assert candidate in text, f"candidate {candidate} missing" Type guard
def is_runtime_contract_error(exc: BaseException) -> bool:
return isinstance(exc, ValueError) and type(exc).__name__ == "RuntimeContractError" Try / catch
try:
check_fragment_caps()
except RuntimeContractError as error:
print(f"[gate] {error}", file=sys.stderr)
raise SystemExit(2) Prevention
- Keep candidate paths as literal strings, not computed values
- When adding a new editor rules file, append - never remove existing candidates without updating the gate list
- Cross-check edits against required_candidates in scripts/check-runtime-contract-budget.py:557-563
When it happens
Trigger: Dropping '.windsurf/rules' from the candidate arrays; respelling a path ('.github/Copilot-Instructions.md'); building paths with format!/join at runtime so the literal substring disappears from the file.
Common situations: Adding a new editor's rules file and 'tidying' older ones out; porting candidate lists into a runtime-built config struct.
Related errors
- bounded fragment module must define PROJECT_INSTRUCTION_CAND
- ProvidersToml returned no provider tables
- DEFAULT_FRAGMENT_MAX_BYTES ({default_bytes}) must not exceed
- DEFAULT_FRAGMENT_MAX_BYTES definition not found
- MAX_FRAGMENTS_PER_CONTEXT must be {FRAGMENT_MAX_COUNT_CEILIN
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/ed015c11819a38b2.
Report an issue: GitHub.