Skip to content

FE-1320: Structural private-mission isolation for /compare-specs - #415

Merged
lunelson merged 5 commits into
nextfrom
ln/fe-1320-comparison-mission-isolation
Aug 19, 2026
Merged

lunelson merged 5 commits into
nextfrom
ln/fe-1320-comparison-mission-isolation

Conversation

@lunelson

@lunelson lunelson commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Why

The /compare-specs controller holds private mission material that comparison targets must never be able to discover through their workspace or relative paths.

What

  • Runs each comparison target in a fresh temporary workspace outside the repository and mission source tree.
  • Rejects adversarial paths that attempt to escape the target workspace.
  • Preserves target outputs and historical comparison evidence unchanged.

How to test

  1. Run the comparison isolation tests and confirm a target cannot resolve controller-private mission files.
  2. Exercise the adversarial escape path and confirm it is rejected.
  3. Confirm target-authored outputs are retained and existing historical evidence is byte-unchanged.

@lunelson lunelson changed the title FE-1320: Isolate comparison mission targets FE-1320: Structural private-mission isolation for /compare-specs Aug 7, 2026
@lunelson
lunelson marked this pull request as ready for review August 7, 2026 16:16
Copilot AI lite review requested due to automatic review settings August 7, 2026 16:16
@cursor

cursor Bot commented Aug 7, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Changes are prompt procedure, documentation, and dev tests—no runtime controller or harness execution code paths. Residual risk is procedural (operators following the updated prompt) rather than production auth or data handling.

Overview
Structural isolation for /compare-specs — each harness now gets a fresh system-temporary target root outside the controller checkout, scratch, and retained run trees, with preflight checks that ancestor paths hold no private-mission.md or other controller-private material. Brunch still launches from the repo root via --workspace; generic harnesses use the external path as cwd. The prompt explicitly closes the CS2 ../../private-mission.md rival and states this is placement hardening, not an OS sandbox.

Evidence retention — teardown now saves harness-visible transcripts from the controller-owned interactive_shell record (not from the external target) and copies only unchanged harness-authored documents before removing the external target root.

Tests and docscompare-specs-prompt.test.ts adds prompt-string oracles plus filesystem fixtures for target visibility, adversarial path rejection, and post-cleanup retention. PLAN/SPEC/TESTING_FINDINGS mark comparison-mission-isolation-hardening complete and defer the live Brunch + Claude witness to saved-mission-comparison-witness.

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

Copilot AI 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.

Pull request overview

This PR hardens /compare-specs private-mission isolation by changing the workflow to allocate each harness a fresh, system-temporary external target root outside controller-owned trees, and updates the written procedure + planning docs to match.

Changes:

  • Update the /compare-specs operator prompt to require per-harness external target roots and specify copy/cleanup sequencing.
  • Add/extend tests around the prompt contract and the external-target placement invariants.
  • Update SPEC/PLAN/testing notes to record FE-1320 as the closeout of the prior placement-risk finding.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
TESTING_FINDINGS.md Updates CS2 disposition to reflect FE-1320 closing the placement risk.
src/dev/tests/compare-specs-prompt.test.ts Adds prompt assertions and filesystem-based isolation/retention tests.
memory/SPEC.md Updates D134-L and I67-L to include external target placement boundary language.
memory/PLAN.md Marks the isolation hardening frontier as completed and removes it from “Next”.
docs/archive/PLAN_HISTORY.md Archives the FE-1320 closeout entry and its evidence summary.
.pi/prompts/compare-specs.md Implements the new external-target-root procedure and retention/cleanup ordering in the operator prompt.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/dev/__tests__/compare-specs-prompt.test.ts
Comment thread .pi/prompts/compare-specs.md Outdated
Copilot AI review requested due to automatic review settings August 10, 2026 09:12
@lunelson
lunelson force-pushed the ln/fe-1318-canonical-document-reconciliation branch from 4f5538e to d63c33a Compare August 10, 2026 09:12
@lunelson
lunelson force-pushed the ln/fe-1320-comparison-mission-isolation branch from 14deb5d to 1a721c7 Compare August 10, 2026 09:12

Copilot AI 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.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/dev/tests/compare-specs-prompt.test.ts:17

  • pathExists treats any access() failure as “does not exist”. That can make the test pass even if the path exists but is unreadable (e.g., EACCES). Restrict the false case to ENOENT and rethrow other errors so the assertion is reliable.
const pathExists = async (path: string): Promise<boolean> => {
  try {
    await access(path);
    return true;
  } catch {

src/dev/tests/compare-specs-prompt.test.ts:100

  • These assertions rely on filesystem enumeration order (readdir / recursive traversal). Directory entry order is not guaranteed across platforms/filesystems, so this can be flaky in CI. Sort the collected names/paths (or use toContain) before asserting exact equality.
      const lsVisible = await readdir(target);
      expect(lsVisible).toEqual(['visible.md']);

      const findVisible = await findEntries(target);
      expect(findVisible.map((entry) => relative(target, entry))).toEqual(['visible.md']);

@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.

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 1a721c7. Configure here.

Comment thread .pi/prompts/compare-specs.md
Comment thread .pi/prompts/compare-specs.md

@kostandinang kostandinang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Placing each harness in a fresh temp root closes the known ../../private-mission.md walk. The prompt and SPEC already say this is not an OS sandbox, which matches what the tests actually prove.

Copilot AI review requested due to automatic review settings August 19, 2026 09:10
@lunelson
lunelson force-pushed the ln/fe-1318-canonical-document-reconciliation branch from d63c33a to e705386 Compare August 19, 2026 09:10
@lunelson
lunelson force-pushed the ln/fe-1320-comparison-mission-isolation branch from 1a721c7 to ec06b46 Compare August 19, 2026 09:10

Copilot AI 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.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (2)

.pi/prompts/compare-specs.md:96

  • The prompt now relies on target placement to prevent reading controller-private files, but it still doesn't explicitly require rejecting adversarial document paths that escape the external target root (e.g. absolute paths, ../ traversal, or symlink escapes) when locating/copying the harness-authored output. This leaves a gap vs the PR's stated "reject adversarial paths" goal and risks copying unintended host/controller files into retained evidence.
7. Locate the harness-authored document if it exists without altering it. Never author, reconstruct, complete, rewrite, or improve it. Missing or partial output remains missing or partial.

src/dev/tests/compare-specs-prompt.test.ts:62

  • This test suite validates the new placement language, but it doesn't assert the prompt requires rejecting adversarial paths that would escape the external target root when resolving/copying the harness-authored output (absolute paths, ../ traversal, symlink escapes). Adding explicit prompt assertions here will lock in the "reject escape paths" contract and prevent regressions.
    expect(prompt).toContain(
      'It is not an OS sandbox and does not claim isolation from unrestricted absolute-path or whole-host discovery',
    );

@cursor
cursor Bot changed the base branch from ln/fe-1318-canonical-document-reconciliation to graphite-base/415 August 19, 2026 15:35
lunelson and others added 2 commits August 19, 2026 15:36
Place each harness in a fresh external temporary root so controller-private mission material is absent from ordinary target-relative traversal while retained evidence stays exact.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep the external-target contract coupled to the existing single-actor, immutable-evidence, and prompt-owned workflow boundaries.

Co-authored-by: Cursor <cursoragent@cursor.com>
lunelson and others added 3 commits August 19, 2026 15:36
Return I67-L to its pre-frontier content so any evidence refresh remains owned by ln-sync.

Co-authored-by: Cursor <cursoragent@cursor.com>
@lunelson
lunelson force-pushed the ln/fe-1320-comparison-mission-isolation branch from ec06b46 to f1c74bf Compare August 19, 2026 15:36
@cursor
cursor Bot changed the base branch from graphite-base/415 to next August 19, 2026 15:37
@cursor

cursor Bot commented Aug 19, 2026

Copy link
Copy Markdown

Merge activity

  • Aug 19, 3:37 PM UTC: Graphite rebased this pull request, because this pull request is set to merge when ready.

@lunelson
lunelson merged commit fc08b8d into next Aug 19, 2026
9 of 11 checks passed
@lunelson
lunelson deleted the ln/fe-1320-comparison-mission-isolation branch August 19, 2026 15:39
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.

3 participants