#!/usr/bin/env python3.14# -*- coding: utf-8 -*-"""Generate and re-document Project Euler solutions (Python and C) via the Claude API.Three public commands drive a model to emit solution files in `// BEGIN <file> ... // END <file>`blocks, then validate each generated file - compile (C), run every answered test case, and lint -retrying with the failures fed back until the files pass or the retry budget is exhausted."""from__future__importannotations__all__=['document_code','generate_c_code','generate_py_code']fromastimportliteral_evalfromfunctoolsimportpartialfromjsonimportloadsfrompathlibimportPathfromreimportDOTALL,MULTILINE,compileasre_compilefromsubprocessimportTimeoutExpired,runfromtimeimporttimefromtypingimportAny,Callable,Literal,NamedTuple,Protocol,runtime_checkablefromanthropicimportAPIErrorfromanthropic.typesimportMessageParamfromsolver.ai.factsimportFacts,format_solutions_markdown,gather_facts,prepare_anthropic_requestfromsolver.ai.modelsimportModel,record_usagefromsolver.configimportconfigfromsolver.core.problemsimportProblem,problemsfromsolver.shellimportconsolefromsolver.shell.dialogueimportconfirmfromsolver.templates.engineimportTemplates,filled_template,get_templatefromsolver.utils.path_utilsimportcanonical_path,iterdir_recursive,write_file# ----------------------------------------------------------------------------------------------------# Response parsing# ----------------------------------------------------------------------------------------------------_FENCE=re_compile(r'^[ \t]*(?:`{3,}|~{3,})[^\n]*\n(?P<body>.*)\n[ \t]*(?:`{3,}|~{3,})[ \t]*$',DOTALL)_PATTERN=re_compile(r'^// BEGIN (\S+)\n(.*?)\n// END \1',MULTILINE|DOTALL)def_strip_code_fence(code:str)->str:"""Drop a surrounding markdown code fence the model sometimes emits inside the delimiters. The // BEGIN / // END block should contain raw source, but a stray ```c ... ``` (or ~~~) wrapper leaks backticks into the file and breaks compilation. If the trimmed code both opens and closes with a fence line, return the body between them; otherwise return the code unchanged. """stripped:str=code.strip('\n')match=_FENCE.match(stripped)fixed=match.group('body')ifmatchelsecodereturnfixed+'\n'def_retry_missing_message(truncated:bool,files_to_generate:str)->str:"""Build the retry-prompt user message when the previous response had no parseable solutions."""iftruncated:reason='Your previous response was truncated before any complete solution block was emitted.'else:reason='Your previous response did not contain any valid solution blocks.'return(f'{reason} 'f'Please output all required solutions using the // BEGIN / // END format, 'f'ensuring each block is fully closed.\n\n'f'Files to generate: {files_to_generate}')classSolution(NamedTuple):name:strcode:strfile:Pathexecutable:Path@staticmethoddeffrom_msg(msg:str,problem:Problem)->list[Solution]:"""Parse solutions from an AI response containing // BEGIN / // END delimiters."""solutions:list[Solution]=[]formin_PATTERN.finditer(msg):name:str=m.group(1)code:str=_strip_code_fence(m.group(2))file:Path=problem.solution_dir/namesuffix:str=file.suffixifsuffixin('.c','.py'):write_file(file,code.encode(),f'generated {name}')ifsuffix=='.c':executable:Path=problem.solution_dir/f'{file.stem}_c'elifsuffix=='.py':file.chmod(0o755)executable=fileelse:executable=file.with_suffix('.exe')solutions.append(Solution(name=name,code=code,file=file,executable=executable))returnsolutions# ----------------------------------------------------------------------------------------------------# Validation result types# ----------------------------------------------------------------------------------------------------classSolutionsCheckResults(NamedTuple):verdict:boolmsg:strpassed:list[str]failed:list[str]errors:dict[str,str]defas_msg(self)->str:# TO:DO, modify if required"""Render the check results (verdict, message, passed/failed lists, errors) as Markdown."""ifself.errors:errors_section='## errors:\n\n'forfilename,errorinself.errors.items():errors_section+=f'### errors in filename: {filename}\n\n{error}\n\n'else:errors_section='## errors:\n\n(none)\n\n'return(f'## verdict:\n\n{'passed'ifself.verdictelse'failed'}\n\n'f'## messages:\n\n{self.msg}\n\n'f'## passed:\n\n{"\n".join(f"- {s}"forsinself.passed)ifself.passedelse"(none)"}\n\n'f'## failed:\n\n{"\n".join(f"- {s}"forsinself.failed)ifself.failedelse"(none)"}\n\n'f'{errors_section}')@runtime_checkableclassValidator(Protocol):"""Protocol for validator callables that check generated code."""def__call__(self,*,attempt:int,solutions:list[Solution],)->SolutionsCheckResults:""" Check the supplied solutions and return a verification result. Args: attempt: The current attempt number for solution verification. solutions: A list of Solution objects to be verified. Returns: A SolutionsCheckResults object containing the result of the verification process. """...# ----------------------------------------------------------------------------------------------------# Generation driver# ----------------------------------------------------------------------------------------------------def_generate_code(model:Model,problem:Problem,label:Literal['c code','py code','doc'],prompt:str,retry_missing:Callable[[bool],str],validator:Validator,images:dict[str,bytes]|None=None,)->bool|None:""" Drive a model to generate solutions, retrying on parse or validation failure. Args: model: The language model used for generating solutions. label: The label for the problem being solved. problem: The problem for which solutions are being generated. prompt: Template prompt to guide the model's solution generation. retry_missing: Function to generate a retry message for missing solutions differentiated based on if stop_reason was max_tokens. validator: Callable used for validating generated solutions. images: Optional map of resource filename to image bytes referenced in the problem content; each is attached to the initial user message as an image content block so the model can actually see the image. Returns: bool: True if solutions were successfully generated and validated, False on generation or validation failure after all retries. """try:client,system_blocks,messages=prepare_anthropic_request(prompt,images)except(ValueError,OSError)ase:console.print(f'[error]error:[/error] {type(e).__name__} preparing request for 'f'[accent]problem {problem.number}[/accent]: {e}')returnFalseforattemptinrange(1,config.max_retries+1):console.print(f'[primary]Generating {label} for [accent]problem {problem.number}[/accent] 'f'(attempt {attempt}/{config.max_retries})...[/primary]')try:withclient.messages.stream(model=model,max_tokens=config.max_output_tokens,system=system_blocks,messages=messages,timeout=config.api_timeout)asstream:response=stream.get_final_message()exceptAPIErrorase:console.print(f'[error]error:[/error] Anthropic API error for 'f'[accent]problem {problem.number}[/accent]: {e}')returnFalserecord_usage(model,response.usage)usage=response.usageconsole.print(f'[muted]Tokens used for [accent]problem {problem.number}[/accent]: 'f'input {usage.input_tokens}, output {usage.output_tokens}, 'f'cache_write {getattr(usage,"cache_creation_input_tokens",0)or0}, 'f'cache_read {getattr(usage,"cache_read_input_tokens",0)or0}, 'f'stop_reason {response.stop_reason!r}[/muted]')truncated:bool=response.stop_reason=='max_tokens'iftruncated:console.print(f'[warning]Warning: max_tokens reached for problem {problem.number}; 'f'response may be truncated[/warning]')text:str|None=next((b.textforbinresponse.contentifb.type=='text'),None)iftextisNone:console.print(f'[error]error:[/error] no text block in response for 'f'[accent]problem {problem.number}[/accent]')returnFalsesolutions:list[Solution]=Solution.from_msg(text,problem)ifnotsolutions:console.print(f'[error]error:[/error] could not parse any solutions from response for 'f'[accent]problem {problem.number}[/accent]')ifattempt<config.max_retries:retry_msg=retry_missing(truncated)messages.append(MessageParam(role='assistant',content=text))messages.append(MessageParam(role='user',content=retry_msg,))continueresult=validator(attempt=attempt,solutions=solutions)ifresult.verdict:returnTrueifattempt<config.max_retries:messages.append(MessageParam(role='assistant',content=text))messages.append(MessageParam(role='user',content=(f'The following solutions failed validation:\n'f'{','.join(result.failed)}\n\n'f'Please fix only the failed solutions 'f'and return them in the same // BEGIN / // END format.\n\n'f'{result.as_msg()}'),))console.print(f'[error]error:[/error] failed to generate valid solutions for 'f'[accent]problem {problem.number}[/accent] 'f'after {config.max_retries} attempts')returnFalse# ----------------------------------------------------------------------------------------------------# Validation: per-solution checks# ----------------------------------------------------------------------------------------------------def_check_solution_against_test_cases(*,solution:Solution,test_cases:list[dict[str,Any]],failed:set[str],errors:dict[str,str],expected_type:type,)->None:"""Run *solution* against each test case, recording failures and errors in place. Executes the solution once per test case, parsing its final stdout line into *expected_type* and comparing it to the case's answer. A `dev`/`main` case that times out, exits non-zero (other than an OverflowError), or returns the wrong answer adds the solution to *failed*; the diagnostic text is collected in *errors* keyed by solution name. A `main` case with no recorded answer prompts the user to confirm the computed result interactively. """timeout=config.timeout_singlefortest_caseintest_cases:category:str=test_case['category']input_args:list[str]=[str(v)forvintest_case['input'].values()]expected:Any|None=test_case['answer']cmdline=[f'{solution.executable}',*input_args,'--runs=1']try:process=run(cmdline,capture_output=True,text=True,cwd=config.root_dir,timeout=timeout,)exceptTimeoutExpiredase:console.print(f'cmdline: {" ".join(cmdline)}\nrc: -1\nstdout:\nstderr:\nerror: {e}\n',markup=False,highlight=False)errors[solution.name]=(f'#### cmdline:\n\n{' '.join(cmdline)}\n\n'f'#### error:\n\ncmd did not complete within timeout of 'f'{timeout} seconds\n\n'f'#### stdout:\n\n{(e.stdoutorb'').decode()}\n\n'f'#### stderr:\n\n{(e.stderrorb'').decode()}\n\n')iftest_case['category']in('dev','main'):failed.add(solution.name)continueelse:console.print(f'cmdline: {" ".join(cmdline)}\nrc: {process.returncode}\n'f'stdout: {process.stdout.strip('\n')}\nstderr: {process.stderr.strip('\n')}\n',markup=False,highlight=False)ifprocess.returncode!=0:if'OverflowError:'notin(process.stderror''):failed.add(solution.name)errors[solution.name]=(f'#### cmdline:\n\n{' '.join(cmdline)}\n\n'f'#### error:\n\nprocess returned non-zero exit code {process.returncode}\n\n'f'#### stdout:\n\n{process.stdout}\n\n'f'#### stderr:\n\n{process.stderr}\n\n')breaktry:_runs,_average,_answer=process.stdout.splitlines()[-1].split(' ',maxsplit=2)answer=literal_eval(_answer)ifexpected_typein(list,tuple,dict)elseexpected_type(_answer)ifcategory=='main'andexpectedisNone:console.print(f'[accent]{solution.name}{input_args} -> [bold]{_answer}[/bold][/accent]')assertconfirm(f'Is {_answer} the correct answer?',assume=False),f'answer {_answer} is rejected.'ifexpectedisnotNone:assertanswer==expected,f'incorrect answer {_answer}, expected {expected}'except(AssertionError,IndexError,ValueError)aserr:failed.add(solution.name)existing_error=errors.get(solution.name,'')existing_error=existing_error+('\n\n'ifexisting_errorelse'')errors[solution.name]=existing_error+(f'#### cmdline:\n\n{' '.join(cmdline)}\n\n'f'#### error:\n\n{err}\n\n'f'#### stdout:\n\n{process.stdout}\n\n'f'#### stderr:\n\n{process.stderr}\n\n')def_check_results(*,passed:set[str],failed:set[str],errors:dict[str,str],)->SolutionsCheckResults:"""Aggregate the passed/failed sets and errors into a `SolutionsCheckResults` verdict."""iffailed:verdict:bool=Falsemsg:str=f'{len(failed)} solutions failed, {len(passed)} passed'else:verdict=Truemsg=f'{len(passed)} solutions passed'returnSolutionsCheckResults(verdict=verdict,msg=msg,passed=sorted(passed),failed=sorted(failed),errors=dict(errors),)def_check_c_solution(*,solution:Solution,test_cases:list[dict[str,Any]],expected_type:type,failed:set[str],errors:dict[str,str],)->None:"""Compile and test one generated C solution, updating passed/failed/errors in place."""cmdline:list[str]=[config.scripts.compile_c,canonical_path(solution.file),'--clean']process=run(cmdline,capture_output=True,text=True,cwd=config.root_dir)console.print(f'cmdline: {" ".join(cmdline)}\nrc: {process.returncode}\n'f'stdout:\n{process.stdout}\nstderr:\n{process.stderr}\n',markup=False,highlight=False)ifprocess.returncode!=0:failed.add(solution.name)errors[solution.name]=(f'#### cmdline:\n\n{' '.join(cmdline)}\n\n'f'#### error:\n\ncompilation failed\n\n'f'#### stdout:\n\n{process.stdout}\n\n'f'#### stderr:\n\n{process.stderr}\n\n')return_check_solution_against_test_cases(solution=solution,test_cases=test_cases,failed=failed,errors=errors,expected_type=expected_type,)def_check_py_solution(*,solution:Solution,test_cases:list[dict[str,Any]],expected_type:type,failed:set[str],errors:dict[str,str],)->None:"""Write and test one generated Python solution, updating passed/failed/errors in place."""# Validate the first two header lines exactly as the prompt and `new.py` template mandate:# line 1 is the python3.14 shebang, line 2 is the UTF-8 coding declaration.expected_header:tuple[str,str]=('#!/usr/bin/env python3.14','# -*- coding: utf-8 -*-')header_lines:list[str]=solution.code.split('\n',2)[:2]actual_header:tuple[str,...]=tuple(line.rstrip()forlineinheader_lines)ifactual_header!=expected_header:failed.add(solution.name)errors[solution.name]=(f'{solution.name} does not have the required header. 'f'Expected first two lines to be {list(expected_header)!r}, 'f'got {list(actual_header)!r}')return_check_solution_against_test_cases(solution=solution,test_cases=test_cases,failed=failed,errors=errors,expected_type=expected_type,)def_lint_generated_code(*,solution:Solution,failed:set[str],errors:dict[str,str],)->None:"""Lint one generated Python solution with flake8 and mypy, updating failed/errors in place. Functional validity (compile / run / answer) is checked elsewhere; this guards the static gates the committed solutions must pass (`flake8 --max-line-length 120` and `mypy`). A lint-only failure the model cannot reliably avoid by instruction alone - an over-long docstring line (E501), a missing trailing newline (W292), or a type error - is caught here and fed back into the retry loop instead of surfacing later at `lint` / `stack`. Both linters always run - even for a solution that already failed a functional check - so a single retry carries the functional and static fixes together, avoiding an extra pass. Only `.py` files are linted (neither tool has a C equivalent; C is covered by compilation). """ifsolution.file.suffix!='.py':returnpath:str=canonical_path(solution.file)defrun_linter(cmdline:list[str],summary:str)->None:process=run(cmdline,capture_output=True,text=True,cwd=config.root_dir)console.print(f'cmdline: {" ".join(cmdline)}\nrc: {process.returncode}\n'f'stdout: {process.stdout.strip('\n')}\nstderr: {process.stderr.strip('\n')}\n',markup=False,highlight=False)ifprocess.returncode!=0:failed.add(solution.name)existing_error=errors.get(solution.name,'')existing_error=existing_error+('\n\n'ifexisting_errorelse'')errors[solution.name]=existing_error+(f'#### cmdline:\n\n{' '.join(cmdline)}\n\n'f'#### error:\n\n{summary}\n\n'f'#### stdout:\n\n{process.stdout}\n\n'f'#### stderr:\n\n{process.stderr}\n\n')run_linter(['flake8',f'--max-line-length={config.max_line_length}',path],f'flake8 reported style violations; every line must pass 'f'flake8 --max-line-length {config.max_line_length}')run_linter(['mypy',path],'mypy reported type errors; the solution must pass mypy with no errors')def_check_generated_code(*,problem:Problem,attempt:int,solutions:list[Solution],test_cases:list[dict[str,Any]],)->SolutionsCheckResults:"""Check that generated solutions are functionally valid, dispatching per file by extension. Each solution is routed by its filename suffix: `.c` is compiled then run, `.py` is header-checked then run; any other extension fails immediately. Every functionally valid file is then linted (`.py` with flake8 and mypy) so a static-check-only violation is rejected and retried rather than surfacing later at `lint` / `stack`. A failed file is preserved as a `.bak` and removed. This single validator backs Python generation, C generation, and the documentation pass (which re-emits a mix of `.py` and `.c` files). """ifnotsolutions:returnSolutionsCheckResults(verdict=False,msg='No solutions found',passed=[],failed=[],errors={})passed:set[str]=set()failed:set[str]=set()errors:dict[str,str]={}expected_type:type=next((type(tc['answer'])fortcintest_casesiftc['answer']isnotNone),str)forsolutioninsolutions:suffix:str=Path(solution.name).suffixifsuffix=='.c':_check_c_solution(solution=solution,test_cases=test_cases,expected_type=expected_type,failed=failed,errors=errors)elifsuffix=='.py':_check_py_solution(solution=solution,test_cases=test_cases,expected_type=expected_type,failed=failed,errors=errors)else:failed.add(solution.name)errors[solution.name]=f'{solution.name} is not a valid source filename, should end with .py or .c'_lint_generated_code(solution=solution,failed=failed,errors=errors)ifsolution.nameinfailed:# Preserve the rejected source as a .bak for debugging and remove it from the solution# directory so a final-failure leftover never lingers; a retry re-emits and rewrites it via from_msg.backup_file:Path=solution.file.with_suffix(f'.{attempt}{suffix}.bak')write_file(backup_file,solution.code.encode(),f'backup of failed {solution.name}')solution.file.unlink(missing_ok=True)else:passed.add(solution.name)final:SolutionsCheckResults=_check_results(passed=passed,failed=failed,errors=errors)iffinal.verdict:# success on any attempt: drop accumulated .bak litter from earlier retriesforfileiniterdir_recursive(problem.solution_dir,rt='path'):iffile.suffix=='.bak':file.unlink(missing_ok=True)elifattempt==config.max_retries:# final attempt still failing: preserve the rejected sourcesbackup_dir:Path=config.backup_dir/f'p{problem.number:04d}_{int(time())}'backup_dir.mkdir(parents=True,exist_ok=True)forfileiniterdir_recursive(problem.solution_dir,rt='path'):iffile.suffix=='.bak':file.rename(backup_dir/file.with_suffix('').name)console.print(f'[accent.dim]backup of failed solutions to {canonical_path(backup_dir)}[/accent.dim]')returnfinal# ----------------------------------------------------------------------------------------------------# Public commands# ----------------------------------------------------------------------------------------------------def_load_test_cases(problem:Problem,filter_null_answers:bool)->list[dict[str,Any]]:"""Load *problem*'s test cases, optionally dropping those without an answer. Warns (or errors, when *filter_null_answers* is True) if no answered case is found, and reports when the answered cases mix more than one answer type. """test_cases:list[dict[str,Any]]=loads((problem.solution_dir/config.test_cases_filename).read_text())ifnot(filtered:=[tcfortcintest_casesiftc['answer']isnotNone]):style='error'iffilter_null_answerselse'warning'console.print(f'[{style}]{style}:[/{style}] no test cases with answer found for 'f'[accent]problem {problem.number}[/accent]')expected_types:set[type]={type(tc['answer'])fortcinfiltered}iflen(expected_types)>1:console.print(f'[error]error:[/error] multiple answer types in test cases for 'f'[accent]problem {problem.number}[/accent]: {expected_types}')return[]returnfilterediffilter_null_answerselsetest_casesdefgenerate_c_code(model:Model,*,problem:Problem,force:bool,major:bool)->bool|None:""" Generates C code for the problem's Python solutions. This function identifies Python solution files that do not have corresponding C implementation files. It generates C code for these Python solutions based on the test cases and problem metadata. The C solutions are created using a templated approach and validated through specific criteria. Errors during the process, such as template parsing failures or missing test cases with answers, are handled, and appropriate messages are logged. Arguments: model (Model) : The model instance to use for generating the C solutions. problem (Problem) : The problem to generate C code for. force (bool) : If True, forces generation even if no files are missing. major (bool) : Whether this is after a major change. Returns: bool | None: Returns True if the C code generation process completes successfully. Returns False if there are errors during the process. Returns None if there are no files to generate. """ifmajor:console.print('[muted]Use structural code transformation for migration after major change.[/muted]')returnNoneifnot(test_cases:=_load_test_cases(problem,filter_null_answers=True)):returnNonepy_solutions:set[str]={f.stemforfiniterdir_recursive(problem.solution_dir,rt='path')iff.suffix=='.py'}c_solutions:set[str]={f.stemforfiniterdir_recursive(problem.solution_dir,rt='path')iff.suffix=='.c'}files_to_generate:str=' '.join(f'{f}.c'forfinpy_solutionsiffnotinc_solutions)ifnot(forceorfiles_to_generate):console.print('[muted]No C solutions to generate.[/muted]')returnNonetry:facts:Facts=gather_facts(problem,strict=True)exceptValueErrorase:console.print(f'[error]error:[/error] could not generate C: {e}')returnFalsesolution_template:str=get_template(Templates.NEW_C).substitute(problem=problem.as_title())try:prompt=filled_template(Templates.PROMPT_C,facts=facts,files_to_generate=files_to_generate,solution_template=format_solutions_markdown({'template.c':solution_template}),)except(KeyError,ValueError)ase:console.print(f'[error]error:[/error] template parsing error for 'f'[accent]problem {problem.number}[/accent]: {e}')returnFalsereturn_generate_code(model=model,problem=problem,label='c code',prompt=prompt,retry_missing=partial(_retry_missing_message,files_to_generate=files_to_generate),validator=partial(_check_generated_code,problem=problem,test_cases=test_cases),images=facts.images,)defgenerate_py_code(model:Model,*,problem:Problem,force:bool,major:bool)->bool|None:""" Generates Python code for a specified problem using the provided model. The function creates a new file in the problem's solution directory with a unique name, gathers problem-related facts, and formulates a completion prompt for generating solutions. It verifies the presence of problem content and valid test cases before code generation. The function also handles template parsing errors and prompts for retry messages when required. Parameters: model (Model) : The AI model to use for generating the code. problem (Problem) : The problem to generate Python code for. force (bool) : Whether to force the code generation process. major (bool) : Whether this is after a major change. Returns: bool | None: True if code generation is successful, False if an error or validation issue occurs, or None if the problem has no content. """ifmajor:console.print('[muted]Use structural code transformation for migration after major change.[/muted]')returnNoneifnot(test_cases:=_load_test_cases(problem,filter_null_answers=False)):returnNonenum_existing:int=sum(1forsinproblem.solution_dir.iterdir()ifs.is_file()ands.suffix=='.py')ifnotforceandnum_existing==0:console.print('[muted]No python solutions; solve the problem first[/muted]')returnNonefile_to_generate:str=f'p{problem.number:04d}_s{num_existing}.py'try:facts:Facts=gather_facts(problem,strict=notforce)exceptValueErrorase:console.print(f'[error]error:[/error] could not generate py: {e}')returnFalseifnotfacts.problem_content:console.print(f'[error]error:[/error] no problem content found for 'f'[accent]problem {problem.number}[/accent]')returnFalsesolution_template:str=get_template(Templates.NEW_PY).substitute(problem=problem.as_title())try:prompt=filled_template(Templates.PROMPT_PY,facts=facts,file_to_generate=file_to_generate,solution_template=format_solutions_markdown({'template.py':solution_template}),)except(KeyError,ValueError)ase:console.print(f'[error]error:[/error] template parsing error for 'f'[accent]problem {problem.number}[/accent]: {e}')returnFalsereturn_generate_code(model=model,problem=problem,label='py code',prompt=prompt,retry_missing=partial(_retry_missing_message,files_to_generate=file_to_generate),validator=partial(_check_generated_code,problem=problem,test_cases=test_cases),images=facts.images,)defdocument_code(model:Model,*,problem:Problem,force:bool,major:bool)->bool|None:""" Refresh the in-source documentation of every solution for the problem, leveraging AI. This is the API counterpart of the claude-euler-solver skill's `document` action: it re-emits each `pNNNN_sK.py` / `.c` with improved module/function docstrings and comments while leaving the algorithm and behaviour untouched, then re-checks functional validity exactly as code generation does - compiling each C file, header-checking each Python file, and running every answered test case. A file that no longer passes its test cases is rejected and rolled back, so a documentation pass can never silently change what a solution computes. Arguments: model (Model) : The model instance to use for re-documenting the solutions. problem (Problem) : The problem whose solutions to re-document. force (bool) : Accepted for the common generator signature; documentation always runs over the existing solutions. major (bool) : Accepted for the common generator signature; unused here. Returns: bool | None: True if all solutions were re-documented and re-validated successfully, False on a generation, validation, or setup error, None if there are no solutions to document. """ifmajor:console.print('[muted]Use structural code transformation for migration after major change.[/muted]')returnNoneifnot(forceorproblem.numberinset(p.numberforpinproblems.solved_problems)):console.print('[muted]Use [accent]--force[/accent] to re-document solutions.[/muted]')returnNoneifnot(test_cases:=_load_test_cases(problem,filter_null_answers=True)):returnNonefiles_to_generate:str=' '.join(sorted(f.nameforfiniterdir_recursive(problem.solution_dir,rt='path')iff.suffixin('.py','.c')))ifnotfiles_to_generate:console.print('[muted]No solutions to document.[/muted]')returnNonetry:facts:Facts=gather_facts(problem,strict=True)exceptValueErrorase:console.print(f'[error]error:[/error] could not document solutions: {e}')returnFalsetry:prompt=filled_template(Templates.PROMPT_DOC,facts=facts,files_to_generate=files_to_generate,)except(KeyError,ValueError)ase:console.print(f'[error]error:[/error] template parsing error for 'f'[accent]problem {problem.number}[/accent]: {e}')returnFalsereturn_generate_code(model=model,problem=problem,label='doc',prompt=prompt,retry_missing=partial(_retry_missing_message,files_to_generate=files_to_generate),validator=partial(_check_generated_code,problem=problem,test_cases=test_cases),images=facts.images,)