Repository navigation
docs(plans): make the review-v2 remediation plan executable - #206
Conversation
Maintainer-accepted refinements to the 2026-10-04 plan (the analysis is untouched, per the analyses immutability rule): - §0.1 must-do set (cut line): A1–A6, A8, D1, D2, B1, F1 item 1. - §0.2 decision batch: every [decision] with a recommendation and a one-line reason; options the plan left open are marked (new). - One issue per PR group (with a row checklist) instead of per row. - E1 split into E1a (editorial, day 1) and E1b (decisions). - A2 option (i): the PR's MATLAB artifact supplies canonical bytes; the generator checks out the PR head SHA; the provenance check becomes "real commit" because ancestry breaks under squash/rebase merges. - A6: full-clone confirmation of the 1e-2 history; local MATLAB route. - §10 trimmed to the facts the per-item table relies on; ci-main made conditional on the A2 decision. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pdlourenco
left a comment
There was a problem hiding this comment.
Review of PR #206 — docs(plans): make the review-v2 remediation plan executable
Posted as a comment review because this session's GitHub identity is the PR author, so GitHub does not allow a "request changes" state. The verdict is: request changes (see §5).
Reviewed at PR head c3946c9 against base d8b2b64. Line numbers below are docs/plans/2026-10-04-review-v2-remediation-plan.md at the PR head, written plan:N. Disclosure: this session wrote the base plan in #205. The #206 diff was written in another session, and this review covers that diff and the plan as it stands after it.
Method: seven independent finder agents, each with its own remit: restated §0.2 rows, new §0.2 rows, decision coverage, A2 mechanics, must-do and sequencing, internal and cross-doc consistency, and the PR body. They were seeded with docs/REVIEW_CONTEXT.md. Findings were deduplicated, and each was checked by two refuters with different lenses. A completeness critic went last. Of 44 candidate findings, 43 survived verification, and every blocker below was re-checked first-hand. Mechanical checks ran (§5), so this is a verification-and-validation review.
1. Summary
The PR turns the plan into something that can be scheduled. It adds a cut line (§0.1), a single decision batch with a recommendation per decision (§0.2), one issue per PR group, an E1a/E1b split, a worked A2 option (i), a full-clone confirmation for A6, and a shorter §10. The direction is right, and the decision batch is the right instrument for CLAUDE.md §4.
It is not ready to merge as written, for three reasons. Several §0.2 rows ask the maintainer to decide on a premise that the spec or the tree contradicts. Two items labelled decision-free carry contract decisions and are scheduled for day 1. And under A2's recommended option (i), the step that produces canonical bytes is assigned to an author who cannot perform it from a cloud session. All of it is text-level; nothing changes the plan's direction.
2. What works well
- §0.2 is honest about provenance. Rows that restate an item are unmarked, new ones carry (new), and the batch says plainly that these are recommendations, not decisions.
- A2 (i) correctly spots two real flaws in the original text. Ancestry checks do not survive squash or rebase merges, and the default
refs/pull/N/mergecheckout would stamp a commit that never reachesmain. - The A2 motivation reproduced live on this PR's base. Merging #205 re-stamped all 32 vectors to
f9744bdind8b2b64, and every payload is identical apart from the provenance block. - The A6 history caveat is resolved properly. The clone now has 606
maincommits, andda5a625does introduce theltv_io1e-2. - Splitting E1 is right in principle: editorial work should not wait on decisions.
3. Issues to address before merge
Blockers
-
Five §0.2 rows rest on a premise that does not hold. The batch asks the maintainer to settle these in one pass on the stated reasons (CLAUDE.md §3–§4; principles 1–3).
- K3,
plan:95(repeated atplan:159). The row says "keep §8.3.4 (warn and return); Python conforms | the spec already says it".- §8.3.4 checks only
rcond(Λ_{k−1})(spec/SPEC.md:993). Both ports check only the previous block (python/sid/_internal/ltv_cosmic_solve.py:107–121,matlab/sid/private/sidLTVcosmicSolve.m:66–77). The analysis's K3 row names exactly this as the structural defect: a singular last block is never diagnosed. - A probe confirms it.
ltv_discwithX = [s, 2s],U = 0andN = 50raisesLinAlgErroratk = 49with no warning, atrcond(Λ_48) = 3.1e-3. That is the item's own collinear-state fixture. - Suggested row: "amend §8.3.4 so the
rcondcheck covers every block the recursion inverts,Λ_0 … Λ_{N−1}, the last included; keep warn-and-return (sid:singularLbd); both ports conform | as worded, §8.3.4 never checks the last block, which is where the collinear-state fixture is singular (analysis K3); no new error code". - The test should assert the warning in both ports. Assert a non-finite result only in Python and on MATLAB proper, because Octave's
\returns a finite minimum-norm result (analysis Appendix A).
- §8.3.4 checks only
- D4,
plan:88(plan:153says the same). The row says "NaN for both | what §2.7 already says".- §2.7 (
SPEC.md:245–269) coversΦ̂_vonly. §3.2 (:326) boundsγ̂²to [0, 1], and §3.3 (:342) handles a degenerate frequency asγ̂² < ε. Python sets the coherence to 0 there (degenerate.py:325). - A NaN
γ̂²is therefore a change to §3.2/§3.3 that D4's spec column (plan:41) does not list. It would also break A7'scoherence ∈ [0, 1]invariant (plan:120). - Suggested row: "
Φ̂_v: NaN in every estimator (what §2.7 says).γ̂²: keep 0 (consistent with §3.2/§3.3); NaN would be a contract change to §3.2/§3.3 and would relax A7's invariant to finite entries". Alignplan:153.
- §2.7 (
- D7,
plan:91(plan:156). The row mapsSidWarning.code"1:1 to the §10 identifiers", but §10 (SPEC.md:1872–1923) names nosid:identifier.- The spec names five, across §2.3, §6, §8.12.4 and §8.14. MATLAB emits 14. A 1:1 mapping would in practice copy MATLAB's set into Python (principle 2), and the D7 spec column says only "python guide" (
plan:44). - Suggested: "spec first: add a warning-identifier table to §10 (each diagnostic and its condition); then Python
SidWarningwithcodemapped 1:1 to that table, and MATLAB checked against it". Set the D7 spec column to "§10 identifier table; python guide" and the ports to "both".
- The spec names five, across §2.3, §6, §8.12.4 and §8.14. MATLAB emits 14. A 1:1 mapping would in practice copy MATLAB's set into Python (principle 2), and the D7 spec column says only "python guide" (
- SP8 Welch
σ_G,plan:102(new). The row codifies the current formula because "both ports already agree".- §3.3 (
SPEC.md:330–345) definesσ_Gas the complex-total stdE|Ĝ − G|²and names the Welch path. Analysis F18 records that the implemented|Ĝ|√((1−γ²)/(γ²ν))(freq_map.py:186,sidFreqMap.m:522–543) is √2 below that form. - Two independent Monte-Carlo runs in this review gave
E|Ĝ − G|² / σ_G²≈ 2.0–2.15, where 1 is expected. Agreement between ports is a consequence, not a reason (CLAUDE.md §3). - Suggested: split SP8 into its own row. "(new) make Welch
σ_Gthe §3.3 complex-total std (√2 × current), state it in §6.5, regeneratereference_freqmap_welch; alternative: declare it magnitude-only in §6.5 and exempt Welch from §3.3". Give SP1, SP3, the MIMO NaN, the DC bin and §14.2 a reason each.
- §3.3 (
p_cov/complex_stftrename,plan:99(new). "Nothing published breaks" is false.- The
v0.1.0-pythonandv0.2.0-pythonreleases ship both names (python/sid/_results.py:82,186,298at the tag).python/RELEASE_NOTES.md:232andpython/README.md:127document them, andspec/EXAMPLES.md:1066,1087namescomplex_stft. - Suggested Why: "restores §9's purely syntactic mapping; no PyPI user yet, but the GitHub releases and docs expose the names, so ship as a documented breaking change (release-notes 'Breaking' entry, optionally a one-release alias),
EXAMPLES.mdfirst".
- The
- K3,
-
Two items are labelled decision-free but carry contract decisions (CLAUDE.md §4).
- E1a,
plan:166(rowplan:49). It is called "editorial, no decision … can start on day one", but it does two things that are choices.- It writes
SegmentLength/ConsistencyThreshold/CoherenceThresholdinto §8.4.3. Today §8.4.3 lists onlyLambdaGridandAlgorithm(SPEC.md:1066–1074). The PR's own K7–K16 row (plan:105) and D10 (plan:159) list those extras as an open "specify or remove" decision, so day-1 E1a would pre-empt it. - It bumps
SPEC.md"to a version that reflects 0.2.0" and adopts a versioning rule.SPEC.mdis already at1.0.0(SPEC.md:3), so the direction of the bump and the policy are a choice. - Suggested: keep only "add
Uncertainty/NoiseCov/CovarianceModeto §8.2 andMethodto §8.4.3". Move the tuning extras under the K7–K16 decision ("added to §8.4.3 only if 'specify' is accepted"). Move the version bump and versioning rule to E1b, or give them a §0.2 row.
- It writes
- D2,
plan:68,:72,:204(item textplan:151). It is called "no decision needed", but it adds two §14.5 error conditions and a typed error.- The conditions are
N_data ≤ DataLengthand1 ≤ MaxLag ≤ N − 1. The typed error is foru = []on state-space models, and it reverses §14.5's documented default[](SPEC.md:2126). - Real alternatives exist. For example,
[]could mean zero input, or be allowed whenq = 0:residualacceptszeros(N, 0)on aq = 0model today. - The label predates this PR, but the PR promotes D2 into the day-1 must-do set.
- Suggested: "D1 — no decision; D2 — needs the §14.5 additions accepted". Add a §0.2 D2 row marked (new): typed errors for
N_data > DataLengthand forMaxLagout of range;u = []an error only whenq > 0. Updateplan:72to five decisions and take D2 off the day-1 list.
- The conditions are
- E1a,
-
A2 option (i) assigns the canonical bytes to someone who cannot produce them (
plan:115,plan:233,plan:280).- Under (i), "the PR author commits that artifact's files". Most PRs here are written by cloud sessions.
- From this container, the artifact download redirects to
productionresultssa*.blob.core.windows.net, and the egress proxy denies it (CONNECT 403; tested with both the API and curl). - The plan also disagrees with itself: §10.2 (
plan:233) says the PR author commits, while §10.4 (plan:280) lists the same step as maintainer-only. Every ci-main cell in §10.3 depends on it. - Suggested: a (new) sub-decision in A2 and §0.2 on who commits under (i).
- (i-a) The PR's MATLAB job pushes the regenerated vectors to a same-repo PR branch when the numeric diff reports a semantic change. It must not use
[skip ci], so the validators run on that commit. Fork PRs fall back to (i-b). - (i-b) The maintainer downloads the artifact and commits it locally.
- Recommend (i-a). That means the §0.2 row's "no auto-commit" should read "no commit on
main". Align §10.2 and §10.4.
- (i-a) The PR's MATLAB job pushes the regenerated vectors to a same-repo PR branch when the numeric diff reports a semantic change. It must not use
Non-blockers
-
The must-do set's criterion does not match its membership (
plan:63,:67,:72,:199–206).- "The subset that stops wrong answers and false claims; everything else is coverage and hygiene" is not what the cut does. Outside the set are silent wrong answers and crashes on documented input: F12 (D6: MATLAB ETFE and Welch silently return
NumTrajectories = 1), F3 (D3), U2 (D5), F8/F9 (D9) and K1/K2/K4 (D10). False user-facing claims are outside it too (F1 items 2–8). - Either reword: "the gate repairs plus the critical defects; it does not remove every silent wrong answer — F3, F12, U2, F8/F9 and K1–K4 form the first backlog tier, gated on their §0.2 decisions". Or pull D3, D6 and D10 K1–K4 in and raise the decision count. That choice is the maintainer's.
- A10 is missing from the membership table, yet
plan:72counts its decision andplan:204schedules it. - A7 is left out without comment. Say that until it lands, nothing catches a vector both ports match wrongly.
- By A1's own text, requiring the MATLAB context blocks fork PRs until the token-mint step is guarded, and that guard sits in A9, outside the set. Move the guard into A1.
- The day-1 lists conflict.
plan:63says everything outside the set comes after it, yet §9 starts E1a, E3 and all of F1 on day 1 (plan:199–200), andplan:204puts F1 item 1 after A10. Suggested: "F1 items 2–8 day 1; item 1 after A10", with decision-free items allowed alongside the set. - Several groups mix day-1 rows with decision-gated rows (A-ci, B-relax, E-spec). Because "the last PR of a group closes it", no issue closes when the must-do set is done. Use a must-do label or milestone, or split groups at the cut line. Also, "about twenty" is 24 groups; 43 rows is correct.
- "The subset that stops wrong answers and false claims; everything else is coverage and hygiene" is not what the cut does. Outside the set are silent wrong answers and crashes on documented input: F12 (D6: MATLAB ETFE and Welch silently return
-
Loose ends in A2 option (i) (
plan:114–115,:241,:81).- The (a) bot-PR / (b)
workflow_run+ revert choice and "decouple the SHA" still read as unconditional, though they are moot under (i). State what (i) removes: the commit step, the App-token mint and theworkflow_dispatchpush path,contents: write, and the bot's always-bypass inmain.json(and the live "Main" ruleset). Removing that bypass is what lets A1 + A2 meet the Phase-A exit criterion. - Stale base. With
strict_required_status_checks_policy: falseand the generator on the PR head, two individually green PRs can merge into stale vectors. Nothing regenerates onmain, so the next, unrelated PR gets the blame. Add: on push tomain, regenerate and run the numeric diff without committing, and fail loudly. - "Real commit" check. Any commit of any PR passes it, abandoned ones included. Local consumer runs have no
refs/pull/*, andfetch-depth: 0does not fetch pull refs. Suggested: a PR-time CI check that each changed vector's full 40-hexgit_shais an ancestor of the PR head; consumers reject only"unknown"or malformed SHAs; the generator stamps the full SHA. - Every PR merge to date has been a merge commit, so the merge-commit-only alternative costs nothing today. The setting probably lives in the untracked "Main" ruleset.
- The (a) bot-PR / (b)
-
Other §0.2 premises to correct (non-blocking, since none of them changes the recommended option).
- D5 (
plan:89):lti_freq_io's DC rule is a linear extrapolation,Re(2Ĝ₁ − Ĝ₂)(§8.12.12), not a hold. Say that it differs rather than that it is consistent. - D6 (
plan:90): the item namessid:dimMismatchonly for frequency-domain 3-D input. Fory2-D withu3-D, the shared validator already usessid:trajMismatch/traj_mismatchfor the mirror case (sidValidateData.m:255,validate_data.py:279). Use that code, or mark the choice (new). - A9 (
plan:84): the failing 1e-15 tolerance isreference_internals'W_rel, not a test-side tolerance, and A4 forbids hardcoding one in a test. Write "add aW_atoltoreference_internalsingenerate_reference.m(A5 needs one anyway), regenerated per A2". - E1b IO
Cost(plan:101): neither port'sresidualorcomparereadsCost, so there is no special-casing to stop. The rename breaks the releasedLTVIOResult.costand MATLAB.Cost, the spec defines no (1×3) IO triple, and A6 stores theCosthistory inreference_ltv_iofirst. Rewrite the Why, set the E1b ports cell to "spec + both ports +reference_ltv_io", and order the decision before A6. - Condition metric (
plan:98):condraises on non-finite input in numpy and Octave, wherercondreturns 0. Treat a non-finite block asrcond = 0(thedegenerate.py:351guard), so K3's warn-and-return cannot turn into an error. - B2 (
plan:86): only "≥ 1" follows from the derivation (Bayesian ≽ sandwich). An upper bound "from the measured λ = 1e0 ratio plus MC margin" is a measurement, which is what B2 says the band must not pin. A cap near 1.4 at the gated λ = 1e2, where the ratio is 1.07, would also pass a ~30 % over-statement. Suggested: a per-λ upper bound from a stated requirement in §8.9 that rejects the S1 over-statement. - K7–K16 (
plan:105): specifying thelti_freq_iotrim "as implemented (both ports agree)" overrides §8.13.1's "average across trajectories" and makes a silent discard part of the contract. Specify it with a warning that names the discarded trajectories (or average all, as §8.13.1 says), and give each tuning extra its own reason.
- D5 (
-
"ADR amendments" contradicts the ADR process (
plan:76; also the A1, A2 and A3 cells).docs/decisions/README.md§"Editing a merged ADR" forbids rewriting accepted ADR text; a changed decision is a new, superseding ADR. Suggested: "recorded as new ADRs; a decision that changes an accepted ADR (A1 vs ADR-0005; A2, A3 vs ADR-0002; K1 vs ADR-0004) is a superseding ADR, not an edit". -
G2 decisions are incomplete (
plan:58,:106,:181,:280). #204 and #203 carry the same "Options (recommend, don't decide)" framing as #202. G2's text settles #204 ("choose option 1") with no marker, and #204 may be moot under A2 (i). Mark both and add §0.2 rows; note the A2 coupling on #204. -
E1a/E1b enumerations (
plan:49,:166,:167).- The E1a row omits four things §5 E1a does:
'welch'out of theMethodenumeration, SP5 (now in neither row),Lin §3.4/§3.5, and the ETFEWindowSize. - Several analysis §6 factual corrections are in neither list, and no other plan item covers them: §8.12.2's reported IO cost is 2N·f(C), not N·f(C); §8.4.2 is missing a ½; and
uncertainty_derivation.mdhas wrongX'(k)dimensions, the ν N-factor missing, an overloadedH⁻¹, and a "Full = Default" row. Append them to E1a as factual corrections.
- The E1a row omits four things §5 E1a does:
-
§10.3/§10.4 and inventory markers (
plan:28,:47,:266,:267,:280).- The D9 maintainer cell is "—", though D9 is a [decision] everywhere else.
- The D10 cell omits K7–K16 and includes D11's
p_cov. - The inventory says K7–K17, while D10 and §0.2 say K7–K16. §10.4 lists the whole range as decisions, though only part of it is.
- B2's spec-edit column is "—", though B2 now writes a §8.9 sentence.
-
A6 on local R2024a (
plan:119).- A local R2024a run measures cross-release drift, not the canonical R2025a drift the tolerance must cover, and §10.1 flags R2024a as churny. The residuals against the committed bytes are measurable in a cloud session.
- "The only items that need local MATLAB" contradicts §10.3 and §10.4: the A5 and D3–D6 rows have LOCAL cells, and interim bytes are listed there too.
- Separately,
da5a625is "the only 'born at' row" at the boundary, not the only row:8a1c436(ltv_cosmic1e-10 → 1e-6) also dates from 2026-04-08.
4. Follow-up suggestions (nits)
plan:68: "(analysis F1, F2, U1, U5)" is ambiguous, because the analysis uses F1/F2 in both §4.1 and §5.1. Write "§5.1 F1, F2; §5.3 U1, U5".plan:85(A10):tests.yml:62–65records that snap channels are not version-pinnable. Name a pinnable source, such as a versioned container image or a snap revision.plan:87(D3): the all-NaN result is not silent. It carries a misleading "some frequencies" warning.- E1a still leaves two choices open: where the spec history goes, and whether to delete or mark Appendix B. Either recommend one each, or note them as small decisions.
- PR body: the (new) list omits the A2 provenance-check row, the must-do list omits A10, and "about 20 issues" is 24.
5. Verdict
Request changes. Blockers 1–3 change what a reader would do or decide. The non-blockers can land in the same push.
Mechanical checks that ran:
- CI is green on
c3946c9: both lint jobs and the strict site build pass, and the engine jobs are correctly gated off for a docs-only change. - Inventory count: 43 rows, 24 PR groups.
- Python probes: the K3 last-block
LinAlgError; two Monte-Carlo runs of the Welchσ_Gratio;residualon aq = 0model withzeros(N, 0). - An artifact download attempted from a cloud container (denied by the proxy).
git log -Son a full 606-commit clone.- The release tags read with
git show. - Every spec line cited above.
Not verified: MATLAB-proper behaviour, and the merge-method settings of the live "Main" ruleset.
Generated by Claude Code
Blockers: - §0.2 rows corrected where their premise did not hold: K3 (amend §8.3.4 to check every inverted block, incl. the last), D4 (Φ̂_v NaN, γ̂² stays 0), D7 (§10 identifier table first), SP8 (Welch σ_G is √2 below §3.3's complex-total std; own row), p_cov rename (documented breaking change). Item text updated to match. - E1a no longer pre-empts decisions (tuning extras wait on K7–K16; version bump moved to E1b); D2 marked as needing its §14.5 decision. - A2 (i): sub-decision on who commits — (i-a) the PR's MATLAB job pushes to the PR branch without [skip ci]; forks (i-b) maintainer. Non-blockers: must-do criterion reworded with a named first backlog tier; A10 added; A7 gap stated; fork-token guard moved into A1; A2 loose ends (what (i) removes, stale-base check on main, PR-time ancestry check); D5/D6/A9/E1b Cost/condition metric/B2/K7–K16 rows; superseding ADRs instead of amendments; G2 #203/#204 rows; E1a factual corrections; §10 cells; A6 measurement source; nits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for the review. Every point is addressed in dcf8bf4. Point by point: Blockers
Non-blockers
Nits: all applied. That covers the analysis section references, the pinnable Octave source, D3's misleading warning, the E1a small choices, and the PR body. A second fresh-context pre-push review of the fixes found 10 leftovers, all fixed before push. The main one: the §9 graph still called D2 decision-free. 🤖 Generated with Claude Code |
pdlourenco
left a comment
There was a problem hiding this comment.
Re-review of PR #206 at dcf8bf4
Posted as a comment review because this session's GitHub identity is the PR author. The verdict is: request changes (see §5). The remaining blockers are small, and one of them is mechanical.
Scope: fix commit dcf8bf4, read against the previous review of c3946c9, and the plan as a whole at the new head. Line numbers are docs/plans/2026-10-04-review-v2-remediation-plan.md at dcf8bf4, written plan:N.
Method:
- Twelve verifiers each checked one prior item, or the nits, against the plan text rather than the reply.
- Three hunters looked for regressions in the fix commit: A2 mechanics, the new §0.2 rows, and internal consistency.
- Two refuters checked every finding, and a critic went last.
- Every blocker below was re-checked first-hand.
1. Summary
The fix commit is a real response. Every prior blocker is addressed in the plan text, and most non-blockers are too:
- K3, D4 and D7 are corrected.
- SP8 has its own row.
- The
p_covrename is framed as a documented breaking change. - D2 is a decision.
- A2 has the (i-a)/(i-b) owner split, plus the stale-base and PR-time ancestry checks.
- ADR amendments became superseding ADRs.
Four things keep it from merging:
- CI never ran on
dcf8bf4. - Two of the new §0.2 rows recommend an action on a premise the spec contradicts.
- E1a and A1 are still scheduled as decision-free while the plan itself gates them on decisions.
- A handful of §10 cells were not carried along with the revisions.
2. Status of the previous review
| Prior item | Status at dcf8bf4 |
|---|---|
1 — K3, D4, D7, SP8, p_cov premises |
fixed; residuals in §3 items 5 and 7 |
| 2 — E1a / D2 not decision-free | D2 fixed. E1a partly fixed: still picks a side and is still day 1 (blocker 3) |
| 3 — A2 owner of canonical bytes | fixed; the (i-b) fallback needs an artifact step (item 4) |
| 4 — must-do criterion and membership | fixed; A1 is the remaining gap (blocker 3) |
| 5 — A2 loose ends | fixed; new mechanics gaps in item 4 |
| 6 — other §0.2 premises | fixed; the new K7–K16 rows introduce one false premise (blocker 2) |
| 7 — ADR amendments | fixed; A2 also supersedes part of ADR-0005 (blocker 3) |
| 8 — G2 | fixed (nit on #203) |
| 9 — E1a/E1b enumerations | fixed (nits) |
| 10 — markers | fixed; some §10 cells are stale (item 6) |
| 11 — A6 | fixed in the item text; the §10.3 A6 row is stale (item 6) |
| Nits | applied |
3. Issues to address before merge
Blockers
-
CI did not run on
dcf8bf4.- The commit message says the MATLAB job "pushes to the PR branch without [skip ci]". GitHub skips every
pushandpull_requestworkflow when the head commit's message contains[skip ci]anywhere. - No workflow run exists for
dcf8bf4, and the combined status is pending with zero checks. The two required lint checks therefore never reported, which is why the PR shows as blocked. - Any follow-up commit whose message does not contain the marker fixes it, for example "…without the skip-ci marker".
- This is the same trap as #204, and A2 (i-a) will meet it again: the plan could add that commit messages must never quote the marker.
- The commit message says the MATLAB job "pushes to the PR branch without [skip ci]". GitHub skips every
-
Two new §0.2 rows recommend an action on a false premise (CLAUDE.md §3–§4).
- K7–K16 tuning extras,
plan:115. The row says "ports follow §8.11.2's>rather than≥… a conformance fix, not a spec change".- §8.11.2 contradicts itself within one sentence: "Select
λ* = max{λ : S(λ) > 0.90}— the largest λ for which at least 90 % of grid points are consistent" (SPEC.md:1435). - Both ports implement the prose,
≥(ltv_disc_tune.py:405). Changing the ports to>therefore picks one half of a self-contradictory sentence, and it is a behaviour change in both ports. - Suggested: "§8.11.2 is self-contradictory (formula
>, prose 'at least 90 %'); (new) make the formula≥, which matches the prose and both ports, so no code changes; alternative:>and change both ports".
- §8.11.2 contradicts itself within one sentence: "Select
- SP3,
plan:107. The row says "remove the §5.4 floor claim | no port has the floor".- §5.4's floor,
M_default = clip(floor(N/10), 2, 30)(SPEC.md:518), is BTFDR's, and both BTFDR ports implement it (freq_btfdr.py:211,sidFreqBTFDR.m:109–112). Followed literally, the row deletes an implemented contract. - The false part of §5.4 is only its side claim that the floor "matches the short-data default of
sidFreqBT". BT has no floor, soM = 1errors. - Suggested: "(new) keep §5.4's BTFDR floor; for BT, either give §2.1's default the same
max(·, 2)floor (both BT ports change) or delete §5.4's 'matches sidFreqBT' clause. Recommended: the floor, because a default that errors on data §10.1 accepts (N ∈ [10, 19]) is a defect".
- §5.4's floor,
- K7–K16 tuning extras,
-
E1a and A1 are still scheduled as decision-free while the plan gates them on decisions (CLAUDE.md §4; the residue of the previous blocker 2).
- E1a, ETFE
WindowSize(plan:49,:180): stating it is not editorial. §4 says ETFE is BT withM = N − 1(SPEC.md:431), and §9 definesWindowSizeasM, but both ports reportN(sidFreqETFE.m:375,freq_etfe.py:513). Writing either value picks a side. Move it to E1b with a §0.2 row, for example "(new) stateN − 1and change both ports; alternative: stateNand reword §4's equivalence". - E1a, day 1 vs its two §0.2 small choices. §5 (
plan:180), the §9 graph (:213) and the §9 prose (:218) call E1a "day 1, no decision". §0.2 (:120) and §10.4 (:291,:294) gate it on two maintainer choices, one of which createsspec/CHANGELOG.md. Say "E1a starts after its two small §0.2 choices", or move those two edits out of E1a. - A1 (
plan:17,:73,:218): the new preamble (plan:77) itself lists A1 as a decision that changes an accepted ADR (ADR-0005). Yet A1 has no [decision] marker and no §0.2 row, and it "can start immediately". Add a §0.2 row, for example "accept the six required contexts and the fork-token guard", and changeplan:73and:218to "once its ADR is accepted". - Relatedly, A2 consequence (4) removes the bot's always-bypass, which ADR-0005's Decision records. So A2 supersedes part of ADR-0005 as well as ADR-0002 (
plan:18,:77).
- E1a, ETFE
Non-blockers
-
A2 option (i) mechanics (
plan:82,:83,:129,:255).- "Semantic change" is too narrow. It is defined only as a payload outside tolerance, but the A-group items mostly change tolerance blocks, keys or encodings: A3 sentinels, A5
_atolfields, A6IterationsandCost. Under (i-a) those never count as semantic, so the bot never pushes them. Define a semantic change as "payload outside tolerance, or any change to a tolerance entry, key set or encoding". - Loop guard. The bot's push touches
testdata/, so the MATLAB job runs again on its own head. That terminates only if every stored tolerance covers R2025a's run-to-run drift. State a guard, for example "never push when the head commit is the bot's own". - (i-b) needs an artifact.
tests.ymlhas no artifact-upload step today, and A2's work cell does not add one. Also say where the maintainer commits for a fork PR. - Full 40-hex SHA. All 32 committed vectors carry 7-hex SHAs (
"f9744bd"), so a consumer that rejects "malformed" SHAs rejects every existing vector. Accept 7–40 hex, or regenerate everything in the A2 PR. - "
contents: writeonmain" does not exist. The grant is workflow-level and applies toGITHUB_TOKENonly (tests.yml:18–19). Under (i-a) the push uses the App token, so the mint step stays and the grant can go. - The author's branch falls behind after a bot push. Note "pull before pushing; never force-push over a bot commit", since agent sessions often amend.
- Local R2024a bytes that sit within tolerance of R2025a are never replaced, so they land on
mainas final. Provenance records no engine. Record the engine in provenance, or rule out locally generated bytes. - A6's "repeated R2025a runs via
workflow_dispatch" (plan:133) is not safe today. A dispatch regenerates, commits and pushes tomainunder[skip ci], and on a non-mainref it rebases ontomainand pushes through the bypass (tests.yml:176–186). Run it only after A2 removes the push path, or add a no-commit input.plan:237has the same issue. - §10.4's maintainer list lacks the ruleset re-application that the bypass removal needs. A2 says it closes #204, while G2 implements #204's option 1, so the tracking issue has two owners.
- "Semantic change" is too narrow. It is defined only as a payload outside tolerance, but the A-group items mostly change tolerance blocks, keys or encodings: A3 sentinels, A5
-
Other row premises.
- Welch MIMO
σ_G(plan:109). "No derivation behind it" is false: §3.6 gives the MIMO diagonal form BT uses, and the Welchνsubstitution is the same one the SISO row recommends. Both ports also emit §3.3'sInfsentinel at degenerate bins (freq_map.py:197–200,sidFreqMap.m:553–554). Suggested: "NaN except the §3.3Infsentinel at degenerate bins; extending §3.6 is out of scope for now". - SP8 has nothing to pin it (
plan:108,:50).reference_freqmap_welchstores noResponseStd(its keys areCoherence,Frequency,NoiseSpectrum,Response_*,Time). Regenerating it changes nothing, and the √2 fix would ship with no cross-port check. AddResponseStdto the vector. - Spec version (
plan:104).EXAMPLES.md§6.1's table covers only example-suite changes, so "MAJOR under that rule" is not something the rule says. Write a SPEC-specific semver table instead; under it, changed outputs of a conforming implementation are MAJOR. - IO
Cost(plan:105). It is not(n_iter × 1)on every path: trust-region stages append the best iterate's J, and therank(H) = nfast path returns length 1. Say "the per-iteration cost history (length varies by path)". "Decide before A6" also makes this E1b decision a prerequisite of the must-do set, which the count atplan:73omits. - K3 test (
plan:98,:173). It asserts a non-finite Python result, but neither §8.3.4 nor the amendment says what is returned. Either specify it in the amendment, for example a NaN-filled estimate, or assert only the warning. - Tuning row (
plan:115).sid:noConsistentLambdais not in the spec and Python's warning has no identifier, so "already a named diagnostic" takes MATLAB as the reference (principle 2); route it through D7's table. The default ismin(floor(N/4), 256). - DoF row (
plan:113). §8.9.3's first fallback,ν = Σ|L(k)| − N·d, cannot be positive when it is reached. So the second fallback is always the one hit, and the typed error would fire on every fallback; say so. - SP1 (
plan:106). Both ports' ETFE constant-input warning still says "sigma_G to Inf" while returning NaN, and §10.3 statesσ_G = Inffor every estimator. Codify it and fix the warning text and §10.3 together. - D2 (
plan:89).N_datais undefined, and state data has N + 1 rows.compare(§15.4) requiresuand has no[]default, so name §15.4. Give theMaxLagerror an identifier, and takeMaxLagout of D10's K list. - D4 (
plan:41). The normative degenerate-input values live in §10.2/§10.3, so add them to the spec column. - First backlog tier (
plan:63). It omits F4 (D4): MATLAB ETFE'smax(PhiV, 0)turns NaN into 0, which is silent and rated major. - K7–K17 typed errors are called "contract additions" in D10 (
plan:173) but carry no [decision], unlike D2's.
- Welch MIMO
-
§10 cells not carried along with the revisions.
- D7's §10.3 row (
plan:278) is still Python-only, with no spec table and no MATLAB side. §10.4 (:291) still lists D7 as cloud-only. - E1b now changes both ports' numerics and a MATLAB-generated vector (SP8), yet §10.3 (
:283) and §10.4 (:291) call it text-only and entirely cloud-capable. - The A6 row (
plan:259) still puts the MATLAB-vs-Octave residual under LOCAL and describes the bytes arriving "on merge". - The A10 cell (
plan:263) still assumes a snap channel. - §10.4 (
:294) lists the canonical regeneration as maintainer-only, though (i-a) automates it; only (i-b) is a maintainer action.
- D7's §10.3 row (
-
Other consistency.
- B2's item text (
plan:144) does not match its revised §0.2 row (:88): it has no "≥ 1" requirement and no per-λ bounds. - Labels and milestones attach to issues, not checklist rows (
plan:13). "F1 item 1" is not a row, so labelling the F1 row marks all eight items. - E1a's "scope §1's 'all functions'" gives no list. The analysis list is partly wrong:
detrendandresidualdo accept 3-D input. - The analysis §6
Verified by:over-claims are in neither E1a nor B6. - The markers do not all follow the preamble's rule. A9 changed but is unmarked, and E1b
Costis marked (revised) although the item listed options without recommending one.
- B2's item text (
4. Nits
- D7 (
plan:94): the five named identifiers sit in §2.3, §5.2, §8.12.4, §8.13.1 and §8.14, not "§6". - D4: ETFE has no coherence output, so the
γ̂²half applies to BT, BTFDR and Welch only. - E1a:
H⁻¹is overloaded inSPEC.md§8.9.2, not inuncertainty_derivation.md. Deletingoutput.mdAppendix B leaves §4.1's reference to it dangling. The E1a row still names onlyoutput.md§7. plan:13: "never as an edit" is too strong, because superseding does edit the old ADR's Status line.- #203 lists two options without recommending either, so "the issue's own recommendation" (
plan:118) does not hold. - K4 needs no decision (
plan:63). D7, D9 and D10 are missing from the phase-order sentence (plan:162).plan:128has an unmatched closing parenthesis.(§9)atplan:67reads as the analysis's §9. - D11:
p_covappears in no.md(only code), and the notebook that usescomplex_stftneeds updating too.
5. Verdict
Request changes.
- Blocker 1 needs any new commit without the marker.
- Blockers 2 and 3 are a few rows each.
- The non-blockers can land in the same push. Items 4 and 6 matter most, because they are what an implementer of A2 would trip over.
Mechanical checks that ran:
- The workflow-run list for the branch: none for
dcf8bf4. - The combined status: pending, 0 checks.
- The spec and code lines cited above, read at
dcf8bf4. - Python's
>=atltv_disc_tune.py:405. - The BTFDR floor in both ports.
- The keys of
reference_freqmap_welch. - The provenance SHA lengths of all 32 vectors.
tests.yml's dispatch and push path.
Not verified: MATLAB-proper behaviour, and the live "Main" ruleset.
Generated by Claude Code
Blockers: - K7–K16 tuning row: §8.11.2 is self-contradictory; recommend making the formula >= (matches prose and both ports, no code change). - SP3 row: keep §5.4's implemented BTFDR floor; recommend giving the BT default the same floor. - E1a no longer scheduled as decision-free (two small §0.2 choices); ETFE WindowSize moved to E1b; A1 gets a [decision] and a §0.2 row; A2 also supersedes ADR-0005's bot bypass. Non-blockers: A2 (i) mechanics (semantic-change definition, loop guard, never quote the skip marker in bot commit messages, artifact step for forks, 7-40 hex SHAs, engine in provenance, contents grant, branch-behind note, dispatch hazard); Welch MIMO, SP8 ResponseStd, spec semver table, IO Cost length, K3 NaN return, DoF, SP1 warning text, D2 N_data/MaxLag/compare, D4 spec column, F4 in backlog tier, K7–K17 typed errors as decisions; §10 cells; B2/B6 text; issue splitting at the cut line; nits. The previous commit's message quoted the CI skip marker, so no workflow ran on it; this message does not. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Re-review addressed in c4b50fe. Blockers
Non-blockers
Nits: all applied. That covers the D7 section list, D4's ETFE coverage, A fresh-context pre-push review of this round found 8 leftovers, all fixed before push. The main one: a non-canonical-engine check without a replacement path would have left a PR red for good. 🤖 Generated with Claude Code |
pdlourenco
left a comment
There was a problem hiding this comment.
Final check of PR #206 at c4b50fe
Posted as a comment review because this session's GitHub identity is the PR author. The verdict is: approve with one change (below).
Scope: fix commit c4b50fe, read against the re-review of dcf8bf4. Five verifiers checked the prior items against the plan text, two hunters looked for regressions, and every candidate went to two refuters with a materiality bar. I re-checked the blockers and the remaining finding first-hand.
Status
- CI is green on
c4b50fe. Both lint jobs, the strict site build and both engine jobs pass, and the commit message carries no skip marker. - Re-review blockers 2 and 3 are fixed everywhere they appear.
- The tuning row recommends
≥. That matches §8.11.2's prose and both ports (ltv_disc_tune.py:405,sidLTVdiscTune.m:278), so no code changes. - SP3 keeps the implemented BTFDR floor.
- ETFE
WindowSizeis an E1b decision. - E1a starts after its two small choices, consistently in §5, §9, §10.3 and §10.4.
- A1 is a [decision] with a §0.2 row and starts once its ADR is accepted.
- A2 also supersedes ADR-0005's bypass.
- The tuning row recommends
- Non-blockers 4–7 are fixed. That covers the A2 mechanics, the row premises, the §10 cells, the B2 text, the counts, and the "seven decision items" (A1, A2, A3, A6, A10, D2, E1b
Cost). I found no new false premise among them.
One change before merge
D11 still claims four findings that are now E1b decisions (plan:48, plan:177).
- D11 lists "F10–F11, F13–F20" as decision-free minor items, and its only [decision] is the rename.
- This PR gives four of those findings their own E1b decision rows:
- F14, ETFE
WindowSize(plan:109) - F16, Welch MIMO
σ_G(plan:111) - F18, Welch SISO
σ_G(plan:110) - F19, the BT floor (
plan:108)
- F14, ETFE
- Someone working through D11's checklist would settle them without the decision. That is the same defect the re-review raised for E1a's
WindowSize. - Suggested, at both lines: "F10–F11, F13, F15, F17, F20 (F14, F16, F18 and F19 are E1b decisions)". Adjust F15 if it is meant to be E1a's
Lin §3.4/§3.5.
This is a one-line edit in two places and needs no further review round.
Optional
- The PR description still says "E1a is editorial and can start on day 1" and lists (revised) rows from the earlier round. Update it so the merge record matches the plan.
Generated by Claude Code
F14, F16, F18 and F19 have their own E1b decision rows; F15 is E1a's L in §3.4/§3.5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Applied in 03378a5. D11 now lists F10–F11, F13, F17, F20 and U6–U8. F14, F16, F18 and F19 are noted as E1b decisions, and F15 as E1a's 🤖 Generated with Claude Code |
Brings in the #206 merge commit now that #207 targets main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wz15nbQvZAdxgAMJ9nkuvf
Summary
Refines
docs/plans/2026-10-04-review-v2-remediation-plan.md(landed in #205) so it can be executed without stalling. The analysis document is untouched (docs/analyses/README.mdrule 3).Cost.σ_Gunderstatement.must-dolabel and a milestone.WindowSize, SP1, SP3, SP8 and §14.2.[skip ci]. For fork PRs, (i-b): the maintainer commits the artifact.mainregenerates and diffs without committing, so a stale base fails loudly.main.Review
Addresses the review of 2026-10-08: all 3 blockers, non-blockers 4–11 and the nits. Point-by-point reply in the PR conversation.
Test plan
Docs-only plan edit.
docs/plans/is outside the published site.Claims re-verified first-hand:
ltv_discon collinear states raisesLinAlgErrorat the last block with no warning.E|Ĝ−G|²/σ_G²comes out at 2.15 in a Monte-Carlo run.p_covandcomplex_stftare inv0.2.0-python.Λ_{k−1}.Pre-push review:
Round 1 flagged 11 issues, fixed in c3946c9.
Round 2 (review fixes) flagged 10 leftovers: the §9 graph still called D2 decision-free; §10.3 D2/A2/G2/D10/E cells; A2's "fails the PR" vs (i-a); E1b
Costrecommendation; counts. All fixed in dcf8bf4.Round 3 (re-review fixes) flagged 8 leftovers, all fixed in c4b50fe. The main one: the non-canonical-engine check had no path to replace those bytes.
Addresses the re-review of 2026-10-08 as well; point-by-point reply in the PR conversation.
🤖 Generated with Claude Code