{"record":{"id":"cb1fa1a65746fe17","repo":"Hmbown/CodeWhale","slug":"bounded-fragment-module-must-define-project-instruction","errorCode":null,"errorMessage":"bounded fragment module must define PROJECT_INSTRUCTION_CANDIDATES","messagePattern":"bounded fragment module must define PROJECT_INSTRUCTION_CANDIDATES","errorType":"exception","errorClass":"RuntimeContractError","httpStatus":null,"severity":"error","filePath":"scripts/check-runtime-contract-budget.py","lineNumber":560,"sourceCode":"    # Marker stability — these strings are pinned by tests / prefix cache\n    required_markers = [\n        \"<!-- cw:ctx:workspace -->\",\n        \"<!-- cw:ctx:project_instructions -->\",\n        \"<!-- cw:ctx:constitution -->\",\n    ]\n    for marker in required_markers:\n        if marker not in text:\n            raise RuntimeContractError(\n                f\"bounded fragment module missing required marker {marker!r}\"\n            )\n\n    # Project-instruction import must be a typed fragment, not ad-hoc\n    if \"load_project_instruction_fragment\" not in text:\n        raise RuntimeContractError(\n            \"bounded fragment module must expose load_project_instruction_fragment (project-instruction import as typed fragment)\"\n        )\n    if \"PROJECT_INSTRUCTION_CANDIDATES\" not in text:\n        raise RuntimeContractError(\n            \"bounded fragment module must define PROJECT_INSTRUCTION_CANDIDATES\"\n        )\n    # Required candidate files from #3978\n    required_candidates = [\n        \".cursorrules\",\n        \".clinerules\",\n        \".windsurf/rules\",\n        \".gemini\",\n        \".github/copilot-instructions.md\",\n    ]\n    for candidate in required_candidates:\n        if candidate not in text:\n            raise RuntimeContractError(\n                f\"PROJECT_INSTRUCTION_CANDIDATES missing required entry {candidate!r}\"\n            )\n\n    # matches_text recognizer must exist on the fragment trait\n    if \"fn matches_text\" not in text:","sourceCodeStart":542,"sourceCodeEnd":578,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/scripts/check-runtime-contract-budget.py#L542-L578","documentation":"check_fragment_caps statically reads crates/core/src/fragments.rs and asserts the project-instruction import is a typed fragment. It requires the module to expose load_project_instruction_fragment and to define the PROJECT_INSTRUCTION_CANDIDATES list; missing the candidates constant fails the contract budget check with this RuntimeContractError. This guards the contract from issue #3978 that project instructions come from a known, typed candidate set.","triggerScenarios":"Running scripts/check-runtime-contract-budget.py when crates/core/src/fragments.rs exists and contains load_project_instruction_fragment but the literal string PROJECT_INSTRUCTION_CANDIDATES is absent from its text (e.g. renamed constant, moved to another module, or never implemented).","commonSituations":"A refactor renames PROJECT_INSTRUCTION_CANDIDATES to something like INSTRUCTION_FILES; the candidates list is moved out of fragments.rs into a helper module; a new fragment module is scaffolded without the project-instruction section; reverting a commit accidentally drops the constant.","solutions":["Open crates/core/src/fragments.rs and define `pub const PROJECT_INSTRUCTION_CANDIDATES: &[&str]` listing the required candidate files.","If the constant was renamed or moved, restore the original name in fragments.rs (or re-expose it there) since the check is a literal text match.","Run `python scripts/check-runtime-contract-budget.py` to confirm the fragment-cap section passes."],"exampleFix":"// before (fragments.rs)\nfn load_project_instruction_fragment() -> Option<...> { ... }\n\n// after\npub const PROJECT_INSTRUCTION_CANDIDATES: &[&str] = &[\n    \".cursorrules\",\n    \".clinerules\",\n    \".windsurf/rules\",\n    \".gemini\",\n    \".github/copilot-instructions.md\",\n];\n\nfn load_project_instruction_fragment() -> Option<...> { ... }","handlingStrategy":"validation","validationCode":"from pathlib import Path\ntext = Path('crates/core/src/fragments.rs').read_text(encoding='utf-8')\nassert 'PROJECT_INSTRUCTION_CANDIDATES' in text, 'define PROJECT_INSTRUCTION_CANDIDATES in fragments.rs'","typeGuard":"def has_project_instruction_candidates(module_text: str) -> bool:\n    return 'PROJECT_INSTRUCTION_CANDIDATES' in module_text","tryCatchPattern":"try:\n    subprocess.run(['python', 'scripts/check-runtime-contract-budget.py'], check=True)\nexcept subprocess.CalledProcessError as e:\n    if 'PROJECT_INSTRUCTION_CANDIDATES' in e.stderr:\n        add_candidates_constant_to_fragments_rs()","preventionTips":["Treat crates/core/src/fragments.rs as a contract-pinned file: check scripts/check-runtime-contract-budget.py before renaming anything in it.","Run the contract budget script in pre-commit or CI so text-level contract breaks surface before merge.","Keep required constants as literal definitions in fragments.rs, not re-exports with different names."],"tags":["rust","static-analysis","contract-check","fragments"],"backgroundTag":"missing-required-config-field","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}