Skip to content

fix: resolve seven HIGH re-review findings (#486) - #505

Merged
dean0x merged 41 commits into
mainfrom
fix/486-rereview-high-findings
Oct 15, 2026
Merged

dean0x merged 41 commits into
mainfrom
fix/486-rereview-high-findings

Conversation

@dean0x

@dean0x dean0x commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Summary

This PR fixes all seven blocking HIGH findings from the re-review of PRs #436, #440 and #459. Each finding is named as "finding N of #486".

Changes

Breaking Changes

  1. Every wave merge creates a merge commit. Each ticket adds one merge commit to the integration history.
  2. An "already up to date" merge halts the wave before Validate. Before this change, the wave continued. The halt text states why the wave stopped and what to check.
  3. A malformed or equal SHA halts the wave before Validate. The halt has a fixed reason. The rejected value is never repeated.
  4. The undo resets to the recorded pre-merge SHA. It does not reset to the parent of the merge commit. The undo counts as done only when HEAD equals the recorded SHA.
  5. A supplied ISSUE_PR_LINK is final for GitHub, Jira and Linear. This includes (none). Step 4b runs only when ISSUE_PR_LINK is absent and no wave block is admitted. It takes only the Handoff Values link line, and it refuses that line in step 4a's words when the line fails the check. It composes no line.
  6. PRs from /code-review and /bug-analysis no longer get a closing line from the branch name. Jira and Linear tickets no longer get a reference from the branch name.
  7. /implement with an issue number and no link emits TRACEABILITY: DEGRADED (ambiguous issue reference).
  8. A run with no issue number and no link writes no Related Issues heading.
  9. The live integration tests no longer use the skip flag. They run in a temp home and a temp repository. They skip, and print a reason, when no credential is set. These are test-only changes.
  10. A static guard fails any claude spawn under tests/ that lacks env or cwd. It also fails a spawn that uses the skip flag or bypassPermissions.
  11. The dynamic-build ceilings are lowered to the new sizes.
  12. A wave merges only a local ticket branch. A branch name that fails the ref check, or that is not a local branch, quarantines the ticket, and no merge runs.
  13. On Jira and Linear, the PR link line always uses the default form, Refs {KEY}-{n}. A custom ## Reference Rendering no longer shapes that line. It still shapes the Shipped Issues section of a release. Follow-up fix: apply the Reference Rendering gate to the Handoff PR link line (Jira, Linear) #511 tracks this change. The maintainer accepted it.

Deviations

  1. A true fast-forward merge is refused. It is not undone. A --no-ff merge is the covered case.
  2. waitForCi stays at 117 lines and depth 6. Finding 5 of Re-review of PRs 436, 440, 459: 7 HIGH findings still on main #486 states 115 lines and depth 5. This PR does not improve those values. The fix is one shared settle comparison.
  3. init always registers the capture hooks. The spawn-context builder removes them from the temporary settings. Therefore, only the memory-hook assertion is a real check.
  4. The afterAll hook of the live-file test disposes its resources without an explicit finally block. createSpawnContext cleans up its own failures.
  5. A test title in tests/setup/isolate-env.test.ts is corrected. The static guard also refuses bypassPermissions under tests/integration.
  6. To fit the ceiling, which has no spare room, the fence comments in src/assets/commands/dynamic-build.mds were condensed by about 400 bytes. This is in addition to the planned cut. The two dynamic-build ceilings are lowered to 106,923 and 103,536. After the base update, the measured sizes are 106,828 and 103,441. The ceilings are not changed.

Validation

  • Head: 3304490. The base update merges main 8875e09 (merge 7eaaf44).
  • Full Validate at 8bef0ce: build PASS, tsc PASS, integration 51 of 51, and unit 12,630 passed with 17 failed in 9 files. All 9 files pass when run alone. The failures are load timeouts, plus two load assertions in the redact-secrets and model-discovery tests. This PR does not touch those tests.
  • Targeted tests at the fix commits all pass.
  • CI at 3304490: build-and-test (22) pass, macos-bash32-hooks pass, security/snyk pass.
  • CI is the binding full-suite gate.

QA

  • 73 checks in total: 63 passed, 2 failed and 8 were skipped.
  • The two failed checks are not code defects.
    • The check for the RED proof on the unedited undo fails earlier than planned. The current test first requires the recorded base SHA. The planned RED output is in the Re-review of PRs 436, 440, 459: 7 HIGH findings still on main #486 issue comment.
    • The check for planning IDs in the PR text fails only on the test-plan block at the end of this body. The evidence contract requires the IDs in that block.
  • The eight skipped checks:
    • Five need a token.
    • Two check the PR body. They ran before the PR existed.
    • One checks the full suite. Validate runs that check.

Not verified: deny-rule binding for subagents and the live proof (no token)

  • The deny-rule probe did not run. The live run did not run. No token was available.
  • The platform-assumptions row records the deny-rule binding as UNVERIFIED.
  • The permission design stays unproven until a run with a token.
  • Dean decides at merge.

live proof not run: no token

Reviewer Focus Areas

  • The deny-rule binding for subagents. It is UNVERIFIED. See the section above.
  • The two halt reasons. Check that the already-up-to-date text says what to do next.
  • The three halt kinds: red, bad-sha and unchanged. Each kind has fixed text. Check each text against its case.
  • The closing-line rule. Check the case with no issue number and no link. That case writes no heading.
  • The real-git test. Check its RED output and its GREEN run.
  • The byte table. Both dynamic-build variants must stay under their ceilings.
  • The platform wording, reproduced here for review:

Where a test needs live claude sessions, the test is opt-in, runs in a temp HOME and a temp repository, and uses an explicit permission mode and deny list instead of the flag (tests/integration/subagent-skill-preload.test.ts is excluded at glob time rather than by a command-line path).

Disputed findings

None. The wording of finding 7 of #486 is corrected: walkRoot is a function of 94 lines with a loop of 55 lines. No count is disputed.

Follow-ups

Related Issues

Closes #486

Test Plan

  • TP-1 (AC-7) Dynamic-build and resolve sizes are recorded before the first fence edit — method:local [files: dist/commands/dynamic-build.md]
  • TP-2 (AC-1) Merge prompt reads baseSha before a no-ff merge, aborts on conflict, and returns baseSha last — method:ci [files: tests/build-mds.test.ts]
  • TP-3 (AC-1) A failed abort returns merged true with no mergeSha, and the wave halts — method:ci [files: tests/dynamic/wave-flow.test.ts]
  • TP-4 (AC-1) Doctrine step one says Git aborts the merge and reports the conflicting files — method:local [files: src/assets/commands/_partials/_wave.mds]
  • TP-5 (AC-2) A bad baseSha with merged true halts before Validate or undo, with null SHA fields — method:ci [files: tests/dynamic/wave-flow.test.ts]
  • TP-6 (AC-2) A rejected SHA value never appears in the halted record, the reason or the report — method:ci [files: tests/dynamic/wave-flow.test.ts]
  • TP-7 (AC-3) Undo collector pins the symbolic HEAD, branch head, caret and baseSha reset checks — method:ci [files: tests/build-mds.test.ts]
  • TP-8 (AC-3) Known-bad probes with a caret reset, a hard reset or a push are refused — method:ci [files: tests/build-mds.test.ts]
  • TP-9 (AC-4) A head equal to baseSha counts as undone, and any other or malformed head halts — method:ci [files: tests/dynamic/wave-flow.test.ts]
  • TP-10 (AC-5) Base A and ticket commits B1 and B2: HEAD returns to A after a fast-forward merge, with B1 unreachable — method:ci [files: tests/dynamic/undo-real-git.test.ts]
  • TP-11 (AC-5) The same test on the unedited build fails with HEAD on B1, and that output is recorded before the fix — method:local [files: tests/dynamic/undo-real-git.test.ts]
  • TP-12 (AC-5) A detached HEAD and a conflicting local change report not undone, and a dirty file survives — method:ci [files: tests/dynamic/undo-real-git.test.ts]
  • TP-13 (AC-5) The real-git test sets its own identity, and the phase 2a fallback is gone after GREEN — method:local [files: tests/dynamic/undo-real-git.test.ts]
  • TP-14 (AC-6) No per-ticket loop line sits more than five levels below while, and a seeded probe fails — method:ci [files: tests/build-mds.test.ts]
  • TP-15 (AC-6) Verdict check stays the first if after the engine call, and the merge name and prompt starts stay — method:ci [files: tests/dynamic/wave-flow.test.ts]
  • TP-16 (AC-6) Frozen anchors stay above the compose step and appear once, and the condensed partial compiles — method:ci [files: tests/guards/retired-wording.test.ts]
  • TP-17 (AC-7) Lowered ceilings match the json rows and test literals, each pattern occurs once, and no ceiling rises — method:ci [files: tests/guards/command-size.test.ts]
  • TP-18 (AC-8) Builder home and cwd are realpaths under a symlinked temp parent, and home passes the temp check — method:ci [files: tests/integration-spawn-context.test.ts]
  • TP-19 (AC-8) Temp repository prints no remote, copies no git or devflow directory, and sits outside the checkout — method:ci [files: tests/integration-spawn-context.test.ts]
  • TP-20 (AC-9) Environment holds the OAuth token first, the API key only as fallback, and HOME as the temp home — method:ci [files: tests/integration-spawn-context.test.ts]
  • TP-21 (AC-9) With no credential the builder yields a printed skip reason, not no-session-dir, and shows set or not set only — method:ci [files: tests/integration-spawn-context.test.ts]
  • TP-22 (AC-10) Both spawn argument lists pin dontAsk, the per-spawn tool, the six-tool deny list and empty strict MCP — method:ci [files: tests/integration-spawn-context.test.ts]
  • TP-23 (AC-10) The token before the prompt is -p and never a variadic flag value, in both argument lists — method:ci [files: tests/integration-spawn-context.test.ts]
  • TP-24 (AC-11) Transcript lookup with the builder home and cwd resolves the encoded real project directory — method:ci [files: tests/integration/helpers.test.ts]
  • TP-25 (AC-12) Init into the temp home installs the Validate and Test agents and no memory or learning hook — method:ci [files: tests/integration-spawn-context.test.ts]
  • TP-26 (AC-12) Cleanup removes both temp directories after a midway throw, and the beforeAll and init timeouts are explicit — method:ci [files: tests/integration-spawn-context.test.ts]
  • TP-27 (AC-13) The guard finds both claude spawns with env and cwd, and no skip flag or bypass mode — method:ci [files: tests/guards/integration-spawn.test.ts]
  • TP-28 (AC-13) Seeded probes lacking env, cwd or the skip flag fail, and the eager memory argv literals do not match — method:ci [files: tests/guards/integration-spawn.test.ts]
  • TP-29 (AC-13) A seeded init spawn without env or cwd in an integration file fails the guard — method:ci [files: tests/guards/integration-spawn.test.ts]
  • TP-30 (AC-14) The probe with Bash allowed and denied in one run leaves probe-marker absent when deny rules bind — method:manual
  • TP-31 (AC-14) The probe records whether dontAsk works with print mode and whether a denied tool ends or stalls the turn — method:manual
  • TP-32 (AC-14) The probe makes at most two attempts, each with HOME and cwd set after a realpath check — method:manual
  • TP-33 (AC-14) Both live files run once under the lock with the opt-in set, and the outcome is pass, fail, or not run with no token — method:manual [files: tests/integration/subagent-skill-preload.test.ts]
  • TP-34 (AC-15) No skip-flag claim and no developer-config claim remain in the four stale texts — method:local [files: docs/reference/platform-assumptions.md]
  • TP-35 (AC-15) Doc reader tests stay green after the platform text edit — method:ci [files: tests/agent-name-guards.test.ts]
  • TP-36 (AC-15) Review confirms the hook line holds no allow or deny judgment — method:manual [files: docs/reference/platform-assumptions.md]
  • TP-37 (AC-16) A supplied none value is final with no reference, and the words or an absent block are gone from step 4a — method:ci [files: tests/seams/pr-link-handoff.test.ts]
  • TP-38 (AC-17) Step 4b requires an absent Handoff block and no admitted wave block, with one writer per path — method:ci [files: tests/seams/pr-link-handoff.test.ts]
  • TP-39 (AC-17) With ISSUE_NUMBER and ISSUE_PR_LINK both none, the built text writes no Related Issues heading — method:ci [files: tests/seams/pr-link-handoff.test.ts]
  • TP-40 (AC-18) No provider step 4b composes a closing line from a bare number or a branch name, and seeds are refused — method:ci [files: tests/seams/pr-link-handoff.test.ts]
  • TP-41 (AC-18) Issue keys stay out of every Code spawn, and the agent input seam tests stay green — method:ci [files: tests/seams/command-agent-input.test.ts]
  • TP-42 (AC-19) The degraded line appears when ISSUE_NUMBER is set and no line is accepted, never for none or empty — method:ci [files: tests/seams/pr-link-handoff.test.ts]
  • TP-43 (AC-20) Every fence passing ISSUE_NUMBER also passes ISSUE_PR_LINK, and at least one fence is found — method:ci [files: tests/seams/pr-link-handoff.test.ts]
  • TP-44 (AC-20) The same fence check passes on the unedited base, so it is a characterization, not RED — method:local [files: tests/seams/pr-link-handoff.test.ts]
  • TP-45 (AC-21) Byte budget rows show zero net growth, the PR-open floor holds, and references stay within baselines — method:ci [files: tests/tracker/byte-budget.test.ts]
  • TP-46 (AC-22) Five settle cases pass on the unedited base, including the 90000 ms boundary and 89999 ms — method:local [files: tests/evidence/ci-wait.test.ts]
  • TP-47 (AC-23) Characterization and window tests pass unedited after the helper refactor — method:ci [files: tests/evidence/ci-wait.test.ts]
  • TP-48 (AC-23) Exports, constants, source scan pins and callers stay unchanged — method:ci [files: tests/evidence/merge-readiness.test.ts]
  • TP-49 (AC-24) Value pins for the five audit limits pass on the unedited base, and the byte self-comparison is gone — method:local [files: tests/core/claude-md-audit.test.ts]
  • TP-50 (AC-25) Audit cases, truncation branches and hop order give identical output after the split — method:ci [files: tests/core/claude-md-audit.test.ts]
  • TP-51 (AC-25) walkRoot is at most sixty lines, only it writes the context, and no members destructure remains — method:ci [files: src/assets/scripts/claude-md-audit.cjs]
  • TP-52 (AC-26) The PR body and issue comment show function 94 lines and loop 55 lines — method:manual
  • TP-53 (AC-27) The compliance KB names the install-time stamp gate and has no run-time probe wording — method:local [files: .devflow/features/compliance-feature/KNOWLEDGE.md]
  • TP-54 (AC-28) The waves KB has no caret one rule, and names the baseSha rule and the verify-evidence publish step — method:local [files: .devflow/features/dynamic-workflow-engine-waves/KNOWLEDGE.md]
  • TP-55 (AC-29) The tracker-guards KB is at or below 39925 characters and has no Phase 10b text — method:local [files: .devflow/features/test-harness-tracker-guards/KNOWLEDGE.md]
  • TP-56 (AC-30) The prompt-install exception row no longer needs the flag and names the hook as a pointer only — method:local [files: .devflow/features/test-harness-prompt-install/KNOWLEDGE.md]
  • TP-57 (AC-31) Rule IDs equal the base, updated is set, and each edited KB is at or below 40000 characters — method:local [files: .devflow/features/*/KNOWLEDGE.md]
  • TP-58 (AC-32) The git agent golden is byte-equal, the install snapshot stays green, and the frozen status file is unchanged — method:ci [files: tests/install-snapshot.test.ts]
  • TP-59 (AC-33) Validate runs both full suites under the heavy tests lock, and both are green — method:local [files: tests/**/*.test.ts]
  • TP-60 (AC-34) The PR text shows the behaviour changes, the follow-ups, the platform wording and no planning IDs — method:manual
  • TP-61 (AC-35) The ref_preflight_branch define, its export and its shared rules row are removed, and no tracker text calls it — method:ci [files: tests/provider-literals.test.ts]
  • TP-62 (AC-36) The settle comparison appears once in the helper, and the helper is called once per window — method:ci [files: src/assets/scripts/ci-wait.cjs]
  • TP-63 (AC-37) Without the opt-in both live files are excluded, and no live spawn or init runs — method:ci [files: vitest.integration.config.ts]
  • TP-64 (AC-37) With the opt-in set to 1, true or yes, both live files are collected — method:ci [files: vitest.integration.config.ts]
  • TP-65 (AC-38) Frozen anchor lines are recorded before the first prompt edit, and each prompt keeps their order — method:local [files: src/assets/mds/git/_ops_steps.mds]
  • TP-66 (AC-39) No planning ID appears in committed text or commit messages, and repository rule IDs are unchanged — method:local
  • TP-67 (AC-40) Each Code brief names only its phase's test files, and only Validate runs the full suite — method:manual
  • TP-68 (AC-40) Every targeted command in the briefs names its test files and removes both credential variables — method:local
  • TP-69 (AC-41) The PR body has a Disputed findings section that reads none unless disputed with evidence — method:manual
  • TP-70 (AC-42) The already-up-to-date halt shows a fixed reason that says what to do next and echoes no SHA — method:ci [files: tests/dynamic/wave-flow.test.ts]
  • TP-71 (AC-43) Each new platform fact row carries the date 2026-10-14 and a drift symptom — method:local [files: docs/reference/platform-assumptions.md]
  • TP-72 (AC-44) The probe and live results reach the resume file and one issue comment, with no new issue filed — method:manual
  • TP-73 (AC-45) Init runs in a temp directory that is not a repository, and checkout status is equal before and after — method:ci [files: tests/integration-spawn-context.test.ts]

dean0x added 20 commits October 14, 2026 20:08
…dy states

The wave partial repeated the undo gates and the exact reset line that the
wave loop's undo spawn already pins. The partial now points at the fence and
keeps the two prohibitions: never a hard reset, never a push.

Frees 210 bytes in each dynamic-build variant.
… on a bad or unchanged SHA

The merge prompt now checks out the integration branch, records its head as
baseSha, merges with --no-ff and aborts on a conflict. A failed abort returns
merged true with no mergeSha. The workflow halts before Validate unless
mergeSha and baseSha are both 40-hex and differ, with one fixed reason for a
bad SHA and one for an unchanged head. Both SHA fields in the halt record are
null, so no rejected value is copied.

Comments the wave fence already states are shortened to stay within the
dynamic-build size ceilings.
…helper

The merge arm of the per-ticket loop sat seven block levels deep. One async
helper now holds the merge, the post-merge Validate and the undo, with early
returns. It returns kept, reason, halted and treeEqual and reads only agent
and the wave argument names. The loop keeps the verdict check first after the
engine call and now sits four levels deep.

The build-mds test gains a depth guard (no loop line more than five levels
below the while) and a helper guard, each with a seeded known-bad probe.

Behaviour is unchanged. The refactor and a few redundant comments removed
free about 310 bytes in each compiled variant.

Refs #486
The undo reset to the merge commit's first parent. After a fast-forward merge
that parent is the ticket's own earlier commit, so part of a failed ticket
stayed on the integration branch.

The undo now runs three read-only checks in order: HEAD names the integration
branch, the branch head equals the merge SHA, and the merge's first parent
equals the recorded baseSha. A non-zero exit or a different value means not
undone. Only then does it run git reset --keep on baseSha. It returns the
branch head, and the workflow counts the undo as done only when that head
equals baseSha. Any other result halts the wave, and the halt record now
carries baseSha.

A real-git test runs the merge, baseSha and undo lines parsed from the built
prompt. A merge commit over a two-commit ticket returns to baseSha with both
ticket commits unreachable. A true fast-forward, a detached HEAD and a
conflicting local change are each reported not undone, and an unrelated dirty
file survives. The build-mds collectors pin the exact merge and reset lines
and refuse a caret reset, a hard reset and a push. The report's Halted bullet
names the bad or unchanged SHA halt.

Refs #486
The undo fix and the wave helper cut dynamic-build to 106,930 bytes
(learning on) and 103,543 bytes (learning off). Lower both ceilings, their
numeric-floors rows and the command-size literals to those sizes, with no
headroom, as the other rows do. No ceiling rises.

Part of #486
The waves KB still said a red merge is undone by a caret-one reset. The
command now records baseSha before the merge, merges with --no-ff, halts
before Validate on a bad or equal SHA, and resets to baseSha only when the
returned head equals baseSha. State that rule in KB-INV-5 and in the wave
execution step.

Step 7 of the wave PR evidence also changed: the workflow runs
verify-evidence publish inline, with no Git agent spawn. Correct that line.
Rule IDs stay. Set updated to 2026-10-14.

Part of #486
The byte and path limits were compared with themselves, so a changed
limit passed. Pin MAX_BYTES_READ, SCAN_BYTES, SKIP_FILE_BYTES and
MAX_PATHS_PER_ROOT by value. Add the truncation branches the walk had no
test for: a cut scan marks the root and its chain line, a spent budget
marks a later root, an exact budget is not a cut, an empty import, and the
exact edge of the path and file-size limits.

Refs #486
Pin how the head-mismatch window and the empty-checks window behave
today: a pending poll resets the empty clock, a mismatch does not carry
into the empty window, a failed poll leaves both clocks as they were,
and each window settles at exactly 90,000 ms and not at 89,999 ms. The
cases use a virtual clock, with no call longer than 25 s.

Refs #486
The head-mismatch window and the empty-checks window each spelled out the
same open-the-window and compare-to-90-seconds steps. Move them into one
pure settle(firstAt, now, settleMs) helper. Each window keeps its own
clock, the gh call order and the exports are unchanged, and the settle
comparison now appears once. A source guard checks that.

Refs #486
walkRoot was 94 lines and did four jobs. Move the head scan into
scanImports, which returns the tokens, the bytes read and whether the run
budget cut the scan, and touches nothing outside itself. Move the root
figures into summarizeMembers, a pure step after the loop that reads the
members in breadth-first order. walkRoot is now 53 lines and the only
function that changes the run context. The result no longer carries a
members list for audit() to drop. The output and the hop check order are
unchanged. Source tests check the line limit and the single writer.

Refs #486
…d branch-name closing paths

Step 4a now treats a supplied ISSUE_PR_LINK, "(none)" included, as the
section's final answer. Only an absent link reaches step 4b, and only when no
admitted wave block exists. An empty Related Issues heading is written only
when ISSUE_NUMBER is set, and a set ISSUE_NUMBER with no admitted line reports
the existing ambiguous-issue-reference reason.

GitHub step 4b renders only the setup-task link line, through the step 4a
shape check, and no longer composes a closing line from a bare number or a
branch name.

Tests: new cases for a supplied none, the degraded line, a composing step 4b
and a heading with both keys none; a characterization that every fence passing
ISSUE_NUMBER also passes ISSUE_PR_LINK; the pinned phrases are updated.
…ear step 4b

Jira and Linear step 4b fell back to the branch name pattern and built a
reference from it. A token in a branch name can look like an issue key
and name another issue, so the PR could carry a wrong reference.

Step 4b now takes the key or reference returned by setup-task and
ensure-traceable-issue as its only source, says never to compose a line
from a bare issue number or a branch name, and publishes the rendered
line only if it passes the step 4a shape check. The fetch-by-key
degradation stays as option b.

The ref_preflight_branch define, its export and its shared-rules row had
no other caller, so they are removed.

Tests: a negative pin for GitHub, Jira and Linear (no branch-derived
text, no composing step 4b), a probe per provider with a seeded branch
fallback, and a check that no tracker source names the removed define.
…t the skip flag

The live claude files ran with the skip-permissions flag, in the real
checkout and under the real HOME, so a spawned agent could write there.

createSpawnContext now builds a temp HOME and a new temp git repository
(no remote, nothing copied from .git or .devflow). installDevflow runs
the built init into that HOME from a second non-repository temp
directory, with memory, learning, ambient, knowledge, rules and proxy
off, and checks that the checkout status does not change. Both spawns
run in that context with one credential, no redirect variable, the
dontAsk mode, one allowed tool, a six-tool deny list and an empty strict
MCP config. The prompt directly follows -p, so no list flag can take it.
A live file without claude or a credential skips and prints why.
… in tests

Add a static guard over tests/ that requires an env and a cwd on every claude
spawn and on every node child in the integration files and the spawn-context
test, and refuses the skip-permissions flag and bypassPermissions in a claude
spawn and anywhere under tests/integration. Seeded probes and a mutation of
every real spawn site keep it live.

The ambient live file joins the preload file in the integration opt-in
exclusion: both are collected only for DEVFLOW_INTEGRATION_ALL set to 1, true
or yes. The gate test checks both files in each branch against the include
list. The comments and one test title that described the old live-test setup
now describe the temp HOME and temp repository each live file builds.
…486

Platform assumptions: the live claude tests are opt-in, run in a temp HOME and a temp repository, and use an explicit permission mode and deny list instead of the skip flag. A new row records the deny-rule assumption as unverified, because no credential was set for a probe or a live run.

Compliance KB: the /code-review language focuses are gated by the install-time stamp line, never by a run-time probe or by presence.

Tracker-guards KB: drop the Phase 10b clause and point to numeric-floors.json without numbers.

Prompt-install KB: describe both live files, their temp HOME and repository, the permission design and the spawn guard. The skip flag stays only as a pointer to follow-up #497 for the background memory hook.
- Keep the tracker-guards KB at or below its character cap: condense
  three clauses of the ops paragraph. No fact is removed.
- Name both live claude files in the platform-assumptions rule on the
  glob-time exclusion.
- Give the ambient live file the opt-in run command. A plain
  `npm run test:integration` now excludes it.
- Refer to the findings by the numbers that issue #486 uses, not by
  labels from the plan.
@dean0x

dean0x commented Oct 14, 2026

Copy link
Copy Markdown
Owner Author

Code Review — Cycle 1

Full summary withheld (public repository).

Category CRITICAL HIGH MEDIUM LOW Total
Blocking - - 11 3 14
Should Fix - - 1 3 4
Pre-existing - - 1 - 1
Total - - 13 6 19

Full report: .devflow/docs/reviews/fix-486-rereview-high-findings/2026-10-14_2309/review-summary.md (not committed; ask the author)
Posted by devflow · cycle 1

…e helper (#486)

- Check the Git-reported ticket branch in code before the merge spawn: the
  repo ref allowlist, no leading dash, no double dot. A refused name
  quarantines the ticket with a fixed reason and spawns no merge. The
  value is never repaired or copied.
- Give the halted record a fixed kind (red, bad-sha, unchanged). The
  Halted line in step 3 renders fixed text per kind and no agent value, so
  a merge that added no commit no longer reads as a red HEAD.
- Give an undo that reports done with another head a fixed reason.
- Tell the Git agent to run git merge --abort when the merge stops for any
  reason, so a refusing commit hook no longer leaves MERGE_HEAD behind.
  A real-git test shows both the stuck state and the abort.
- Name the merge helper in the undo doctrine and state that Validate runs
  after every merge except when a bad or unchanged SHA halts the wave first.
- Pay for the added bytes with cuts of duplicate wording in the same
  files, and lower both dynamic-build size ceilings to the new sizes.
Step 4b in the GitHub, Jira and Linear references kept the shape of the
removed branch fallback. GitHub named a producer that returns no Handoff
Values block. Jira and Linear listed one source under a resolution order, kept
a fetch-by-key gate for a call that step no longer makes, and offered a
bare-key fallback that step 4a's shape check can never admit.

One shared define in the tracker common module now holds the step: the link
line comes only from the Handoff Values block of setup-task or fetch-issue, is
published only when it passes step 4a's check, is refused in step 4a's words,
and is never composed by the step. Each provider keeps its own first sentence
and its rendering note; the discarded-token fallback now renders the documented
default, which passes the check. The git ops steps text no longer mentions a
branch-pattern check, and the common module header counts the three remaining
ref pre-flight heads.

The seam guard drops its fetch-by-key exception and holds all three providers
to the one form, and the op-mention row for step 4b names setup-task and
fetch-issue.
- The skip-reason test now passes a credential to the one path that takes
  one and returns text, so a reason that printed the value would fail it.
- The two cleanup tests assert on the exact cwd and HOME paths the injected
  runner saw, not on a listing of the shared temp dir that other runs write to.
- Add dispose tests: a path outside the temp root, a sibling that shares the
  temp-root prefix and a path that climbs out of it are refused, the other
  directory is still removed, and the first error is the one thrown.
- Compare only the paths devflow init writes before and after an install, and
  print the differing status lines on failure.
- The spawn guard now matches shell-string claude calls (exec and execSync),
  with the claude --version probe in the helper file as the only exemption.
- Give the real-git undo tests a 60 s budget above the 20 s per-call git budget, so the default 5 s test timeout cannot fire first.
- Pin the fast-forward refusal to the first-parent check by its exact reason, not to any check that prints another value.
- Compare the merge prompt's baseSha order only when both lines exist, so a missing --no-ff line reports one defect. Add a probe for a baseSha recorded after the merge.
- Name the fake gh default call time in the CI wait test.
- Add undo replies with no head and with a head that is not hex. Both halt the wave as a refused undo.
- CHANGELOG: name the ticket branch check, the halt when a merge adds no
  commit, the missing wave PR on a halt, and the halt reason in the run
  summary. A failed post-merge build is the undone case, not a conflict.
- Wave KB: the first parent of mergeSha is baseSha whenever the merge adds
  a commit. The halted record renders fixed text per kind, and mergeSha
  only for kind red. State the branch check and the three halt kinds.
- Test-harness KB: the live-claude tests build a temp HOME and temp repo
  and run init there; they do not use the real ~/.claude.
- Rename LIVE_CLAUDE_TEST to LIVE_PRELOAD_TEST so it is parallel to
  LIVE_AMBIENT_TEST; it names only the preload file.
- Match the integration config's exclude list as globs, as include is,
  so a glob exclude that covers a live file is detected. A trailing **
  now reads as any depth. Add cases for a glob exclude that covers a
  file and for one that does not.
- Point the permission-mode note in both live files at the args builder
  that sets it, and give both the same Run note.
@dean0x

dean0x commented Oct 14, 2026

Copy link
Copy Markdown
Owner Author

Resolution Summary

Full summary withheld (public repository).

Metric Value
Total Issues 34
Fixed 25
False Positive 0
By Design 2
Deferred 2
Blocked 0
Escalated 0
Duplicates Collapsed 5

Full report: .devflow/docs/reviews/fix-486-rereview-high-findings/2026-10-14_2309/resolution-summary.md (not committed; ask the author)
Posted by devflow

@dean0x

dean0x commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner Author

Test Plan Evidence — 23f450b

Verified 53/73: VERIFIED-CI 44, ATTESTED-LOCAL 9, UNVERIFIED 10, STALE 10, FAILED 0, INDETERMINATE 0

  • TP-1 ATTESTED-LOCAL sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS exit:0 h:cea138ec6871
  • TP-2 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:18b453630631
  • TP-3 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:b76572fe2bea
  • TP-4 STALE sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:PASS exit:0 h:1257f347b97c
  • TP-5 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:ce4a69792859
  • TP-6 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:c2550fbe9616
  • TP-7 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:4bf4b1b30cf4
  • TP-8 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:9e2e075da1c3
  • TP-9 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:eda17797ce23
  • TP-10 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:f3fbdb19e873
  • TP-11 STALE sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:FAIL exit:1 h:23f5b8a06b3e
  • TP-12 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:9edff34a13df
  • TP-13 STALE sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:PASS exit:0 h:84cda487abd7
  • TP-14 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:05db77211421
  • TP-15 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:32784f4563ea
  • TP-16 VERIFIED-CI sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS run:38629000437/1 exit:0 h:9d1841a6801f
  • TP-17 VERIFIED-CI sha:23f450b9464dcfe3350e3cdf4f3d61cb48359d8a out:PASS run:38707263598/1 h:41bd71ca66e2
  • TP-18 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:23660941c5d8
  • TP-19 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:d6ee5af4544f
  • TP-20 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:27331183b9b5
  • TP-21 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:abc43fd8e5b0
  • TP-22 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:03f33fce75f1
  • TP-23 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:9ac68ed5ed6f
  • TP-24 VERIFIED-CI sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS run:38629000437/1 exit:0 h:3189f70f69c0
  • TP-25 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:d8d513a6c2b3
  • TP-26 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:32989279b65d
  • TP-27 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:6948eec7f117
  • TP-28 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:73f6639f87ea
  • TP-29 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:2078f7cf3584
  • TP-30 UNVERIFIED sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:SKIP h:f86ef3d167dd
  • TP-31 UNVERIFIED sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:SKIP h:d8837efd59c0
  • TP-32 UNVERIFIED sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:SKIP h:9e4d966b4d33
  • TP-33 UNVERIFIED sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:SKIP h:623bbdacecbb
  • TP-34 ATTESTED-LOCAL sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS exit:0 h:726934d0fc22
  • TP-35 VERIFIED-CI sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS run:38629000437/1 exit:0 h:d30c1ae28384
  • TP-36 ATTESTED-LOCAL sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS h:669b7d7ebb20
  • TP-37 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:070a23db96d3
  • TP-38 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:b6e5473830f2
  • TP-39 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:8688c7f176f4
  • TP-40 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:c52be00c3fc7
  • TP-41 VERIFIED-CI sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS run:38629000437/1 exit:0 h:afaaf8133b12
  • TP-42 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:316703663a6d
  • TP-43 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:186e149b175e
  • TP-44 STALE sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:PASS exit:0 h:e67284142867
  • TP-45 STALE sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS exit:0 h:75f1424e6ae8
  • TP-46 ATTESTED-LOCAL sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:PASS exit:0 h:50042a81b70a
  • TP-47 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:e1286fc25160
  • TP-48 VERIFIED-CI sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS run:38629000437/1 exit:0 h:1a8fd0ed72fe
  • TP-49 ATTESTED-LOCAL sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS exit:0 h:42c4e06b6fab
  • TP-50 VERIFIED-CI sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS run:38629000437/1 exit:0 h:4a971eefa1b2
  • TP-51 VERIFIED-CI sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS run:38629000437/1 exit:0 h:8d7f1f2c35ef
  • TP-52 UNVERIFIED sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:SKIP h:4ace35ac60cb
  • TP-53 STALE sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS exit:0 h:371537999493
  • TP-54 STALE sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:PASS exit:0 h:5671b2ed7e09
  • TP-55 ATTESTED-LOCAL sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS exit:0 h:af2b082394ce
  • TP-56 ATTESTED-LOCAL sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS exit:0 h:31e814054218
  • TP-57 STALE sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:PASS exit:0 h:041f71353b02
  • TP-58 VERIFIED-CI sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS run:38629000437/1 exit:0 h:0ce6cae305e5
  • TP-59 UNVERIFIED sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:SKIP h:3bb8601aeac1
  • TP-60 STALE sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:FAIL h:8c0a72ef1681
  • TP-61 VERIFIED-CI sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS run:38629000437/1 exit:0 h:65d9294f2e2f
  • TP-62 VERIFIED-CI sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS run:38629000437/1 exit:0 h:caa8a9cde441
  • TP-63 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:af6b40452e7c
  • TP-64 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:9ef2e88767e8
  • TP-65 ATTESTED-LOCAL sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:PASS exit:0 h:72cd5596d966
  • TP-66 STALE sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:FAIL h:a102f3bec732
  • TP-67 UNVERIFIED sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:SKIP h:05f9d14d62ee
  • TP-68 UNVERIFIED sha:83e2d7a7ed593bd98a535bbea6d60b4863bbad92 out:SKIP h:d862e1b58707
  • TP-69 UNVERIFIED sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:SKIP h:1acc92c4569a
  • TP-70 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:0d3b12d64f56
  • TP-71 ATTESTED-LOCAL sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:PASS exit:0 h:4ef377513a06
  • TP-72 UNVERIFIED sha:24d93527bfec4deedc1c9635e10676eb26558e9f out:SKIP h:17ba4f5e0540
  • TP-73 VERIFIED-CI sha:33044903d780ff0c3e6108263c1cc9ab0e0cc58c out:PASS run:38653411115/1 exit:0 h:da1937915898

@dean0x

dean0x commented Oct 14, 2026

Copy link
Copy Markdown
Owner Author

Code Review — Cycle 2

Full summary withheld (public repository).

Category CRITICAL HIGH MEDIUM LOW Total
Blocking 0 1 6 6 13
Should Fix - - - 1 1
Pre-existing - - 0 0 0

Full report: .devflow/docs/reviews/fix-486-rereview-high-findings/2026-10-15_0121/review-summary.md (not committed; ask the author)
Posted by devflow · cycle 2

dean0x added 12 commits October 15, 2026 01:42
Bring in the GATE_LEVEL settings line and machine default. The merge had
no conflicts. The compiled dynamic-build command stays under both byte
ceilings, so no ceiling changed.
The live-file install builds a temp HOME and a temp repository, then installs devflow into that HOME. init runs from a separate directory that is not a repository. The install fails when a path that init writes changes in the checkout.
The two-gate-shapes entry now names the rule that the claude-dir guard still holds: no prompt reads a path under the home Claude directory outside the CLAUDE_CONFIG_DIR rule.
Step 4b runs only when the PR link is absent and no wave block is admitted. It takes only the Handoff Values link line, composes no line, refuses a bad line in step 4a's words, and skips silently when there is none.
The disposeSpawnContext describe kept thrownMessage local and the
checkout-status describe repeated it as an inline function. Move it to
file scope and call it from both places.
Add a Changed entry for the PR link and wave ticket branch rules, and name the merge or base SHA in the Fixed entry.
The "climbs out" row built its path with path.join, which folds the
".." away before the guard sees it, so it repeated the first row. Build
it as text so the segment survives. Add a row for a link under the temp
root that points outside it: a guard that does not resolve links lets
it through, and rmSync would then remove only the link.
The guard missed path-qualified binaries, the launchers npx, sudo,
nice, xargs, timeout and env flags, the separators &, backtick, { and
!, shell keywords such as then and do, quoted program names, and a
command string given to spawn, spawnSync, execFile or execFileSync.
Build the command-string regexes from named parts, accept a path
before the name, add the missing launchers and separators, and add the
argument-list arm. Each new form has a known-bad probe through the
guard's own collector. Forms that stay out of scope are named in the
header, and each has a "does not match" probe.
…that began (#486)

The wave merge prompt told Git to run git merge --abort whenever a merge
stopped. A merge that never began (a missing ref, local changes it would
overwrite, unrelated histories) leaves no MERGE_HEAD, so the abort exited 128
and the wave halted as bad-sha although nothing had merged. The prompt now
aborts only when git rev-parse -q --verify MERGE_HEAD succeeds, and a merge
that did not begin returns merged false with the reason.

The ticket branch comes from a lower-trust agent. The check now refuses a
value that is not a string, a leading # (the shell reads it as a comment), and
the revision names HEAD, @, FETCH_HEAD, ORIG_HEAD and MERGE_HEAD. The merge
prompt verifies refs/heads/<name> first and merges that ref, so a tag, a SHA or
a remote ref never merges.

Tests: real-git cases for a missing ref, a tag and a SHA; refused probes for
#7-x, the revision names and a branch that is not a string; a seeded probe for
each collector arm, including the late check and the loose allowlist. The
wave-flow describe title now states the rule instead of a review label. The
byte growth is offset by cutting wave doctrine that restated the helper.
…ed record (#486)

Describe the local-branch check, the abort that runs only for a merge that
began, the string and allowlist check on the ticket branch, and the five
fields of the halted record.
#486)

The shared step 4b takes only the Handoff Values link line, composes no
line and skips silently when there is none. The Jira and Linear notes
still told the step to render the key or reference as the documented
default when the rendering section was absent, so an agent could publish
a reference the shared text forbids.

Each note now covers closing effects only. The rendering gate and the
documented-default paragraph in these two ensure-pr-ready references
served no step and are removed; create-release keeps both. The first
sentence takes the link form from pr_link_default. The section-14.3
claim rows and the render-site set in schema-scope now name create-release
as the only operation that renders the token.
collectStep4bComposition now reports a step 4b block that tells the agent
to render the key or the reference, or that names the rendering section.
The known-bad probe seeds the removed Jira and Linear sentences and the
leading rendering sentence through the same collector, and checks that
each seed lands.
@dean0x

dean0x commented Oct 14, 2026

Copy link
Copy Markdown
Owner Author

Resolution Summary

Full summary withheld (public repository).

Metric Value
Total Issues 14
Fixed 14
False Positive 0
By Design 0
Deferred 0
Blocked 0
Escalated 0
Suggestions adopted 1 of 5
Follow-ups filed 1 (#511)

Full report: .devflow/docs/reviews/fix-486-rereview-high-findings/2026-10-15_0121/resolution-summary.md (not committed; ask the author)
Posted by devflow

dean0x added a commit that referenced this pull request Oct 15, 2026
…s after #472 (#514)

## Summary

PR #508 cut 76 bytes from each command that carries the settings line.
It did not change the command byte ceilings. This PR lowers the ceilings
to the measured sizes on main (8875e09). The slack is now 0 for each
changed row.

Only ceiling values change, in `tests/guards/command-size.test.ts` and
`tests/fixtures/numeric-floors.json`. The `description` of each changed
fixture row now states the new measured size. No prompt text changes.

## Ceilings

| Command | On: old → new | Off: old → new |
|---|---:|---:|
| bug-analysis | 25065 → 24966 | 21077 → 21056 |
| debug | 19967 → 19885 | 17046 → 16966 |
| dynamic-plan | 36994 → 36880 | 32557 → 32530 |
| dynamic-profile | 16487 → 16389 | 12684 → 12673 |
| dynamic-tickets | 41450 → 41336 | 37156 → 37129 |
| explore | 12944 → 12866 | 10040 → 9964 |
| implement | 49883 → 49807 | 47029 → 46953 |
| plan | 38096 → 38018 | 35126 → 35050 |
| release | 22903 → 22825 | 19609 (no change, already exact) |
| research | 14972 → 14894 | 10838 (no change, already exact) |
| resolve | 52422 → 52287 | 49220 → 49087 |
| self-review | 15889 → 15691 | 12801 → 12619 |

Sizes are in bytes.

### Not changed here

- `code-review` (on and off): open PR #512 changes this command and its
ceilings.
- `dynamic-build` (on and off): open PR #505 changes this command and
its ceilings.

Those PRs set their own ceilings. Open PR #513 changes no command and no
ceiling.

## Evidence

- `npm run build` on a clean tree: exit 0, 33 compiled, 0 errors, 0
warnings.
- The measured sizes equal the slack table in the #508 PR body. There
are no differences.
- `npx vitest run tests/guards/command-size.test.ts
tests/guards/numeric-floor-manifest.test.ts`: 2 files, 16 tests pass.
- `npx tsc --noEmit`: exit 0.
- CI: see the checks on this PR.

## Breaking Changes

None. The change is in test constants only.
@dean0x
dean0x merged commit 7ae1b5d into main Oct 15, 2026
3 checks passed
@dean0x
dean0x deleted the fix/486-rereview-high-findings branch October 15, 2026 08:53
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.

Re-review of PRs 436, 440, 459: 7 HIGH findings still on main

1 participant