| name | code-completion-NO-RECOVERY-LOOP |
| description | ABLATION VARIANT — RECOVERY LOOP REMOVED.
This is the doctest-driven code-completion skill with the iterative Recovery
Loop pattern ablated out. Everything else (Orchestration: the staged pipeline,
task routing, 5-tier classification, multi-file progressive disclosure; and the
Quality Gates) is preserved exactly as in the full skill.
Use this skill whenever you are given a Python code file with missing code and
asked to complete it. It generates doctests as a validation oracle, generates the
code, runs the doctests ONCE to record a pass/fail signal, and then delivers the
first candidate. It does NOT diagnose failures and it does NOT iterate or repair.
Trigger for:
- Any prompt containing a Python code file where code is missing or truncated
- Requests like "complete this function", "fill in the missing code", "implement this"
- JSON records with a "prompt" field and a "metadata" field with either
"function_name" (function body task) or "line_no" (line completion task)
- Any RepoEval-style code completion benchmark instance
Do not trigger for:
- General code questions or explanations with no missing code to fill in
- Requests to write entirely new files from scratch with no existing context
- Debugging tasks where all code is already present
|
| compatibility | {"requires":"bash_tool, Python 3.7+","note":"bash_tool is used to run the single validation pass (run_doctest.py). If bash_tool is unavailable, generate doctests and code but flag that validation was skipped."} |
Code Completion with Doctest-Driven Validation — NO RECOVERY LOOP (Ablation A)
What is ablated: the Recovery Loop pattern. In the full skill, Step 9 writes
the candidate to a temp file, runs the doctest runner, diagnoses failures,
applies a targeted fix, and repeats up to MAX_RECOVERY_ITERATIONS times. In
this variant Step 9 runs the doctest runner exactly once and records the
result. There is no diagnosis, no fix, and no re-run. Whatever the first
candidate produced is what gets delivered.
What is preserved: Orchestration (the staged recipe, task routing, the
5-tier classification, the multi-file reference structure) and the Quality Gates
(Steps 5 and 10). This isolates the marginal contribution of the Recovery Loop:
comparing this variant against the full skill measures exactly what the iterative
repair buys.
This skill completes missing Python code — either a full function body or the
remainder of a truncated line — using a test-first approach: generate doctests that
define the contract, generate code that fulfils it, then validate once.
The order still matters. Doctests before code forces you to commit to what the
function should do before deciding how it does it. The difference from the full
skill is that a misunderstanding surfaced by the single validation pass is
reported, not repaired — there is no loop to fix it.
Folder structure
code-completion-NO-RECOVERY-LOOP/
├── SKILL.md ← you are here
├── run_doctest.py ← executes doctests against candidate code (ONE pass)
├── doctest_generator.md ← formatting rules, tier strategy, generation patterns
├── single_validation.md ← the single-pass validation step (replaces recovery_loop.md)
└── injection.md ← final assembly and delivery format
Load each reference file at the step that calls for it.
Understanding your inputs
You will receive a JSON record in one of two shapes. The single metadata key that
differs between them is how you tell the tasks apart — check it explicitly, never
infer from the prompt shape.
Function body completion — the prompt ends right after a function's docstring
closing """ (or after the signature : if there is no docstring). The body is
entirely absent. Generate the complete indented body.
Line completion — the prompt ends mid-line. Generate only the characters that
complete that one line. Nothing more — no newline, no next line.
Routing rule: "function_name" in metadata → FUNCTION_BODY task.
"line_no" in metadata → LINE task. These are mutually exclusive.
Configuration
| Parameter | Default | What it controls |
|---|
DOCTEST_SCOPE | "targeted" | "targeted" = target function only; "file" = also generate for functions the target calls internally |
INJECT_DOCTESTS | true | Whether passing doctests stay in the final output permanently |
Note: MAX_RECOVERY_ITERATIONS and BEST_ATTEMPT_ON_FAILURE from the full skill
are intentionally absent — there is no loop and no across-iteration best-attempt
tracking in this variant. The single validation pass is always one attempt.
The workflow
Steps run in strict order. Each produces something the next depends on.
Step 1 → Analyse the file
Step 2 → Route to task type
Step 3 → Load additional context (only what is needed)
Step 4 → Classify the target function
Step 5 → Pre-generation quality gate
Step 6 → Generate doctests [→ doctest_generator.md]
Step 7 → Validate doctest structure
Step 8 → Generate first candidate code
Step 9 → Single validation pass [→ single_validation.md] (NO recovery loop)
Step 10 → Post-generation quality gate
Step 11 → Inject and deliver [→ injection.md]
Step 1 — Analyse the file
Read the entire prompt field before doing anything else. Build a mental model of
the codebase so that whatever you generate fits naturally into it.
As you read, note:
- Every import statement and what it provides
- Module-level variables and constants
- Class names, their methods, and inheritance relationships
- Other function names visible in the prompt and what they do
- The naming style in use (snake_case, camelCase — infer from existing code)
- How existing functions handle errors: raise, return None, return a sentinel value?
- What types existing functions return
- Any decorators on the target function
- The exact docstring of the target function, verbatim, if present
Stop here if the prompt is empty or unparseable. Report the error rather than
proceeding with no context.
Step 2 — Route to task type
Check the metadata keys:
"function_name" present → FUNCTION_BODY task. Record the function name and
metadata["lineno"] as the line where the body starts.
"line_no" present → LINE task. Record metadata["line_no"] as the line
being completed.
- Neither present → stop. Report that the task type cannot be determined.
For FUNCTION_BODY: generate everything from the first indented line of the body
through the final return or expression. Match the file's indentation (4 spaces
standard). Do not alter the signature or the docstring.
For LINE: generate only the characters that come after the last character of the
prompt on that same line. No leading newline. No additional lines.
Step 3 — Load additional context
The prompt is your primary source. Before loading anything else, exhaust what it
already tells you. Only go further if the target function references names that do
not appear anywhere in the prompt and cannot be inferred from the imports.
Never load the repository's test files. Those are the external ground truth that
runs after delivery. Loading them contaminates the completion.
Step 4 — Classify the target function
Before generating any doctests, classify the target function into the tier that best
describes what it does. The tier determines what kind of doctests are possible.
| Tier | Type | Signal | Doctest strategy |
|---|
| 1 | Pure / Deterministic | No external calls, same output every time | Full input → output examples |
| 2 | Contract-Testable | Non-deterministic output but testable type/shape/range | Test isinstance, len, bounds |
| 3 | Setup-Assisted | Needs temp object, class instantiation, or asyncio.run | Set up context inline in doctest |
| 4 | Error-Path Only | Calls DB, API, network, filesystem | Test only input validation and error raises |
| 5 | Untestable | Even error paths need live external state | Document with TODO, skip doctest |
Special case for LINE tasks: First determine what syntactic context the
truncated line sits in:
- Inside a function body → classify that function using the tier table above
- Inside an import block (
from x import () → Tier 5, no doctest possible
- Module-level assignment or constant → Tier 5, no doctest possible
- Class attribute declaration → Tier 5, no doctest possible
For Tier 5 contexts in LINE tasks, skip doctest generation entirely and proceed
directly to Step 8. Record that validation was skipped and why.
Read doctest_generator.md for detailed guidance on each tier's generation
patterns before proceeding to Step 6.
Step 5 — Pre-generation quality gate
Before writing any doctest or any code, confirm you can answer these questions. If
you cannot answer one, make the assumption explicit and record your confidence level
(high / medium / low).
- What does this function do? (source: docstring, function name, call sites)
- What input types does it accept?
- What does it return, and in what type?
- What exceptions should it raise, and under what conditions?
- Are all imports this implementation will need already present in the prompt?
- For LINE tasks: what syntactic construct is the truncated line completing?
Note: in the full skill, a wrong assumption here could still be caught and
repaired by the recovery loop. In this variant there is no such safety net — a
wrong assumption here will be carried straight through to delivery. The quality
gate is therefore the only pre-delivery check on intent. Treat it accordingly.
Step 6 — Generate doctests
Read doctest_generator.md now.
Generate doctests appropriate for the tier you identified in Step 4. The goal is to
define the function's contract before implementing it — what goes in, what comes
out, what gets raised.
For Tier 1–2 FUNCTION_BODY tasks: generate 2–6 doctests covering the typical
happy path, at least one edge case, and any documented exception.
For Tier 3 FUNCTION_BODY tasks: generate setup inline in the doctest block.
For Tier 4 FUNCTION_BODY tasks: generate doctests only for input validation and
error-raise paths.
For LINE tasks inside a function (Tier 1–3): generate a doctest for the
containing function that exercises the line being completed.
All expected output values must be concrete and deterministic.
Step 7 — Validate doctest structure
Before running anything, verify the doctests are syntactically correct. Check every
doctest block for:
>>> prefix with exactly one space after the arrows
... prefix on continuation lines with exactly one space
- Expected output on the very next line after
>>> — no blank line between them
<BLANKLINE> used wherever expected output contains a blank line
- Exception format exactly:
Traceback (most recent call last): then ... then
ExceptionType: message
- No
... wildcard in expected output unless # doctest: +ELLIPSIS is on the
same >>> line
Fix any formatting problems before proceeding.
Step 8 — Generate first candidate code
Generate the completion using everything gathered in Steps 1–7.
For FUNCTION_BODY tasks: generate the full body, properly indented; stay
consistent with existing imports; honour observed naming and error-handling
patterns; keep consistent with the expected outputs committed to in Step 6; do not
alter the signature or docstring.
For LINE tasks: generate only the remainder of the truncated line, starting at
the exact character position where the prompt ends; no leading whitespace or
newline; end at the natural conclusion of the syntactic construct; do not generate
the next line.
Step 9 — Single validation pass (NO RECOVERY LOOP)
Read single_validation.md now.
Write the candidate code to a temporary file alongside the generated doctests, then
run the doctest runner once:
python run_doctest.py /tmp/completion_candidate.py
Read the structured output and record it: STATUS, how many doctests passed, and
any failure details. That is the entire step.
This variant does NOT:
- diagnose the failure class,
- make a targeted fix,
- re-run the runner,
- iterate up to a maximum number of attempts,
- track a best attempt across iterations.
The first candidate from Step 8 is the delivered code regardless of whether the
single validation pass passed or failed. The runner output is captured as a
reported signal only — it does not change the completion.
For Tier 5 / LINE instances there is no runnable oracle, so the runner is skipped
and only a syntax check (ast.parse / python -c) is performed — same as the full
skill.
Step 10 — Post-generation quality gate
Before delivering anything, verify:
- Does the completion cover only what was missing — no changes to the existing prompt?
- Is indentation consistent throughout (no mixed tabs/spaces, correct depth)?
- For LINE tasks: does the completion attach cleanly to the last character of the
prompt with no spurious leading space or newline?
- Are there syntax errors in the completion?
- Does the completion reference any names not in scope? Flag but do not block.
Block on syntax errors. Flag but proceed on scope warnings.
Step 11 — Inject and deliver
Read injection.md now.
Assemble the final output:
- The original prompt, unchanged
- The completion appended at the correct position
- If
INJECT_DOCTESTS = true: doctests that PASSED the single validation pass
embedded in the docstring. Doctests that FAILED the single pass are replaced with
a TODO comment (a known-failing doctest is never injected).
Deliver in this structure:
task_id: <from metadata>
task_type: FUNCTION_BODY or LINE
status: VALIDATED_PASS (single pass: all doctests passed)
VALIDATED_FAIL (single pass: one or more doctests failed — delivered anyway)
SKIPPED_NO_ORACLE (Tier 5 / LINE — syntax check only)
doctests_passing: <n passing> / <n total generated>
completion: <the generated code only — not the full file>
full_output: <complete prompt + completion with passing doctests embedded>
Then tell the user, in plain language: what tier the function was, how many doctests
were generated, the result of the single validation pass, and — if it failed — what
the failure was (reported, not fixed, since this variant has no recovery loop).
A worked example
Input (function body task): factorial(n), Tier 1.
Step 6 doctests: factorial(0) -> 1, factorial(5) -> 120,
factorial(-1) -> ValueError.
Step 8 candidate:
if n < 0:
raise ValueError("n must be non-negative")
if n == 0:
return 1
return n * factorial(n - 1)
Step 9 (single pass): Runner reports 3/3 passed. Recorded. (Had it reported a
failure, the same candidate would still be delivered — there is no loop to repair it.)
Step 11 output:
task_id: example/1
task_type: FUNCTION_BODY
status: VALIDATED_PASS
doctests_passing: 3 / 3
What this skill does not do
- Run the developer-written ground truth tests
- Modify the function signature or existing docstring prose
- Iterate, diagnose, or repair after the single validation pass (ablated)
- Load repository test files