Skip to content

TASK-115: the read-only report's guards cover both surfaces and the task store - #17

Merged
ranjiao merged 10 commits into
feat/work-modesfrom
coding/task-115-readonly-guard-coverage
Aug 20, 2026
Merged

TASK-115: the read-only report's guards cover both surfaces and the task store#17
ranjiao merged 10 commits into
feat/work-modesfrom
coding/task-115-readonly-guard-coverage

Conversation

@ranjiao

@ranjiao ranjiao commented Aug 20, 2026

Copy link
Copy Markdown
Owner

What this is

TASK-079 shipped ten new tests, all green, and a fresh-context V4 reviewer scored every deliverable MET. Two holes were invisible to all of that — they surfaced only when the reviewer mutated the production code and watched which tests failed. Five of six mutations were caught; these two were not.

Nothing was broken. What shipped is correct. What was missing is the guard that keeps it correct, so the measure here is not "the tests pass" — it is "the mutation that survived now dies".

No production code changed. bin/perry-migrate is untouched; the guard needed no seam.

The two holes

1 · The wording guard did not cover the machine-readable plan. TASK-079's deliverable 4 requires the emitted wording to state what was observed, not what should happen — the refuse-versus-report policy is USER-004 and this change must not settle it. The guard banned should/must/refus/chmod/instead/unsafe/warning/error on the rendered note only. Putting you should chmod it into the --json plan's read_only_override.observed left all ten tests green.

test_the_json_wording_states_what_was_observed_too now checks every read_only_override in the plan. Both surfaces read one POLICY_WORDS tuple rather than a copy of the list — a second copy is the same defect class this project keeps hitting, and it is the drift READ_ONLY_MECHANISM already exists to prevent for the sentence itself.

2 · The task-store path had no test behind it. _plan_task_store sets read_only_mode=owner_read_only(store_path). Deleting that line left all ten tests green, and a read-only tasks.jsonl would have silently lost its report. It is in the per-file list, so it is inside deliverable 1, and it was the only reported file with nothing standing behind it.

Two tests now stand there: test_the_read_only_task_store_is_reported_in_both_surfaces (the note and the JSON) and test_the_task_store_it_names_was_in_fact_rewritten (asserted on the bytes — a note about an override that did not happen would be a worse defect than the silence it replaced).

The fixture writes the store with the shipped writer, then ages it back to how a pre-TASK-106 Perry left it — no summary key. The record stays valid and projects identically to the board, so nothing is refused, and migration has a canonical rewrite to plan. Without a rewrite waiting there is no override to report, which is what test_a_file_left_byte_identical_is_not_reported_as_overridden pins.

Mutation results — all six die

Mutation Test(s) that fail
you should chmod it into read_only_override.observed test_the_json_wording_states_what_was_observed_too
delete read_only_mode=owner_read_only(store_path) test_the_read_only_task_store_is_reported_in_both_surfaces, test_the_task_store_it_names_was_in_fact_rewritten
drop and self.writable test_a_file_left_byte_identical_is_not_reported_as_overridden
report every file 4 tests, incl. test_a_project_with_no_such_file_reads_exactly_as_it_did_before
policy word in the rendered note test_the_wording_states_what_was_observed_not_what_should_happen
dry-run only 3 tests, incl. test_the_applied_run_names_it_in_the_same_place

The last four were re-run to confirm this change does not trade one hole for another.

Verification

  • tests/test_migrate.py: 130 → 133, green before and after. The class went 10 → 13; none of the ten was weakened — test_the_wording_... now reads the shared POLICY_WORDS, same words.
  • python3 tests/parallel: 1846 → 1849 tests. Same 3 red modules before and after — test_diagnose, test_one_line_break_rule, test_v5_signoff — none mine, all pre-existing on this branch.
  • bash tests/run: those three plus test_host_support, the documented shared-cache flake.
  • python3 bin/perry-lint: 0 errors. git diff --check: clean.

Out of scope

The read-only policy itself. Whether migration should refuse such a file is USER-004 and stays unanswered — no refusal is implemented, and no policy word was let into either surface while adding the guard against policy words.

🤖 Generated with Claude Code

ranjiao and others added 10 commits August 20, 2026 16:14
PR #6's conflicts were a wrong base, not a code conflict: it targeted main,
which trails this branch by ~280 commits. The day's first dispatch prompt did
not name a base branch. Verified zero code conflict before touching anything.

TASK-092 dispatched — the chain head that gates nine rows including both P0s.
It became dispatchable the moment the blank-marker fix was committed, because
that fix is in the exact module the row extends.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
USER-003 spent two days reported as a person waiting, for a decision the user
had already made the day it was minted. Nothing reconciles a USER- row against
an ADR that answers it.

TASK-070 split rather than cleared: TASK-110 measures and proposes, TASK-070
keeps the execute half. Re-measurement moved it P2 -> P1 — Perry's own state is
31.3% of tracked bytes now, and evidence/ grew 5.6x in two days.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three findings, increasing in severity: PR #12's CI red is the branch base, not
the change; a test reads two files outside the repository and is therefore green
here and red on CI forever; and main carries a stale second implementation of
the NS-01 change that PR #13 reverts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three checks went red on ordinary progress, all one defect class: a test that
reads the project living around it. One of them is self-referential — writing
that REL-00 was gone, inside a signed V5 record, is what brought it back.

TASK-114 is delegated rather than dispatched: aiMark is another repository and
the work is a version catch-up, deliberately not the architecture change its
KR eventually wants.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both V4 reviews were run by fresh-context agents that scored the written rubric
without the author's RESULT block, and both ran mutation batteries rather than
only re-running the suite. Between them they found six coverage gaps no passing
test would have shown: TASK-115 and TASK-116.

TASK-108's review found a test that breaks when someone writes a design
document, which is the same class TASK-113 is fixing right now and worse than
its three. Handed to that agent mid-run.

TASK-110's proposal argues against itself: the whole thing recovers 1.4 days of
growth, once, and the obvious rotation candidate holds 12% of the bytes.
TASK-117 and TASK-118 are the two defects it found in passing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
TASK-079 shipped ten green tests and a fresh-context V4 scored every
deliverable MET. Mutating the production code found two the suite could
not see.

1. The wording guard read the rendered note only. Injecting `you should
   chmod it` into the `--json` plan's `read_only_override.observed` left
   all ten green — a policy word could enter through the machine surface
   while USER-004 is still open. The guard now covers every override in
   the plan, against ONE `POLICY_WORDS` list both surfaces read, because
   a second copy is a second thing to forget.

2. `tasks.jsonl` is in the per-file list and had nothing behind it.
   Deleting `read_only_mode=owner_read_only(store_path)` from
   `_plan_task_store` left all ten green, and a read-only store would
   have lost its report in silence. Two tests now stand there: one for
   the note in both surfaces, one pinning that the file it names was in
   fact rewritten and its mode left as found.

No production code changed — the behaviour was already correct; only the
guard that keeps it correct was missing.

All six of the reviewer's mutations now die: the two above, plus
dropping `and self.writable`, reporting every file, a policy word in the
rendered note, and reporting on the dry run only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ranjiao
ranjiao merged commit 4951101 into feat/work-modes Aug 20, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant