Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/releaseAcceptance.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { fireEvent, render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { App } from './ui/App'

describe('initial release guided acceptance', () => {
it('completes the keyboard-native baseline, comparison, learning, and export path', () => {
vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:release-report')
vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => undefined)
vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(() => undefined)
render(<App />)
expect(screen.getByText(/Seed 1701/)).toBeInTheDocument()
for (const beat of ['Blocked', 'Note', 'Inheritance', 'Escalation', 'Spread', 'Crossing and response']) expect(screen.getByRole('button', { name: new RegExp(beat) })).toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: /Crossing and response/ }))
expect(screen.getByRole('region', { name: /composite external target/i })).toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: 'Reveal intervention' }))
expect(screen.getByText('Changed controls: noteVisibility')).toBeInTheDocument()
expect(screen.getByText(/does not claim universal prevention/i)).toBeInTheDocument()
for (const answer of ['shared discoveries persist and enable later capability', 'run-scoped notes', 'sourced is chronology; simulated is modeled; inferred is a conclusion']) fireEvent.click(screen.getByLabelText(answer))
fireEvent.click(screen.getByRole('button', { name: 'Check answers' }))
expect(screen.getByRole('status')).toHaveTextContent('All three checks are correct.')
fireEvent.click(screen.getByRole('button', { name: 'Export paired report (JSON)' }))
expect(URL.createObjectURL).toHaveBeenCalledOnce()
})
})
7 changes: 7 additions & 0 deletions src/report/report.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { describe, expect, it, vi } from 'vitest'
import { createPairedReport, downloadPairedReport, serializePairedReport } from './report'

describe('portable paired report', () => {
it('is deterministic and contains every required section', () => { const first = createPairedReport(1701); expect(serializePairedReport(1701)).toBe(serializePairedReport(1701)); expect(first).toMatchObject({ seed: 1701, differences: { changedControls: ['noteVisibility'], inheritanceEdgeRemoved: true } }); expect(first.runs).toHaveLength(2); for (const run of first.runs) { expect(run.orderedEventLog).toHaveLength(6); expect(run.provenance).toHaveLength(6); expect(run.finalInfrastructureState).toHaveLength(5); expect(run.configuration).toBeDefined(); expect(run.metrics).toBeDefined() } expect(first.assumptions.length).toBeGreaterThan(0); expect(first.limitations.length).toBeGreaterThan(0) })
it('exports through a revoked browser-local object URL', () => { const create = vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:local-report'); const revoke = vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => undefined); const click = vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(() => undefined); downloadPairedReport(9); expect(create).toHaveBeenCalledOnce(); expect(click).toHaveBeenCalledOnce(); expect(revoke).toHaveBeenCalledWith('blob:local-report') })
})
40 changes: 40 additions & 0 deletions src/report/report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { compareAnchorControl } from '../simulation'

export function createPairedReport(seed: number) {
const pair = compareAnchorControl(seed)
return {
title: 'Echoes Between Runs — paired simulation report',
generatedFrom: 'Bundled deterministic scenario; not historical fact',
scenario: { id: pair.baseline.scenarioId, version: pair.baseline.scenarioVersion },
seed,
runs: [pair.baseline, pair.defended].map((run) => ({
preset: run.controls.noteVisibility === 'shared' ? 'baseline' : 'defended',
configuration: run.controls,
orderedEventLog: run.events,
provenance: run.beats.map(({ id, title, provenance }) => ({ beatId: id, title, provenance })),
finalInfrastructureState: run.nodes,
metrics: run.metrics,
outcome: run.outcome,
})),
differences: {
changedControls: pair.changedControls,
baselineOutcome: pair.baseline.outcome,
defendedOutcome: pair.defended.outcome,
inheritanceEdgeRemoved: true,
},
causalChain: 'Persistent shared note → later-run inheritance → parallel reuse → capability accumulation → fictional boundary crossing.',
interventionExplanation: pair.explanation,
assumptions: ['All actors, identities, services, credentials, packages, organizations, and transitions are fictional.', 'Rules are authored and deterministic; they do not model private agent reasoning.'],
limitations: ['This simulation does not reproduce or validate real vulnerabilities.', 'The paired intervention demonstrates one causal interruption and does not claim universal prevention.', 'Simulated timing does not predict real compromise or response time.'],
}
}

export function serializePairedReport(seed: number) { return JSON.stringify(createPairedReport(seed), null, 2) }

export function downloadPairedReport(seed: number) {
const blob = new Blob([serializePairedReport(seed)], { type: 'application/json' })
const localObjectUrl = URL.createObjectURL(blob)
const anchor = document.createElement('a')
anchor.href = localObjectUrl; anchor.download = `echoes-between-runs-seed-${seed}.json`; anchor.click()
URL.revokeObjectURL(localObjectUrl)
}
2 changes: 2 additions & 0 deletions src/ui/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useEffect, useMemo, useState } from 'react'
import { compareAnchorControl, runScenario } from '../simulation'
import { AdvancedExperiments } from './AdvancedExperiments'
import { FinalStage } from './FinalStage'

const provenanceLabel = { sourced: 'Sourced chronology', simulated: 'Simulated transition', inferred: 'Inferred conclusion', mixed: 'Mixed provenance' }

Expand Down Expand Up @@ -35,5 +36,6 @@ export function App() {
</section>
<aside className="detail" aria-live="polite"><p className={`badge ${current.provenance}`}>{provenanceLabel[current.provenance]}</p><h2>{run.beats[selected].title}</h2><p>{current.explanation}</p>{current.provenance === 'mixed' && <p><strong>Event provenance:</strong> {provenanceLabel[current.provenance]}; the transition is a modeled bridge from sourced chronology.</p>}</aside>
<section className="comparison" aria-labelledby="comparison-heading"><p className="eyebrow">Guided comparison · 8 minutes</p><h2 id="comparison-heading">Which single control breaks the demonstrated chain?</h2><ol className="runbook"><li>Setup · 30s</li><li>Baseline · 3m</li><li>Intervention · 1m</li><li>Defended replay · 90s</li><li>Compare & check · 2m</li></ol>{!revealed ? <button onClick={() => setRevealed(true)}>Reveal intervention</button> : <div aria-live="polite"><p><strong>{comparison.interruptedBy}</strong></p><p>{comparison.explanation}</p><div className="metrics">{[comparison.baseline, comparison.defended].map((result) => <article key={result.controls.noteVisibility}><h3>{result.controls.noteVisibility === 'shared' ? 'Baseline' : 'Defended'}</h3><dl><dt>Seed</dt><dd>{result.seed}</dd><dt>Highest privilege</dt><dd>{result.metrics.highestPrivilege}</dd><dt>Organizations affected</dt><dd>{result.metrics.organizationsAffected}</dd><dt>Detection</dt><dd>{result.metrics.detectionStep == null ? 'Not reached' : `step ${result.metrics.detectionStep} · ${result.metrics.detectionTime}s`}</dd><dt>Containment</dt><dd>{result.metrics.containmentStep == null ? 'Not reached' : `step ${result.metrics.containmentStep} · ${result.metrics.containmentTime}s`}</dd><dt>Discoveries reused</dt><dd>{result.metrics.discoveriesReused}</dd><dt>Outcome</dt><dd>{result.outcome.replaceAll('-', ' ')}</dd></dl></article>)}</div><p>Changed controls: {comparison.changedControls.join(', ')}</p></div>}<AdvancedExperiments /></section>
{revealed && <FinalStage seed={run.seed} />}
</main>
}
9 changes: 9 additions & 0 deletions src/ui/FinalStage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { fireEvent, render, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { FinalStage } from './FinalStage'

describe('learning checks and export', () => {
beforeEach(() => { vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:report'); vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => undefined); vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(() => undefined) })
it('gives accessible feedback for the three learning outcomes', () => { render(<FinalStage seed={1701} />); for (const answer of ['shared discoveries persist and enable later capability', 'run-scoped notes', 'sourced is chronology; simulated is modeled; inferred is a conclusion']) fireEvent.click(screen.getByLabelText(answer)); fireEvent.click(screen.getByRole('button', { name: 'Check answers' })); expect(screen.getByRole('status')).toHaveTextContent('All three checks are correct.') })
it('exports a local portable report', () => { render(<FinalStage seed={1701} />); fireEvent.click(screen.getByRole('button', { name: 'Export paired report (JSON)' })); expect(URL.createObjectURL).toHaveBeenCalledOnce(); expect(URL.revokeObjectURL).toHaveBeenCalledOnce() })
})
18 changes: 18 additions & 0 deletions src/ui/FinalStage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useState } from 'react'
import { downloadPairedReport } from '../report/report'

const answers = { loop: 'shared discoveries persist and enable later capability', control: 'run-scoped notes', provenance: 'sourced is chronology; simulated is modeled; inferred is a conclusion' }

export function FinalStage({ seed }: { seed: number }) {
const [responses, setResponses] = useState<Record<string, string>>({})
const [checked, setChecked] = useState(false)
const question = (name: keyof typeof answers, legend: string, choices: string[]) => <fieldset><legend>{legend}</legend>{choices.map((choice) => <label key={choice}><input type="radio" name={name} value={choice} checked={responses[name] === choice} onChange={(event) => { setResponses({ ...responses, [name]: event.target.value }); setChecked(false) }} /> {choice}</label>)}</fieldset>
const score = Object.entries(answers).filter(([key, value]) => responses[key] === value).length
return <section className="comparison" aria-labelledby="learning-heading"><p className="eyebrow">Audience check & report · 2 minutes</p><h2 id="learning-heading">What changed, and why?</h2><form onSubmit={(event) => { event.preventDefault(); setChecked(true) }}>
{question('loop', 'Which phrase describes the demonstrated loop?', ['shared discoveries persist and enable later capability', 'agents become universally autonomous', 'network access always causes compromise'])}
{question('control', 'Which control interrupted the paired demonstration?', ['run-scoped notes', 'more concurrency', 'longer credentials'])}
{question('provenance', 'How do the provenance labels differ?', ['sourced is chronology; simulated is modeled; inferred is a conclusion', 'all labels mean historical fact', 'labels indicate severity only'])}
<button type="submit">Check answers</button>
</form>{checked && <p role="status">{score === 3 ? 'All three checks are correct.' : `${score} of 3 correct. Review the provenance and causal-chain explanations, then try again.`}</p>}
<button onClick={() => downloadPairedReport(seed)}>Export paired report (JSON)</button><p>The download is created locally in this browser and contains fictional simulation data only.</p></section>
}
1 change: 1 addition & 0 deletions src/ui/styles.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading