TASK-115: the read-only report's guards cover both surfaces and the task store - #17
Merged
ranjiao merged 10 commits intoAug 20, 2026
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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-migrateis 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-004and this change must not settle it. The guard banned should/must/refus/chmod/instead/unsafe/warning/error on the rendered note only. Puttingyou should chmod itinto the--jsonplan'sread_only_override.observedleft all ten tests green.test_the_json_wording_states_what_was_observed_toonow checks everyread_only_overridein the plan. Both surfaces read onePOLICY_WORDStuple rather than a copy of the list — a second copy is the same defect class this project keeps hitting, and it is the driftREAD_ONLY_MECHANISMalready exists to prevent for the sentence itself.2 · The task-store path had no test behind it.
_plan_task_storesetsread_only_mode=owner_read_only(store_path). Deleting that line left all ten tests green, and a read-onlytasks.jsonlwould 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) andtest_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
summarykey. 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 whattest_a_file_left_byte_identical_is_not_reported_as_overriddenpins.Mutation results — all six die
you should chmod itintoread_only_override.observedtest_the_json_wording_states_what_was_observed_tooread_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_rewrittenand self.writabletest_a_file_left_byte_identical_is_not_reported_as_overriddentest_a_project_with_no_such_file_reads_exactly_as_it_did_beforetest_the_wording_states_what_was_observed_not_what_should_happentest_the_applied_run_names_it_in_the_same_placeThe 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 sharedPOLICY_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 plustest_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-004and 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