Skip to content

compiler-parity: autoMerge accepts a non-boolean, silently flipping the compiled merge policy (issue #183) - #184

Draft
ruvnet wants to merge 3 commits into
mainfrom
dream/2026-10-15-compiler-parity
Draft

ruvnet wants to merge 3 commits into
mainfrom
dream/2026-10-15-compiler-parity

Conversation

@ruvnet

@ruvnet ruvnet commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Closes #183.

Hypothesis

Given a dream.config.json whose autoMerge value is present but not a boolean (e.g. the string "no", "false", or any other truthy/falsy non-boolean), when validateConfig() is extended to reject it, then dream-machine compile should report a structured ValidationResult error instead of silently compiling a prompt whose STEP 20-25 merge-policy section reflects JS truthiness of the raw value rather than the config author's intent — subject to: zero behavior change for any well-formed boolean value, including this repo's own self-hosted dream.config.json (autoMerge: false), and zero regression in the existing test suite or golden snapshots. Confirmed, not amended after evaluation began.

Candidate

packages/compile/src/config.ts (validateConfig()): one new check, mirroring the existing buildStep.degradeOnWasmFailure guard —

if (config.autoMerge !== undefined && typeof config.autoMerge !== 'boolean') {
  errors.push('autoMerge must be a boolean');
}

packages/compile/src/index.test.ts: +7 tests — non-boolean rejection ('no', 'false', 0, 1, 'true'), boolean acceptance, optional-omission, plus three compile()-level tests proving the real-world consequence (pre-fix a truthy non-boolean compiled the guarded-auto-merge-ENABLED policy text).

docs/dream-cycle/2026-10-15-compiler-parity-report.md: full evidence report (GIST=LOCAL, committed per STEP 17-18's best-effort policy — no gh CLI auth or gist MCP tool this session).

+11/-0 net lines across the two source files, well under the 300-line target, one conceptual change.

Evaluation Receipt

Real evaluator: npm test (vitest run && npm run test:governance).

vitest governance
Parent (baseline, b2abcc1) 809 passed 195/195 passed
Candidate 820 passed (+11, all new) 195/195 passed (unchanged)

npm run lint/npm run typecheck clean. Self-hosted dream.config.json compiles byte-identical before/after, independently re-confirmed by an adversarial critic subagent from a separate run.

Baseline

Parent commit b2abcc14a632d7e0948962065a7c6c8920cf306c (main), measured live via git stash/git stash pop on this session's own checkout — not inferred from logs. Baseline's own fresh shallow clone initially failed 3/195 governance tests on the already-filed, already-open issue #149/PR #150 (BASELINE_COMMIT git-show oracle on a shallow clone); resolved session-locally via git fetch --depth=1 origin <that exact pinned SHA> before the baseline run, so it is not conflated with this candidate's regression count (same handling as the 2026-10-10 report).

Darwin Lineage

DARWIN=not-applicable — single validation-shape fix, no evolvable population or numeric objective, consistent with unbroken precedent (#29, #79, #105, #111, #127, #142/#143, #164/#165).

Evidence

OBSERVATION (zero type check, bare-truthy downstream read) → OBSERVATION (live pre-fix repro: autoMerge: "no" compiles "guarded auto-merge ENABLED") → HYPOTHESIS (frozen above) → MEASUREMENT (809/195 → 820/195, live before/after) → INFERENCE (independent critic's own grep found the only other autoMerge consumer, scripts/automerge-guard.mjs, already uses strict === true equality, never exposed) → DECISION (ship; ACCEPT).

Reward-Hack Check

Independent adversarial critic (separate subagent context, no authorship stake, read the live diff and repo state directly): CLEAR on first pass. Verified autoMerge: null is also rejected (closing an obvious bypass: null !== undefined and typeof null !== 'boolean'). Verified the only other real consumer of this field, scripts/automerge-guard.mjs's evaluateGuard/inspectPullRequest, already uses strict boolean equality (config.autoMerge !== true) and so was never exposed to this defect. Independently rebuilt and reran the full suite (820/820 vitest, 195/195 governance, 0 regressions) and re-compiled the self-hosted config twice (byte-identical both times). Confirmed via its own search_issues/search_pull_requests calls this is not a duplicate. No fixture/threshold/gold-answer touched at any point; no test weakened.

Security Review

Pure in-memory type validation — no new I/O, credential, network, or tool/MCP authority surface. Closes a (low-severity, config-authoring-time) integrity gap in this self-hosting system's own authoritative control-plane compiler. Does not grant, and could never grant, auto-merge or self-promotion authority — only prevents the textual description of that policy from silently inverting in a compiled prompt. The one other real-world consumer of this field (CI-facing scripts/automerge-guard.mjs, which gates actual auto-merge eligibility) was confirmed never exposed, since it already uses strict equality.

Regression Analysis

0 regressions: vitest 809→820 (+11, all new), governance 195/195 unchanged. No existing test weakened, no threshold changed, no gold data touched. Independently re-verified by the critic from a from-scratch rebuild.

ADR

None — parameter/validation-shape fix, consistent with every prior compiler-parity fix of this shape (#29, #79, #105, #111, #127, #142/#143, #152, #164/#165 — none has an ADR).

Gist

GIST=LOCAL — no gh CLI (invalid token this session) or gist-creation MCP tool available. Full report committed at docs/dream-cycle/2026-10-15-compiler-parity-report.md.

Issue

#183

Witness

report_sha256 : 3169cdad4ee28c9b2fd78f98e1ced4ffd5ff918ca72b3729dc4724aef26cef9a
session_commit: b2abcc14a632d7e0948962065a7c6c8920cf306c
witness       : 316c77d1902ce2bcbe5eab6f13165e41c2385df39279ada2d25fd705e7cec886

Reproduce: node packages/cli/dist/bin.js witness verify-report docs/dream-cycle/2026-10-15-compiler-parity-report.md --commit b2abcc14a632d7e0948962065a7c6c8920cf306c

Merge Policy

Human review required. This session never self-merges and never autonomously promotes candidate state. No automerge-safe label applied.


🤖 Generated with Claude Code

https://claude.ai/code/session_01DQn3topashe98CEmrcK2zm


Generated by Claude Code

…he compiled merge policy (issue TBD)

validateConfig() had zero type check for the optional autoMerge boolean.
withDefaults()'s `?? false` only catches undefined/null, so a value like
the string "no" is JS-truthy and step20to25PublishFlow's bare `autoMerge
? enabled : disabled` ternary compiled "guarded auto-merge ENABLED" into
this self-hosting system's own authoritative nightly prompt -- the
opposite of what a config author writing "no" would expect. Same
inversion-on-a-truthy-non-boolean class already fixed for
buildStep.degradeOnWasmFailure (issue #142/PR #143).

Adds a typeof check mirroring the existing degradeOnWasmFailure guard,
plus tests covering non-boolean rejection, boolean acceptance, optional
omission, and the compiled merge-policy text for both true/false/absent.

npm test: vitest 809->820 (+11 new), governance 195/195 unchanged, 0
regressions. lint/typecheck clean. Self-hosted dream.config.json
compiles byte-identical.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQn3topashe98CEmrcK2zm
GIST=LOCAL (no gh CLI auth, no gist-creation MCP tool this session).
Witness self-verified against session commit b2abcc1.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DQn3topashe98CEmrcK2zm

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants