165 lines
6.5 KiB
Markdown
165 lines
6.5 KiB
Markdown
# issue-template.md — the issue body contract
|
|
|
|
The shape of every issue this plugin causes to be filed on a **target plugin's
|
|
own repo** (output path A, `design/plan.md` §10, FR-6). Loaded at runtime by
|
|
`bin/filing-plan`, which renders it; it is kept here rather than in the script
|
|
body so that a change to what an issue says is a reviewable diff.
|
|
|
|
Format is the same as `signals-catalog.md`: each `## <section>` heading below is
|
|
followed by **exactly one fenced block**, and the fenced block is the only part
|
|
the parser reads. Prose outside the fences is for humans.
|
|
|
|
Placeholders are `{{name}}`. Every placeholder in a template must be supplied —
|
|
`filing-plan` fails loudly on an unknown or missing one rather than rendering a
|
|
half-filled issue.
|
|
|
|
## Who decides what
|
|
|
|
`filing-plan` renders the **body**, because the body is the contract: the marker,
|
|
the measurement, the rubric verdict, and the falsifiability triple are all
|
|
already-computed values and rendering them is a `pure-script` step.
|
|
|
|
It does **not** decide where the issue goes. Repo, final title, labels beyond
|
|
`token-offload`, and milestone are `anxious:issuer-agent`'s call, per its own
|
|
taxonomy. The `issue-title` section below is a *proposal* passed to `issuer`,
|
|
not an instruction.
|
|
|
|
## The marker is load-bearing
|
|
|
|
The first line of every body — and of every update comment — is
|
|
|
|
```text
|
|
<!-- ia-candidate: <candidate_id> -->
|
|
```
|
|
|
|
It is how a re-run recognizes its own prior work (FR-6.3). It renders invisible
|
|
in Gitea, is stable across runs because `candidate_id` is, and must never be
|
|
edited by hand on a filed issue. Removing it from an issue causes the next audit
|
|
to file a duplicate — which the spec names as the single most likely way for
|
|
this plugin to become hated.
|
|
|
|
## issue-title
|
|
|
|
A proposal. `issuer` may rewrite it.
|
|
|
|
```text
|
|
token-offload: {{headline}} ({{skill}})
|
|
```
|
|
|
|
## issue-body
|
|
|
|
`{{examples}}` renders as a markdown list, one input→output pair per line, with
|
|
the edge case marked. `{{determinism_tests}}` renders as `T1 ✓ T2 ✓ …`, using ✗
|
|
for a failed test. `{{evidence}}` always renders — it states whether the cost
|
|
claim is `measured`, `thin`, or `unmeasured`, so a reader never has to guess
|
|
whether the number is evidence or arithmetic.
|
|
|
|
```markdown
|
|
<!-- ia-candidate: {{candidate_id}} -->
|
|
|
|
**Measured cost.** {{measured_cost}}
|
|
|
|
**Evidence strength.** {{evidence}}
|
|
|
|
**Boundary position.** {{position}} — confidence {{boundary_confidence}}.
|
|
Determinism tests: {{determinism_tests}}
|
|
|
|
**Proposed signature.**
|
|
`{{signature}}`
|
|
|
|
**Examples.**
|
|
|
|
{{examples}}
|
|
|
|
**When a human would overrule this.** {{overrule_case}}
|
|
|
|
**Escalation path.** {{escalation_path}}
|
|
|
|
**What crosses the boundary.** {{digest_schema}}
|
|
|
|
---
|
|
|
|
This is a proposal from an audit, not an accepted design. It is deliberately
|
|
falsifiable: if the overrule case above is *common*, the cut belongs earlier in
|
|
the pipeline than proposed, and this issue should be reshaped rather than
|
|
implemented. Closing this as `wontfix` is a useful outcome and is tracked as a
|
|
calibration signal.
|
|
|
|
Audit: `{{audit_page}}` on the {{wiki_repo}} wiki. Rubric v{{rubric_version}}.
|
|
```
|
|
|
|
## update-comment
|
|
|
|
Posted instead of a new issue when the marker is already present on the repo
|
|
(FR-6.3). It carries the marker again so that the search finds this issue
|
|
whether the marker lives in the body or only in a comment.
|
|
|
|
```markdown
|
|
<!-- ia-candidate: {{candidate_id}} -->
|
|
|
|
**Re-measured {{run_date}}** — window {{window}}. Status: {{status}}.
|
|
|
|
{{measured_cost}}
|
|
|
|
Evidence strength: {{evidence}}
|
|
|
|
Boundary position {{position}}, confidence {{boundary_confidence}} (rubric
|
|
v{{rubric_version}}).
|
|
|
|
Audit: `{{audit_page}}` on the {{wiki_repo}} wiki.
|
|
```
|
|
|
|
## marker-search
|
|
|
|
How the pre-filing search is actually performed (FR-6.3). This is not
|
|
hand-waved: both queries below run against the **target** repo, through
|
|
`anxious:issuer-agent` → `cluster:gitea-agent`, and their merged results are
|
|
what `filing-plan plan --existing` consumes.
|
|
|
|
**Three steps, not one.** The obvious one-query design does not work, and the
|
|
reason was established empirically against the live Gitea (2026-07-29, probe
|
|
issue `kotkan/claude-plugin-inference-arbitrage#9`, since closed):
|
|
|
|
> **Neither `search_issues` nor `list_issues` returns the issue `body`.** Both
|
|
> return metadata only — number, title, state, labels, timestamps. A marker
|
|
> match therefore *cannot* be made from a search result. The body must be
|
|
> fetched per issue with `issue_read(method="get")`, and comments with
|
|
> `issue_read(method="get_comments")`.
|
|
|
|
Also established by the same probe: `search_issues` **does** full-text match on
|
|
body content, including text inside an HTML comment (a query for a string that
|
|
appeared only in the body, never in the title, returned the issue). So the
|
|
full-text path works — it just cannot be trusted to *confirm* a match, only to
|
|
suggest one.
|
|
|
|
```text
|
|
1. candidates list_issues(owner, repo, labels=["token-offload"], state="all")
|
|
search_issues(query="ia-candidate: <candidate_id>", owner, state="all")
|
|
-> union of issue numbers; bodies are NOT in these responses
|
|
2. fetch issue_read(method="get", index=N) -> body
|
|
issue_read(method="get_comments", index=N) -> comment bodies
|
|
(comments only needed when the body has no marker)
|
|
3. match filing-plan plan --existing <merged.json> -> local literal match
|
|
```
|
|
|
|
Step 1's label scan is the authoritative half: every issue this plugin files
|
|
carries `token-offload`, so it is a bounded, exact superset of the issues that
|
|
can carry a marker. The full-text query is the safety net for an issue whose
|
|
label a human removed. Step 3's match is a literal string comparison and is the
|
|
only thing that decides identity — the search engine never does.
|
|
|
|
If step 1 finds no `token-offload` label on the target repo, that is the
|
|
first-audit case: there are no prior issues, `issuer` creates the label with the
|
|
first filing, and the empty result is correct.
|
|
|
|
The merged shape handed to `--existing` is a JSON array of
|
|
`{number, state, title, body, comments: [...]}`. `filing-plan` matches
|
|
`<!--\s*ia-candidate:\s*<id>\s*-->` against the body **and each comment**, so an
|
|
issue keeps its identity even if a human rewrites the body entirely, as long as
|
|
one update comment survives — also verified against the live probe issue.
|
|
|
|
**`--existing` is mandatory, even when empty.** `filing-plan plan` refuses to
|
|
run without it rather than defaulting to "nothing exists", because that default
|
|
turns a failed search into a duplicate-filing spree — the exact outcome FR-6.3
|
|
exists to prevent.
|