Skip to content

FE-1241: Add isolated brownfield comparison cases#362

Merged
kostandinang merged 15 commits into
nextfrom
ka/fe-1241-brownfield-comparison-cases
Jul 23, 2026
Merged

FE-1241: Add isolated brownfield comparison cases#362
kostandinang merged 15 commits into
nextfrom
ka/fe-1241-brownfield-comparison-cases

Conversation

@kostandinang

@kostandinang kostandinang commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Why

The greenfield Petri case does not prove that exact handoff, repository preparation, and solution isolation hold inside real brownfield repositories. This adds representative backend and frontend replays without exposing historical solutions to either execution lane.

What

Add two frozen comparison profiles:

  • Brunch host landing — replays FE-1201/PR FE-1201: Land promoted runs on the host #336 and judges the public /brunch:land journey with black-box TUI evidence plus an independent full-range Git model.
  • Petrinaut optimization — replays PR #9051 on /optimization, using focused package preparation, a same-origin deterministic optimizer, declared mechanical addresses, and contrastive browser rivals.

Both profiles use the same admitted historical-replay pipeline:

pinned source
  -> synthetic source commit
  -> packet-only handoff commit
  -> controller-only dependency preparation
  -> Claude + Brunch isolation admission
  -> selected execution lane
  -> controller-owned compiled oracle

The admission boundary verifies the exact two-commit prefix, clean tracked source, closed dependency recipes, bounded filesystem access, disabled web/MCP surfaces, and denied historical-source network probes. Oracle reports are retained write-once beside a hash covering controller manifests, implementation modules, and runtime calibration inputs.

How to run a comparison

Run comparisons from a trusted top-level project Pi session in the Brunch repository. To list the available cases:

/compare-execution

The eligible case ids are:

  • minimal-petri-net-editor — greenfield; no source checkout required.
  • brunch-host-landing — brownfield; requires a Brunch checkout containing parent f5a423b19f76cf345d88053456870a126e451618.
  • petrinaut-optimization — brownfield; requires a HASH checkout containing parent 5c7a2d9db5caa851c38938f4b1bac19005b0e978.

For a greenfield run, use the guided workflow directly:

/compare-execution minimal-petri-net-editor

For a brownfield run, inspect the frozen public packet and prepare each executor in a fresh absolute target directory:

npx tsx src/dev/execution-comparison-operator.ts inspect \
  --case <brunch-host-landing|petrinaut-optimization>

npx tsx src/dev/execution-comparison-operator.ts prepare \
  --case <case-id> \
  --lane <brunch|claude_code> \
  --source-repository /absolute/path/to/source-repository \
  --target /absolute/path/to/fresh-target

Review the returned launch descriptor and run it unchanged. Keep exactly one executor lane live at a time, stop Brunch at promotion_prepared, and retain the target after process cleanup. Once the lane has terminated, run the compiled controller oracle with an absolute evidence path:

npx tsx src/dev/execution-comparison-operator.ts oracle \
  --case <case-id> \
  --app /absolute/path/to/retained-output \
  --out /absolute/path/to/attempt/browser/report.json

Repeat with a fresh target for the other executor. Preserve failed and invalid attempts; compare validity and requirement evidence before outcomes, and do not infer a general winner from one run. The full operator/evidence rules are in docs/praxis/comparison-runs.md.

Before the first Petrinaut provider attempt, run the required merged-reference preflight:

npx tsx src/dev/execution-comparison-operator.ts petrinaut-preflight \
  --source-repository /absolute/path/to/hash \
  --parent-target /absolute/disposable-work/parent \
  --reference-target /absolute/disposable-work/reference \
  --output-root /absolute/retained-evidence

A passing receipt is required under D138-L. The implementation-PR waiver is not reusable as campaign evidence.

Scope and evidence

  • Historical references, patches, controller expectations, and optimizer fixtures remain outside candidate targets.
  • Brunch and Claude receive the same frozen specification/public-contract bytes from the same pinned source.
  • Linux CI has portable admission coverage; the production network-denied verifier remains fail-closed on its supported host recipe.
  • The post-review hardening closes calibration-seed hashing, fixture-locator fallbacks, Brunch public-type drift, and ambiguous relative evidence paths.
  • No Petrinaut provider campaign was run. D138-L still requires a passing merged-reference preflight before any future first provider attempt.

How to test

  • npm run verify:full
  • npm run check
  • npx changeset status --since=origin/next
  • git diff --check origin/next...HEAD

Comment thread src/dev/execution-comparison/__tests__/historical-replay-target.test.ts Outdated
Comment thread src/dev/execution-comparison/__tests__/execution-comparison-brunch.test.ts Outdated
@semgrep-code-hashintel

Copy link
Copy Markdown

Semgrep found 2 detect-non-literal-regexp findings:

RegExp() called with a overrides function argument, this might allow an attacker to cause a Regular Expression Denial-of-Service (ReDoS) within your application as RegExP blocks the main thread. For this reason, it is recommended to use hardcoded regexes instead. If your regex is run on user-controlled input, consider performing input validation or use a regex checking/sanitization library such as https://www.npmjs.com/package/recheck to verify that the regex does not appear vulnerable to ReDoS.

View Dataflow Graph
flowchart LR
    classDef invis fill:white, stroke: none
    classDef default fill:#e7f5ff, color:#1c7fd6, stroke: none

    subgraph File0["<b>src/dev/execution-comparison/__tests__/historical-replay-target.test.ts</b>"]
        direction LR
        %% Source

        subgraph Source
            direction LR

            v0["<a href=https://github.com/hashintel/brunch/blob/5e1ed22b8c9bf153d017514aaf987584350e0892/src/dev/execution-comparison/__tests__/historical-replay-target.test.ts#L734 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 734] overrides</a>"]
        end
        %% Intermediate

        subgraph Traces0[Traces]
            direction TB

            v2["<a href=https://github.com/hashintel/brunch/blob/5e1ed22b8c9bf153d017514aaf987584350e0892/src/dev/execution-comparison/__tests__/historical-replay-target.test.ts#L734 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 734] overrides</a>"]

            v3["<a href=https://github.com/hashintel/brunch/blob/5e1ed22b8c9bf153d017514aaf987584350e0892/src/dev/execution-comparison/__tests__/historical-replay-target.test.ts#L234 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 234] portableDependencies</a>"]

            v4["<a href=https://github.com/hashintel/brunch/blob/5e1ed22b8c9bf153d017514aaf987584350e0892/src/dev/execution-comparison/__tests__/historical-replay-target.test.ts#L225 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 225] await</a>"]

            v5["<a href=https://github.com/hashintel/brunch/blob/5e1ed22b8c9bf153d017514aaf987584350e0892/src/dev/execution-comparison/__tests__/historical-replay-target.test.ts#L225 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 225] ready</a>"]

            v6["<a href=https://github.com/hashintel/brunch/blob/5e1ed22b8c9bf153d017514aaf987584350e0892/src/dev/execution-comparison/__tests__/historical-replay-target.test.ts#L275 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 275] `</a>"]
        end
            v2 --> v3
            v3 --> v4
            v4 --> v5
            v5 --> v6
        %% Sink

        subgraph Sink
            direction LR

            v1["<a href=https://github.com/hashintel/brunch/blob/5e1ed22b8c9bf153d017514aaf987584350e0892/src/dev/execution-comparison/__tests__/historical-replay-target.test.ts#L275 target=_blank style='text-decoration:none; color:#1c7fd6'>[Line: 275] new RegExp(`^${ready.baseSha}\\.\\.[a-f0-9]{40}$`, &apos;u&apos;)</a>"]
        end
    end
    %% Class Assignment
    Source:::invis
    Sink:::invis

    Traces0:::invis
    File0:::invis

    %% Connections

    Source --> Traces0
    Traces0 --> Sink

Loading

kostandinang commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@kostandinang
kostandinang marked this pull request as ready for review July 22, 2026 15:31
Comment thread src/.pi/extensions/agent-runtime/runtime/index.ts
Comment thread src/dev/end-to-end-comparison/claude-adapter.ts
kostandinang and others added 5 commits July 22, 2026 21:06
Add history-free Brunch and Petrinaut profiles with controller-owned oracles so real repositories can enter the crossed comparison without exposing historical solutions.

Co-authored-by: Cursor <cursoragent@cursor.com>
Make strict two-commit admission the sole lane-ready preparation path and harden its dependency and network contracts.

Co-authored-by: Cursor <cursoragent@cursor.com>
Exercise the branded sandbox contract with a portable test runner so Linux CI does not invoke the macOS-only production verifier.

Co-authored-by: Cursor <cursoragent@cursor.com>
Align the frozen mission with merged reference behavior while preserving greenfield access, isolated runtime bounds, and portable CI verification.

Co-authored-by: Cursor <cursoragent@cursor.com>
Preserve the landed FE-1250 and FE-1251 frontier state alongside the latest brownfield comparison status.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kostandinang
kostandinang force-pushed the ka/fe-1241-brownfield-comparison-cases branch from 24abfa8 to 3327b6a Compare July 22, 2026 19:14
Comment thread src/dev/execution-comparison/petrinaut-optimization-oracle/browser.ts Outdated
Comment thread src/dev/execution-comparison/petrinaut-optimization-oracle/browser.ts Outdated
Comment thread src/dev/execution-comparison/__tests__/petrinaut-historical-preflight.test.ts Outdated
kostandinang and others added 2 commits July 22, 2026 21:22
Run the expect-backed PTY integration suite on Ubuntu with the zsh executable its fixtures invoke.

Co-authored-by: Cursor <cursoragent@cursor.com>
Accept both first-run mode selection and an already-settled controller session before driving the public landing command.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/.pi/extensions/agent-runtime/runtime/index.ts
Canonicalize bounded reads across filesystem aliases and replace runtime regex construction with fixed-text option matching while retaining redaction coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/.pi/extensions/agent-runtime/runtime/index.ts
Deny lexical escapes uniformly while permitting canonical in-root aliases and retaining symlink containment checks.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/.pi/extensions/agent-runtime/runtime/index.ts
kostandinang and others added 2 commits July 22, 2026 22:21
Validate the nearest existing ancestor so absent in-root paths reach the underlying tool without weakening alias or symlink boundaries.

Co-authored-by: Cursor <cursoragent@cursor.com>
Retire consumed scope cards and preserve the real-reference preflight as an explicit future gate rather than completed evidence.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread src/dev/end-to-end-comparison/brunch-adapter.ts Outdated
@kostandinang kostandinang changed the title FE-1241: Add Brunch and Petrinaut brownfield end-to-end comparison cases FE-1241: Add isolated brownfield comparison cases Jul 22, 2026
Move the waived provider evidence to an explicit Later gate and keep only current D136-D138 topology in live canonical memory.

Co-authored-by: Cursor <cursoragent@cursor.com>
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches agent tool policy, TUI comparison launch paths, and dev-only git/oracle automation with real subprocess and filesystem boundaries; scope is evaluation tooling rather than shipped product RPC, but mis-bounded reads or oracle regressions could skew comparison evidence.

Overview
Adds two brownfield execution-comparison cases alongside the existing greenfield Petri editor: Brunch host landing (pinned FE-1201 parent, /brunch:land + independent Git oracle) and Petrinaut optimization (pinned HASH parent, immutable install, focused /optimization builds, deterministic loopback optimizer + browser checks). Frozen packets, study contracts, missions, and oracle manifests wire these into the same Brunch vs Claude Code lane model.

Controller and operator plumbing gains D137-L historical replay (materializePinnedSourceTree, packet verification, prepare with optional --source-repository), compile-time oracle dispatch in execution-comparison-operator.ts, and inspect output that includes repository requirements and per-case oracle identity instead of a single fixed Petri browser suite.

Lane isolation tightens comparison runs: Brunch comparison TUI disables web tools and Specify subagents, bounds foreground read/grep/find/ls to the target (symlink-aware), and limits execution subagents to planner/worker; Claude brownfield launches use strict MCP, disabled web fetch/search, sandbox denied reads for controller roots, and parallel subagent path bounding.

Docs and process update /compare-execution, comparison guides, SPEC (D136-L/D137-L), PLAN closeout, and CI (expect, ripgrep, zsh; test:full = fast + slow at --maxWorkers=1 for slow tests). PLAN_HISTORY records retirement of merged-reference preflight, duplicate HASH installs, and adversarial admission in favor of remote-free snapshots and calibration only when source/contract/oracle changes.

Reviewed by Cursor Bugbot for commit bc323a3. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread src/dev/end-to-end-comparison/claude-adapter.ts Outdated
kostandinang and others added 2 commits July 23, 2026 00:32
Bind retained evidence to every runtime oracle input and make Petrinaut interactions fail closed on declared addresses.

Co-authored-by: Cursor <cursoragent@cursor.com>
Encode tool policy lists unambiguously and provision ripgrep so the Linux full gate can exercise bounded grep reads.

Co-authored-by: Cursor <cursoragent@cursor.com>
assertContainedPath(root, target);
const [realRoot, realTarget] = await Promise.all([realpath(root), realpath(target)]);
assertContainedPath(realRoot, realTarget);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subagent path bound rejects aliases

Medium Severity

assertBoundedExistingPath rejects lexically mismatched paths before comparing canonical roots, so macOS /var vs /private/var aliases fail even when both resolve inside the worktree. Foreground assertBoundedReadPath in this same change already allows that alias case, and planner/worker reads now go through the stricter helper unconditionally.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ec0d321. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit bc323a3. Configure here.

await assertBoundedExistingAncestor(cwd, target);
await mkdir(dirname(target), { recursive: true });
await assertBoundedExistingPath(cwd, dirname(target));
await assertBoundedExistingTargetIfPresent(cwd, target);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dangling symlink write escape

High Severity

The new worktree write bounds treat a missing final path as safe, then call writeFile. A dangling symlink that is lexically inside the worktree still resolves to ENOENT on realpath, so containment passes and writeFile follows the link and can create or overwrite a file outside the target root. That undermines the comparison isolation this change is adding.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit bc323a3. Configure here.

caseValue['surface'] !== 'backend' ||
repository['substrate'] !== 'pinned_git' ||
!gitObjectId(repository['parentCommit']) ||
!gitObjectId(repository['parentTree']) ||

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brunch source identity unfrozen

Medium Severity

The Brunch brownfield parsers only require parentCommit and parentTree to look like Git object ids. Petrinaut pins the exact frozen hashes in the same allowlist path, so Brunch source identity can drift to any other commit/tree without failing contract validation.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit bc323a3. Configure here.

@kostandinang
kostandinang merged commit f2a8bab into next Jul 23, 2026
7 checks passed
@kostandinang
kostandinang deleted the ka/fe-1241-brownfield-comparison-cases branch July 23, 2026 00:52
@hash-worker hash-worker Bot mentioned this pull request Jul 23, 2026
@kostandinang kostandinang self-assigned this Jul 23, 2026
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.

1 participant