From ef9f0380da70aeb2d6b1040add464a97095c5c30 Mon Sep 17 00:00:00 2001 From: quill Date: Sat, 24 Oct 2026 16:15:33 +0000 Subject: [PATCH] quill: add issue-to-draft brief and retry_decorator sample --- wizard-work/quill/issue-to-draft-brief.md | 56 +++++++++++++++++++++++ wizard-work/quill/retry_decorator.py | 35 ++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 wizard-work/quill/issue-to-draft-brief.md create mode 100644 wizard-work/quill/retry_decorator.py diff --git a/wizard-work/quill/issue-to-draft-brief.md b/wizard-work/quill/issue-to-draft-brief.md new file mode 100644 index 0000000..de52735 --- /dev/null +++ b/wizard-work/quill/issue-to-draft-brief.md @@ -0,0 +1,56 @@ +# Issue-to-Draft Brief + +A reusable template that converts a structured issue spec into a ready-to-run task brief for a Draft-lane agent. + +## Input Contract +- **issue_id**: str +- **title**: str +- **acceptance_criteria**: list[str] +- **constraints**: list[str] (optional) +- **context**: str (optional) + +## Output Contract +A single markdown file containing: +1. Goal (1 sentence) +2. Scope (bullets from acceptance criteria) +3. Constraints (bullets, or "none") +4. Artifact path (where the deliverable lives) +5. Verdict template (one-line + CHECK command) + +## Rules +- No filler, no hedging. +- Plain claims over adjectives. +- If a claim is unmeasured, mark it `[CLAIMED]`. +- End with `VERDICT:` line and `CHECK:` line (exit code 0 = correct). + +## Sample Filled Brief + +**Input:** +- issue_id: DRAFT-7 +- title: Add retry decorator to http client +- acceptance_criteria: + - decorator retries 3x on 5xx + - exponential backoff capped at 5s + - type hints present +- constraints: stdlib only, <80 LOC +- context: replaces ad-hoc retry loop in main.py + +**Output:** + +GOAL: Add a stdlib-only retry decorator for 5xx errors with 3 attempts and exponential backoff capped at 5 seconds. + +SCOPE: +- Decorator with 3-attempt retry on 5xx +- Exponential backoff (1s, 2s, 5s cap) +- Type hints on all public callables +- Remove ad-hoc retry loop from main.py + +CONSTRAINTS: +- stdlib only +- <80 LOC + +ARTIFACT: /root/.hermes/wizard-outputs/quill/retry_decorator.py + +VERDICT: Decorator implemented, tested, and under 80 LOC. + +CHECK: python /root/.hermes/wizard-outputs/quill/verify.py diff --git a/wizard-work/quill/retry_decorator.py b/wizard-work/quill/retry_decorator.py new file mode 100644 index 0000000..4e985dc --- /dev/null +++ b/wizard-work/quill/retry_decorator.py @@ -0,0 +1,35 @@ +"""Stdlib-only retry decorator for 5xx errors. + +Exponential backoff: 1s, 2s, 5s cap. 3 attempts max. +Type hints on all public callables. <80 LOC. +""" +import time +import functools +from typing import TypeVar, Callable, ParamSpec + +P = ParamSpec("P") +R = TypeVar("R") + + +def retry_on_5xx(max_attempts: int = 3, base_delay: float = 1.0, cap: float = 5.0) -> Callable[[Callable[P, R]], Callable[P, R]]: + """Decorator: retry wrapped callable on 5xx up to max_attempts times.""" + def decorator(func: Callable[P, R]) -> Callable[P, R]: + @functools.wraps(func) + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: + delay = base_delay + last_exc: BaseException | None = None + for attempt in range(1, max_attempts + 1): + try: + return func(*args, **kwargs) + except Exception as exc: + last_exc = exc + status = getattr(exc, "status", None) + if not (isinstance(status, int) and 500 <= status < 600): + raise + if attempt == max_attempts: + break + time.sleep(delay) + delay = min(delay * 2, cap) + raise last_exc # type: ignore[misc] + return wrapper + return decorator