CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / integration (push) Successful in 57s
CI & Build / Python tests (push) Successful in 1m36s
CI & Build / Build & push image (push) Successful in 14s
A session's go-ahead request sat inside a completion list as "Blocked by the permission check", and the operator read it as a fault rather than a question waiting on them. The reporting-back skill now puts any action held for a yes under a section headed "Approval requested", near the top of whatever reply it is: each change numbered so part can be approved, why it needs them, how it is undone, and what happens after. The Asks table gains an Approval row, and the completion report's "Needs you" points at the section. test_reporting_back_skill pins the heading and the row. Plugin version minted: 2026.09.15.1921. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
66 lines
2.7 KiB
Python
66 lines
2.7 KiB
Python
"""The reporting-back skill keeps its shape (milestone 409 step 2).
|
|
|
|
WHY THIS EXISTS
|
|
|
|
The skill is what turns a reply written in the order the work happened into
|
|
one the operator can read: where the work sits, what changed, what needs
|
|
them, what is next. Its value is in its SECTIONS, and a later tidy-up that
|
|
folds them into prose would leave a skill that still loads and no longer
|
|
shapes anything.
|
|
|
|
WHAT THIS PINS, AND WHAT IT DOES NOT
|
|
|
|
Structure, never wording — the same reason test_create_tools_disambiguate
|
|
gives: a test that punishes rewriting gets deleted. It pins that the
|
|
completion report keeps its five sections, that placement is taken from the
|
|
record rather than recalled, and that the shipped shapes stay domain-neutral.
|
|
Whether the guidance is any good is milestone 409's last step, read against
|
|
real replies, not something a test can see.
|
|
"""
|
|
import pathlib
|
|
import re
|
|
|
|
SKILL = pathlib.Path(__file__).resolve().parents[1] / "plugin/skills/reporting-back/SKILL.md"
|
|
|
|
|
|
def _text() -> str:
|
|
return " ".join(SKILL.read_text().split())
|
|
|
|
|
|
def test_the_skill_names_itself_as_its_directory():
|
|
front = re.search(r"^---\s*\nname:\s*(\S+)", SKILL.read_text())
|
|
assert front and front.group(1) == "reporting-back"
|
|
|
|
|
|
def test_the_completion_report_keeps_its_sections():
|
|
text = _text()
|
|
for section in ("Where this sits", "What now works", "How / why", "Needs you", "Next"):
|
|
assert section in text, f"the completion report lost its {section!r} section"
|
|
|
|
|
|
def test_a_request_for_approval_has_its_own_named_section():
|
|
"""The operator, 2026-09-15 (#4084): a session's go-ahead request sat inside
|
|
a completion list as "Blocked by the permission check", and read as a
|
|
fault rather than a question waiting on them. The heading is what they
|
|
scan for, so it is pinned by name."""
|
|
text = _text()
|
|
assert "Approval requested" in text
|
|
assert "| **Approval**" in text, "the Asks table lost its Approval row"
|
|
|
|
|
|
def test_placement_comes_from_the_record():
|
|
"""The failure this milestone started from: a placement written from memory
|
|
reads exactly like a real one when it is wrong."""
|
|
text = _text().lower()
|
|
assert "placement" in text and "take the placement from the record" in text
|
|
|
|
|
|
def test_the_shipped_shapes_assume_no_particular_domain():
|
|
"""Scribe is domain-neutral: a home-infrastructure or writing project reads
|
|
these too. Software-specific evidence belongs in an operator's own
|
|
preferences, never in the product default."""
|
|
text = _text()
|
|
dev_only = [w for w in (r"\bCI\b", r"\bcommit", r"\bpull request", r"file:line", r"\bpytest\b")
|
|
if re.search(w, text, re.IGNORECASE)]
|
|
assert not dev_only, f"software-only vocabulary in a product-wide shape: {dev_only}"
|