Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .claude/agent-memory/atomic-planner/MEMORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Preflight revision seams (per issue; newest first)

- [#953 R3](project_953_r3_grep_gitignore_directory_path_and_measured_line_lengths.md) — Grep honours .gitignore for a DIRECTORY path (root+glob over artifacts/ returns nothing; pass the absolute file path), Glob does not; a `none` outcome needs its positive control in the same task; measure line lengths with `^.{N,}` probes, never estimate; leading `<` in a pattern works
- [#953 R2](project_953_r2_grep_long_line_omission_and_cr_anchor_seams.md) — Grep tool omits lines over ~500 chars (JUnit read needs `-n` + Read offset/limit); ripgrep `$` fails before CR (`\r?$` on executor-written files); "before Phase 1" wrong when tests are authored in P1 (anchor to task ids); expect-fail needs a wrong-reason branch keyed to `Expected `/`, but got `
- [#953 R1](project_953_r1_pwsh_refused_and_count_recheck_seams.md) — Bash guard refuses pwsh (od/rm fallbacks, `git -C <root>`, absolute operands); re-count `-A 1` blocks per file (16 not 17); Glob hash-set folders (14 not 13); `-Force` count-0 self-hits the module comment; `-o` must extend past `Version=`; `'*packages.config'` pathspec; `[AllowEmptyString()]` on Mandatory `[string[]]`; ls-files --eol fields space-padded
- [#953 R0](project_953_fizzler_redirect_sweep_and_ratchet_plan_seams.md) — ripgrep strips the BOM (zero-hit Grep inconclusive); text=auto hides CRLF loss from git diff (gate `git ls-files --eol` w/ column); shared attribute string on a sibling block needs a two-line Edit; banned double quotes push the JUnit read onto Read/Grep with delete-before freshness
- [#956 R1](project_956_r1_spec_self_hit_and_raw_doc_name_seams.md) — spec-wording counts self-hit the AC line; `cobertura` substring matches tracked agent-memory .md (anchor `cobertura[^/]*\.xml$`); orchestrator-amended AC needs a P0 literal check
- [#952 R3](project_952_r3_shared_origin_main_ancestry_gate_seam.md) — origin/main is one ref shared by all worktrees: a no-fetch plan still needs a P0 `merge-base == BASE-SHA` gate (`BASE AHEAD OF BRANCH`) beside the late `BASE REF MOVED`; "never fetches so the ref does not move" is false prose
- [#952 R2](project_952_r2_label_counts_helper_enumeration_and_hex_backslash_seams.md) — recount every `all N required` label (observations are not conditions); a Pester helper enumerating a directory is a read site for every file in it; keyed ExpectedExitCode must state its OMITTED branch; backslash in a plan Grep as `\x5C` with `(^|[^A-Za-z])` so `https://` is excluded; line counts via Grep `^` count never Read rows
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: project-953-fizzler-redirect-sweep-and-ratchet-plan-seams
description: "#953 R0 minimal-audit plan seams - ripgrep strips a UTF-8 BOM so a Grep for BOM bytes is inconclusive; .gitattributes text=auto hides a CRLF-to-LF rewrite from git diff (use git ls-files --eol w/ column); a shared attribute string on a sibling block defeats single-line replace; directive-banned double quotes in pwsh -Command pushed the JUnit read onto Read/Grep tools with delete-before freshness; multiline Grep name+newVersion count re-measures a known-debt table in one call per row"
metadata:
type: project
---

Seams re-derived while authoring the issue #953 plan (Fizzler redirect sweep plus a Pester ratchet detector) in worktree `.claude/worktrees/agent-a5292122c820774d3` on 2026-10-02, revision round 0. 47 tasks, 3 phases, no commits.

**Why:** each one either made a caller-supplied verification instruction unobservable with the tools available, or would have drawn a preflight finding.

**How to apply:** re-check before planning any app.config or other CRLF-and-BOM file edit, any PowerShell plan where the delegation bans double quotes in `pwsh -Command`, or any ratchet test keyed to a measured table.

1. **ripgrep strips a UTF-8 BOM before matching.** Grep patterns `^\x{FEFF}` and `(?-u)^\xEF\xBB\xBF` both returned zero matches over 17 files the orchestrator had verified carry a BOM. A zero-hit Grep for the BOM is therefore inconclusive, never evidence of absence. Observe a BOM with `git diff --numstat <BASE> -- <path>` (a lost BOM alters line 1, so a one-line edit reads `2 2` instead of `1 1`) or with a byte read: `pwsh -NoProfile -Command '(Get-Content -LiteralPath <path> -AsByteStream -TotalCount 3) -join [char]44'` prints `239,187,191` and contains no double quote.
2. **`.gitattributes` `* text=auto` makes a CRLF-to-LF rewrite invisible to `git diff`.** git normalises the working-tree text before comparing, so numstat `1 1` does not prove terminators survived. The working-tree observation is `git ls-files --eol -- <path>`: gate the second field (`w/crlf` passes; `w/lf`, `w/mixed` fail) and record the `i/` field without gating it, because whether the index blob was normalised depends on when the file was first committed.
3. **A shared attribute string on a sibling block defeats a single-line replace.** `oldVersion="0.0.0.0-1.3.0.0" newVersion="1.3.0.0"` sits on the Fizzler block in 11 configs and also on the System.ClientModel block in six of them (17 occurrences). The Edit tool needs a unique old_string, so include the preceding `assemblyIdentity name="..."` line in a two-line old_string, and verify afterwards that the sibling block is unchanged by a scoped `-A 1` Grep on the sibling name.
4. **When the delegation bans double quotes inside `pwsh -Command`, do not fight the quoting.** The repo's proven `CMD-JUNIT-READ` one-liner (issue 929 plan) needs inner double quotes. Replace it with tool reads over `artifacts/pester/pester-junit.xml`: Grep `<testsuites ` for the root counts, `<testsuite ` for per-file counts (transcribe the leaf of the absolute-path name attribute only), and `status="Failed"` with `-A 2` for failing testcase names and `failure` messages. Replace the timestamp freshness guard with delete-before: `pwsh -NoProfile -Command 'Remove-Item -LiteralPath artifacts/pester/pester-junit.xml -ErrorAction SilentlyContinue'` plus a Glob that must return nothing before the MCP call and the file afterwards.
5. **Formatter no-rewrite observation that sees untracked files.** `git status --porcelain` over a folder reports a new file as `??` whether or not the formatter rewrote it. Use `git hash-object <path>` over every PowerShell file in the scan folders before and after `run_poshqc_format` (works on untracked files) and gate on identical hash sets.
6. **Re-measure a known-debt table with one multiline Grep per row.** Pattern `name="<escaped>"[^\n]*\n[^\n]*newVersion="<escaped version>"` in count mode with `multiline: true` returns the per-file hit list for that (assembly, version) pair in one call; pair it with a `-o` Grep of `Include="<name>, Version=` over the csproj set for the Reference side. The 15 rows for #953 re-derived to 137 entries; `<bindingRedirect` and `assemblyIdentity name=` both count 1176, so every block carries a redirect and the detector's examined count can be compared to an independent element count inside the test itself.
7. **Hook versus directive on the PREFLIGHT line.** The delegation said "do NOT emit a PREFLIGHT signal", while `.claude/hooks/validate-planner-output.ps1` lines 148-151 and 372-374 block the turn unless exactly one `PREFLIGHT: ALL CLEAR|REVISIONS REQUIRED` line follows the review header. Emit `PREFLIGHT: REVISIONS REQUIRED` as the bounding line with the qualifier on adjacent lines and record the conflict in the plan's residual risks; the heading regex at line 238 now uses the em dash.
8. **Verified tree facts (re-derive before reuse):** 17 app.config at root level, every one with CR count equal to line count; 18 csproj; Fizzler blocks 13 (11 stale, SVGControl and UtilitiesCS correct); Unsafe 17 at 6.0.3.0; `scripts/powershell/` absent (the rule's pester.runsettings.psd1 path is a bundled extension resource); `artifacts/` ignored at `.gitignore:57`; `enforce-powershell-batch-budget.ps1` caps at lines 10-11 with override variables `CLAUDE_POWERSHELL_BUDGET_PROD`/`_TEST` at 37-40.

Related: [[project_945_sortemail_trysave_directory_seam_plan_seams]] (no-commit two-dot gates), [[powershell-gate-observables]], [[reference_poshqc_mcp_measurement_limits]], [[validate-planner-output-hook-line-anchored-gotchas]], [[porcelain-collapses-untracked-directories]].
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: project-953-r1-pwsh-refused-and-count-recheck-seams
description: "#953 R1 preflight deltas - the Bash isolation guard refuses pwsh so every pwsh one-liner needs an od/rm fallback and git -C <root>; a -A 1 block count must be re-derived per file (one app.config carried no block); Glob counts over two folders must be re-run not recalled; a count-0 gate on a token the module's own comment repeats cannot pass; -o on a pattern ending at Version= prints no version; 'packages.config' pathspec is root-only; Mandatory [string[]] needs [AllowEmptyString()] for empty elements; git ls-files --eol fields are space-padded with one tab before the path"
metadata:
type: project
---

Round 1 preflight deltas on the issue #953 plan (worktree `.claude/worktrees/agent-a5292122c820774d3`, 2026-10-02). Eleven defects, no task-count change (47). Each one was a figure or command shape I carried forward from the orchestrator's directive or from reasoning instead of observing it in this worktree.

**Why:** every delta was detectable before handoff by one Grep, one Glob, or one read of the tool's actual output.

**How to apply:** before any handoff, re-run every census count the plan asserts (per file, not from the directive), and for every shell command either observe its success-case output or write the fallback the executor will need when the Bash tool refuses the binary.

1. **pwsh is refused by the Bash worktree-isolation guard, in one-liner form too.** `od -A n -t u1 -N 3 <abs path>` prints ` 239 187 191` for a BOM file, `rm -f <abs path>` exits 0, `git -C <root> ...` runs. Write the fallback into the CMD definition, make every file operand absolute (`<execution-worktree-root>/<path>`), state in C5 that every `git` is `git -C <execution-worktree-root>`, and have the executor record `PWSH-REFUSED: <tool message>` so the fallback is not a deviation.
2. **A `-A 1` block census must be counted per file.** `name="System.ClientModel"` over `*/app.config` gives 16 blocks (6 at 1.3.0.0, 10 at 1.16.0.0); SVGControl/app.config (23 lines) carries none. I had written 17/11 by assuming every one of the 17 configs carried the block. The shared-string count (17 = 11 Fizzler + 6 ClientModel) was right and is a different figure; search the plan for both when correcting one.
3. **Glob the hash-set folders; do not recall the count.** `scripts/dependencies` has 6 `.ps1/.psm1` and `tests/scripts/dependencies` 8 (14, 16 after two new files); I wrote 13/15.
4. **A count-0 gate on `-Force` fails on the module's own comment** that explains why `-Force` is omitted. Gate the statement line instead: `^Import-Module ` count 1 and `^Import-Module .*Force` count 0.
5. **`-o` on a pattern that ends at `Version=` prints no version.** Extend the pattern through the value (`Version=[^,"]+`) so the printed match carries the figure the gate asserts. Multiline count mode reports one count per file: assert "N files, each count 1" rather than a bare total.
6. **`git ls-files --eol` output is `i/lf w/crlf attr/text=auto<TAB>path`** - the three fields are space-padded, only the path is tab-preceded. Describe the gate as "second whitespace-separated field", not tab fields.
7. **Pathspec `'packages.config'` matches only the repository root.** Use `'*packages.config'` (git pathspec `*` crosses `/`).
8. **Mandatory `[string[]]` rejects an empty element at binding** unless `[AllowEmptyString()]` is present, so help text claiming "the parser rejects empty text" is false without it. Add the attribute and state the real two-step behaviour; cite the parser's own test (PackageGraph.Tests.ps1 line 268) instead of adding an It that would shift every test-count gate.
9. **Pin the test-file import form.** The repo form is `Import-Module (Join-Path $script:RepoRoot '<module>') -Force` (RepositoryTreeConsistency.Tests.ps1 line 5); quote the exact two lines in the spec and gate them with anchored patterns, and require BeforeAll fixtures to be `$script:` variables.
10. **Ratchet drift must be detectable at fail-before, not after all edits.** Pester renders `Should -Be` failures as `Expected ..., because <text>, but got ...`, so a `-Because` that appends `observed: <sorted list -join '; '>` lets the fail-before task gate the exact 16-entry list between `observed: ` and `, but got`.
11. **A repository-level ratchet test is not an edge test for the helper it calls.** Map each exported function to its own It numbers (10 positive, 11 negative, 12 edge), not to the integration test.
12. **Coverage Evidence Contract exception must be named where the figures would sit.** When no local coverage route instruments the folder, cite the design decision (D8) in the baseline test task and the handoff task with a literal line stating the exception and the reason.

Related: [[project-953-fizzler-redirect-sweep-and-ratchet-plan-seams]] (round 0 seams), [[project_pwsh_refused_in_isolated_worktree_agents]], [[powershell-gate-observables]], [[verify-line-spans-and-computed-literals]].
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
name: project-953-r2-grep-long-line-omission-and-cr-anchor-seams
description: "#953 R2 preflight deltas - the Grep tool replaces any output line over about 500 characters with [Omitted long matching line], so a JUnit read via Grep -A 2 cannot transcribe Pester failure messages (use -n for the line number, then Read with offset/limit; Read returns a 3,000-character line in full); ripgrep's $ does not match before a carriage return so end-of-line gates over executor-written files need \\r?$; 'before Phase 1' is wrong when the test is authored inside Phase 1 (anchor to task ids); an expect-fail task needs a wrong-reason branch keyed to the message shape"
metadata:
type: project
---

Round 2 preflight deltas on the issue #953 plan (worktree `.claude/worktrees/agent-a5292122c820774d3`, 2026-10-02). Four defects plus one advisory, no task-count change (47).

**Why:** each one is a tool-behaviour or wording fact that reading the plan could not reveal; the reviewer found them by running the Grep tool over the plan itself and by tracing where the tests are authored.

**How to apply:** before any plan that transcribes figures from a long-line XML document (JUnit, TRX, Cobertura) with the Grep tool, and before any `$`-anchored gate over a file the executor writes.

1. **The Grep tool omits long lines.** Any output line longer than about 500 characters is replaced with `[Omitted long matching line]` (match) or `[Omitted long context line]` (`-A`/`-B` context). The line number from `-n` survives. A Pester JUnit `testsuite` line carries the absolute test-file path twice and a `failure` line carrying a `-Because` list runs to 1,700 characters, so a Grep-only CMD-JUNIT-READ cannot transcribe them. Pattern: Grep with `-n` for the line number, then the Read tool with `offset` equal to that line number and `limit` 1 (or 3 to span testcase plus failure child); the Read tool returned a 3,000-character plan line in full. Observe it with Grep pattern `^.{500,}` over any file.
2. **ripgrep `$` does not match before a carriage return.** A gate such as `... -Force$` fails on a CRLF file even when the content is right. On a file the executor writes (new .psm1/.Tests.ps1) whose terminator the plan does not pin, write `\r?$`. Check tracked targets instead of changing them blindly: issue.md was LF (Grep `\r$` count 0) so its `^## Acceptance Criteria$` gate was left alone and the check recorded.
3. **Name the task position, not the phase, for fail-before/pass-after prose.** "red before Phase 1" was false because the regression tests are authored at P1-T2 inside Phase 1; the accurate form is "red at P1-T3, before the config edits P1-T4 to P1-T14, and green at P1-T15". Grep the whole plan for the phrase; it sat in section 7 and twice in section 9.
4. **An expect-fail task needs a wrong-reason branch.** A test that fails with an exception or StrictMode error instead of the expected assertion still yields `failures=1`. Gate the message shape (Pester `Should` failures begin `Expected ` and contain `, but got `) and route anything else to "defect in a new file, fix and re-run as `.iter<N>`".
5. **A parenthetical list in a CITATION is itself a count claim.** The VBFunctions.Test citation listed the other 1.16.0.0 ClientModel configs and omitted UtilitiesCS 107-108 while claiming "10 blocks"; re-enumerate every member when the line is touched.
6. **Plan self-references to line numbers go stale.** When citing the long-line observation, name the CMD definitions and section-9 tests the lines hold, plus the Grep that reproduces it, rather than only the line numbers.

Related: [[project-953-r1-pwsh-refused-and-count-recheck-seams]], [[project-953-fizzler-redirect-sweep-and-ratchet-plan-seams]], [[powershell-gate-observables]], [[verify-line-spans-and-computed-literals]].
Loading
Loading