Files
FabledScribe/plugin/skills/reporting-back/SKILL.md
T
bvandeusenandClaude Opus 5 5c6175ad97
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 50s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / Python tests (push) Failing after 1m4s
CI & Build / Build & push image (push) Skipped
feat(placement): a record you only cite carries its status (#4154)
Step 1 made placement cheap for a task whose status CHANGES: create_task
and update_task return where it sits, and the report is written from
that. It did nothing for a task a reply merely cites.

This milestone's own step-6 review reported "#4014 is the open step of
milestone 409". #4014 had been done for four days; the open step was
#4015. The id did not come from a read — it came from a retrieval hint,
which carries an id, a kind and a title and says nothing about status,
while list_milestones said "8 of 9" and would not say which one. The
gap was there to be filled and the nearest-looking id filled it.

Two surfaces, one principle: the status arrives with the id.

1. get_project_milestone_summaries gains next_step — the earliest open
   step, {id, title, status} or None — carried through _BRIEF_FIELDS to
   enter_project, get_project and list_milestones. One extra flat query
   for the whole batch, so #2384's fan-out does not come back.

   OPEN_STEP_STATUSES moves to services/milestones.py and placement.py
   imports it; both surfaces now answer "what is next" and must not
   drift on what counts as open. Both step queries take the same
   readable_notes_clause (rule 78), so a row cannot name a step its own
   progress numbers exclude.

2. _record_kind renders a task's status: [task (done)], [issue (todo)].
   A finished step and an open one read identically before, which is
   exactly the line the misreport was taken from. Only tasks — is_task
   IS status-is-not-None on the model, so there is no fallback branch.

reporting-back gains the practice, owned and registered in the guidance
ownership table: a record you only mention is a record to read.

The guards are structural and each fails on the regression it names:
the query count is asserted rather than the payload shape, and the two
surfaces' agreement is pinned on the rendered ORDER BY, since a mocked
session hands back whatever order the test chose.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
2026-09-18 12:08:00 -04:00

196 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: reporting-back
description: Use when you are about to write the reply the operator will read — work finished, a task marked done, stopping on a blocker, asking them to decide or to do something, answering "where are we" / "what's next", or proposing an approach. Shapes the reply around where the work stands (which task, what changed, what needs them, what comes next) instead of the order you did things in. Triggers on reporting completion, handing off, asking a question, or summarising progress.
---
# Reporting back
Your reply is where the operator finds out what happened. They were not there
while you worked: they don't hold the files you read, the names you used or
the order you did things in. A reply that follows *your* path is accurate and
still unreadable to them. Shape it around **where the work stands**.
Pick the kind of reply first (the tables below). Its sections are **what to
consider including, not a form to complete.**
Two kinds of section, and they behave differently:
- **A section that answers a standing question** — *does anything need me? what
happens next?* — is always answered, even when the answer is nothing.
"**Needs you:** nothing" is what they were looking for.
- **A section that explains** — how it was done, why that way, what else you
noticed — earns its place only when it changes what the operator does or
decides. When it would not, leave it out: that detail belongs in the record's
log, where it is available and not in the way.
**Write the shortest reply that carries the answer.** To someone reading
quickly, length is not thoroughness — it is work handed back to them. A reply
that fills every heading faithfully and runs a full screen is worse than four
lines naming the two things that changed their position. Extra length has to be
earned: a comparison they asked for, options that need laying side by side, a
measurement whose numbers are the point.
## Every reply
- **Conclusion first.** The verdict, the result, or the question — before the
reasoning that supports it.
- **One topic per section.** Two things the operator raised get two sections.
- **Make priority visible.** Bold the few things that matter; let the rest be
plain.
- **End with the ask, in bold** — the one thing they need to decide or do. If
there is nothing, say so.
- **A request for approval gets its own section, headed "Approval requested".**
Whenever you are holding an action until the operator says yes — a permission
prompt their client raised, something hard to undo, a change you have
prepared and not made — put it there, near the top, whatever kind of reply
this is. Inside a progress or completion list it reads as a status line, and
the operator does not see that you are waiting on them.
- **Plain words.** Use the operator's vocabulary, not the names you coined while
working. If a term has to appear, explain it once.
- **Place the work in Scribe.** Name the task, issue or milestone it belongs to,
by id *and* title (using-scribe: "Name the record, never just its number").
- **A decision already made gets acted on, and the reply says what you did with
it.** Once the operator has chosen, that is the input to the work, not a topic
to revisit. If something you have since learned genuinely overturns the
choice, say so once and plainly — name the new evidence and what it changes —
and otherwise let the decision stand. Laying out the trade-offs of a settled
question again reads as contradicting yourself rather than as being careful,
and it costs the operator the decision twice.
## Take the placement from the record
A remembered milestone title or "next step" reads exactly like a real one when
it is wrong. So take placement from Scribe:
- `update_task` and `create_task` return a **`placement`** block — the project,
the milestone, `position` (step N of M), `progress`, and `next` (the next open
step). Use those values as they came back.
- For a wider view, `get_milestone` (a plan and its steps) or `enter_project`
(the whole project). Every milestone they list carries **`next_step`** — the
earliest step still open, or null when none is — so a reply that says what
comes next takes it from the listing it already read. Progress alone says a
plan has an open step and not which one, and that is the gap recall fills.
- **A record you only mention is a record to read.** `placement` rides the
write that changed a task, so a task you cite without touching arrives with
nothing vouching for it. A retrieval hint carries an id, a kind and a title;
where a task stands is in the line's kind marker — `[task (done)]` — and a
line you are working from memory has no marker at all.
- Work with no task behind it: say so plainly — "this wasn't tracked as a
task" — and offer to record it. An honest "untracked" is a placement too.
## The operator's own shapes come first
The shapes below are defaults. An operator may have changed some of them — a
section they always want, an order they read faster, a kind of reply they want
shorter — and those changes are `preference` records. Where a preference and a
default differ, the preference is what they asked for.
- **A completion report brings its preferences with it.** Closing a task with
`update_task` returns them as **`reply_preferences`** when the operator has
any; the `report_back` line says so. Nothing to search for.
- **Every other reply, ask before writing it.** A finding, a decision, a
handoff, a "where are we" — no tool call comes before these, so nothing
hands their preferences over. Once you know which kind of reply you are
writing, `search(content_type="rule")` for it in the words of that moment —
"writing a decision for the operator", "handing off to the operator" — and
follow any preference that comes back. Nothing coming back means the default
shape stands.
## Reports — work happened
| Kind | Sections |
|---|---|
| **Completion** | Where this sits · What now works · How / why · Needs you · Next |
| **Finding** (a problem you found and did not fix) | Symptom · Cause · Size of the fix · **Offer to fix it** |
| **Blocked / failed** | What stopped · What you tried · What you need from them |
| **Progress** (mid-work) | One or two lines: where things are, what's next, any blocker |
| **Where are we** | The milestone and its progress · Done · Open · Needs you · Next |
## Asks — the operator needs to act or decide
| Kind | Sections |
|---|---|
| **Decision** | The question first · 24 options, each with what it changes · recommendation first |
| **Clarification** | "My reading is X · the gap is Y · unless you say otherwise I'll do Z" |
| **Handoff** (only they can do it) | The action · why it needs them · what it unblocks · what you'll do after · any way to skip it |
| **Approval** (you are ready to act and holding for a yes) | **Approval requested:** exactly what happens once they approve, one numbered item per change so they can approve part · why it needs their yes · how it can be undone · what you'll do after |
| **Conflict** (what you're about to do clashes with a rule, a plan or an earlier decision) | What it says · what you were about to do · where they clash · A or B? |
Before asking, check whether you can find the answer yourself — something that
can be read or looked up is a fact to check, not a question to send.
## Answers — the operator asked something
| Kind | Sections |
|---|---|
| **Explanation** | The answer first · then the evidence, pointing at what they could open to check it |
| **Evaluation** ("can we / should we") | Verdict · What exists · The gaps · Recommendation |
## Proposals — shaping future work
| Kind | Sections |
|---|---|
| **Options** | 23 approaches · the trade-off of each · one recommendation |
| **Plan** | Goal · Steps · Open questions — for review before starting (writing-plans) |
| **Review** | Findings ranked by how much they matter, one per item |
## The completion report, in full
The most common reply, and the one most often written in the order the work
happened. The shape:
> **Where this sits:** milestone 12 "Move the backups offsite", step 3 of 5.
> Task #340 "Schedule the nightly sync" is done.
>
> **What now works**
> - The nightly sync runs at 02:00 and copies the photo library to the remote
> store.
>
> **How / why**
> - Used the scheduler the other jobs already use, so there is one place to
> look when a job doesn't run.
> - Verified by running it once by hand and checking the remote copy's size
> matches the source.
>
> **Needs you:** nothing.
>
> **Next:** #341 "Alert when a sync fails". Starting it unless you redirect.
Notes on each section:
- **Where this sits** — from `placement`. If the work isn't under a milestone,
the task alone is enough.
- **What now works** — outcomes the operator would notice: "You can now…",
"X no longer…". The files and steps behind them belong in the task's log.
- **How / why** — only the decisions worth knowing, plus **how it was
verified**. If something could not be verified, say what and why here rather
than letting it read as passed.
- **Needs you** — an action, an approval, a decision, or "nothing". If it's an
action, give the reason with it. An approval you are holding for also gets
its own **Approval requested** section, and this line points at it.
**Two tests, and it takes both: is this theirs to decide, and is work waiting
on it?** A choice that is genuinely theirs — a priority, a trade-off only they
can price, something they have to live with afterwards — belongs here. A
question you could settle by reading something, by taking a measurement you
already have access to, or by choosing the obvious default does not: that is
work not yet done, and sending it moves your uncertainty onto them. Settle it,
say which way you went and why, and leave them free to overrule you. This
section is for what blocks them, not for what you are unsure about.
- **Next** — from `placement.next`, or say the milestone is finished. If you
found something you didn't fix, the offer to fix it goes here.
## Before sending
Read the reply as the operator will: someone who wasn't there, reading
quickly. Can they tell **what was done, whether anything needs them, and what
happens next** without asking a follow-up? If not, the sections are what's
missing — not more detail.
Then read it once more for **what can go**. A section filled because it was in
the table, reasoning supporting a conclusion nobody is going to dispute, a
finding already written to the record — none of it changes what the operator
does, so none of it belongs in the reply. Cutting is not hiding: the log holds
it, and the reply stays readable. A reply that has been cut twice is the one
they can act on.