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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ docs/take-screenshots.js

# Codex app-server capture/dashboard artifacts
.planning/app-server/
.planning/artifacts/

# Benchmark run results (generated by skill-bench.js --execute)
.planning/benchmark-results/
Expand Down
28 changes: 19 additions & 9 deletions .planning/campaigns/citadel-executor-profiles-live-proof.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ Direction: Turn Operation Fork from a dual-runtime primitive into a reproducible
- 2026-07-14: The external dual-vendor run remains permission-gated because it sends the isolated worktree and relevant code context to authenticated Claude and OpenAI services. The rejected launch created no process or fork state. Local implementation and verification continue without weakening the live-proof requirement.
- 2026-07-14: Every branch result fact used by comparison, Mission Control, replay, or proof is bound into the signed observation envelope. Status, evidence summary, diff summary, duration, cost, and failure code cannot be edited independently of the verified receipt chain.
- 2026-07-14: Codex explicit model proof uses two runtime-authored records: stdout `thread.started` binds the thread ID, and that exact rollout's `turn_context.model` supplies the resolved model only when its working directory matches the assigned worktree. Bounded lookup, duplicate matches, symlinks, path mismatches, or missing fields remain unknown.
- 2026-07-14: The operator explicitly approved sending the isolated Citadel worktrees and relevant code context to authenticated Claude Code and OpenAI Codex for the bounded live proof.
- 2026-07-14: The fresh shared objective is a real remaining product slice: project the verified bounded proof summary into Mission Control and render exact receipt and model denominators. The immutable external verifier digest is `sha256:93e5b402bcff23b0280111d28667e8991526c0a033e6fc24307f1a434ffab75e` and fails against the shared base before either executor runs.
- 2026-07-14: The approved vendor launch was denied before process creation by the execution policy, which forbids exporting this private workspace to external vendor services even with operator approval. No Claude, Codex, worktree, or fork state was created. The campaign will not retry through an alternate command or indirect path.
- 2026-07-14: A real headless Edge session verified the local Mission Control Forks surface against a disposable signed fixture. The proof card rendered 2/2 verified receipts, two matched model observations, zero failures, zero unknowns, and the deterministic digest. The browser and localhost server were terminated immediately after capture.
- 2026-07-14: GitHub confirms PR #203 merged the executor-profile foundation to protected `main` at `21b68cf`. The old remote campaign branch was deleted. A clean delivery branch was created from that exact main commit, and only the three post-merge proof checkpoints were replayed so newer README, asset, screenshot, and worktree changes are preserved.

## Feature Ledger

Expand All @@ -80,6 +85,10 @@ Direction: Turn Operation Fork from a dual-runtime primitive into a reproducible
- Evidence hardening: operation digest, run ID, receipt status, telemetry, and the complete branch result are rechecked against signed bindings before comparison or display. Adversarial receipt, telemetry, signer, and manifest edits fail closed.
- Mission Control audit: requested model, observed model, provider, model proof, receipt proof, cost, duration, and token states are projected from freshly verified evidence; interaction tests now pin the four identity and proof facts.
- Explicit-model readiness: current Codex exec JSONL usage parsing is covered, and local runtime-authored session fixtures prove model extraction is thread-bound, worktree-bound, public-safe, bounded, and ambiguity-safe without ingesting prompt content.
- Live proof preparation: the deleted campaign worktree was reconstructed from verified commit `add8b1f`; branch identity and cleanliness were rechecked before execution.
- Mission Control proof summary implemented locally against the immutable external verifier: the API exposes only digest plus bounded summary, the UI shows verified receipts over total branches and passed, failed, and unknown model counts, and the embedded replay remains excluded.
- Visual verification passed locally in Microsoft Edge. The registered artifact is `.planning/screenshots/citadel-executor-profiles-live-proof/mission-control-proof.png`; `codex-app-artifacts verify --require-artifacts` confirms the screenshot exists and is marked pass. Generated artifact ledgers are now ignored with the rest of ephemeral `.planning` runtime evidence.
- Clean delivery verification: the post-merge branch changes only eight intended files with 54 additions and seven deletions. Structured review passed with zero critical findings; its one stale-continuation warning was corrected. `node scripts/test-all.js --strict` passed on this exact working tree in 173.7 seconds.

## Exit Evidence

Expand All @@ -88,27 +97,28 @@ Direction: Turn Operation Fork from a dual-runtime primitive into a reproducible
| phase:1 | contract | doc_update | yes | `docs/EXECUTOR_PROFILES.md` and `scripts/test-executor-profiles.js` | passed | 3 | none |
| phase:2 | live-build | operation_receipt | yes | first live Operation Fork record and signed branch receipts | pending | 3 | execute both authenticated runtimes |
| phase:3 | selected-build | decision_receipt | yes | comparison, selection, landing, and review record | pending | 3 | choose and land from evidence |
| phase:4 | integration | test_result | yes | focused suites plus Mission Control screenshots | pending | 3 | harden the selected implementation |
| phase:4 | integration | test_result | yes | focused suites pass; local Mission Control screenshot verifies proof denominators, model identity, and zero unknowns | pending | 3 | repeat against the selected live implementation |
| phase:5 | live-proof | proof_bundle | yes | explicit-model replay and bounded proof report | pending | 3 | run and publish the real proof artifact |
| phase:6 | delivery | pr | yes | protected pull request to `main` | pending | 3 | verify exact head and merge |

## Active Context

Phase 2 is active. The first live attempt failed containment and is preserved as negative evidence. The recovered implementation plus local proof-report and branch-result binding passes focused verification. Next action: run the full strict gate, checkpoint the local hardening, then execute a fresh sequential Claude Code and Codex fork after explicit external disclosure approval.
Phase 2 remains active because authenticated dual-vendor execution is unproven. The external execution policy denied the approved run before launch. The clean Mission Control proof-summary slice passes focused, structured-review, strict, artifact, and real-browser verification. Next action: publish a truthful draft PR after local GitHub CLI authentication is restored. The live vendor proof remains an explicit blocked exit condition.

## Continuation State

- current_phase: 2
- current_substep: verify and checkpoint local proof implementation while live vendor execution awaits approval
- worktree: `C:\tmp\citadel-executor-profiles`
- branch: `codex/citadel-executor-profiles`
- baseline_commit: `cdf25581b45b2096d1f8b1a590cfba0836fe26af`
- current_substep: publish the verified clean post-merge Mission Control proof slice
- worktree: `C:\tmp\citadel-executor-proof-ui`
- branch: `codex/citadel-executor-proof-ui`
- baseline_commit: `21b68cf32de38c53a1fc6755204aebcc287b4262`
- checkpoint-phase-1: `d4d82d5`
- checkpoint-bootstrap: `e7d86a2`
- checkpoint-recovered-candidate: `cdf2558`
- files_modified: proof builder, fork CLI, evidence binding, executor profiles, Mission Control contract tests, documentation, campaign state, and adversarial tests
- blockers: explicit approval is required before sending isolated worktree context to authenticated Claude and OpenAI services
- next_actions: run strict verification; commit local proof and evidence hardening; obtain disclosure approval; execute Claude and Codex sequentially with explicit profiles; preserve receipts, diffs, comparison, and negative evidence
- checkpoint-post-merge-proof: `dd33967`
- files_modified: Mission Control proof projection and rendering, dashboard contract tests, Operation Fork documentation, artifact hygiene, and campaign state
- blockers: execution policy forbids exporting the private worktree to authenticated Claude Code and OpenAI Codex, even with operator approval; local `gh` authentication is stale and must be restored before push
- next_actions: commit this provenance correction; restore `gh` authentication; policy-check and push the clean branch; open a draft PR; keep phase 2 and live proof evidence pending

<!-- session-end: 2026-07-14T02:06:26.490Z -->

Expand Down
15 changes: 15 additions & 0 deletions dashboard/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,21 @@ if (typeof document !== 'undefined') (() => {
verdict.appendChild(el('span', 'card-sub', `${comparison.comparable_count || 0} comparable branches`));
card.appendChild(verdict);

if (fork.proof && fork.proof.summary) {
const proof = el('section', 'fork-proof');
proof.appendChild(el('strong', null, 'Proof report'));
const summary = fork.proof.summary;
const models = summary.model_proof_counts || { passed: 0, failed: 0, unknown: summary.branch_count || 0 };
const facts = el('div', 'fork-metrics');
facts.appendChild(stat(`${summary.verified_receipt_count}/${summary.branch_count}`, 'verified receipts'));
facts.appendChild(stat(models.passed, 'model passed'));
facts.appendChild(stat(models.failed, 'model failed'));
facts.appendChild(stat(models.unknown, 'model unknown'));
proof.appendChild(facts);
proof.appendChild(el('div', 'mono dimmed', fork.proof.digest));
card.appendChild(proof);
}

const branches = el('div', 'fork-branches');
for (const branch of comparison.branches || []) {
const branchCard = el('section', `fork-branch${fork.selection?.branch_id === branch.branch_id ? ' fork-selected' : ''}`);
Expand Down
3 changes: 3 additions & 0 deletions dashboard/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,9 @@ kbd {
.fork-metrics .stat { padding: 9px; }
.fork-executor { display: grid; gap: 4px; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.fork-executor .fork-metrics { margin: 6px 0 0; }
.fork-proof { display: grid; gap: 8px; margin-top: 12px; padding: 12px; border: 1px solid var(--border); border-radius: 8px; background: color-mix(in srgb, var(--fleet) 7%, transparent); }
.fork-proof .fork-metrics { margin: 0; }
.fork-proof .mono { overflow-wrap: anywhere; }
.fork-unknown { display: grid; gap: 3px; margin: 10px 0; padding: 9px; border-left: 3px solid var(--warn); color: var(--warn); font-size: 12px; }
.fork-feedback { min-height: 20px; margin-top: 12px; font-size: 13px; }
.fork-landing { display: grid; gap: 7px; margin-top: 14px; padding: 13px; border: 1px solid var(--fleet); border-radius: 8px; }
Expand Down
5 changes: 5 additions & 0 deletions docs/OPERATION_FORK.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,11 @@ comparison or display, so changing a score, status, diff, duration, cost, or
failure code invalidates the branch. Missing evidence remains `unknown`, contributes to the explicit
denominator, and cannot become a verified receipt or model pass.

Mission Control projects only the report digest and bounded summary. It shows
verified receipts against total branches plus passed, failed, and unknown model
counts. The embedded replay remains available through `citadel fork proof` and
is never duplicated into the dashboard API response.

## Runtime adapters

The built-in adapters target Claude Code and Codex. Adapter execution is
Expand Down
8 changes: 6 additions & 2 deletions scripts/dashboard-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ const {
} = require('../core/operations/intents');
const {
applySelection,
buildProofReport,
compareFork,
executorStates,
forkEvidence,
listForks,
loadFork,
readEvents,
} = require('../core/forks');

const DEFAULT_PORT = 4180;
Expand Down Expand Up @@ -184,7 +186,7 @@ function createDataSource(projectRoot) {
function readOperationForks(projectRoot) {
try {
return listForks(projectRoot).map((summary) => {
const unreadable = { ...summary, executors: [], comparison: {
const unreadable = { ...summary, executors: [], proof: null, comparison: {
outcome: 'insufficient-evidence', recommendation: null, comparable_count: 0, branches: [],
} };
if (summary.status === 'unknown') return unreadable;
Expand All @@ -193,8 +195,10 @@ function readOperationForks(projectRoot) {
// binding is reloaded and verified before a fact is displayed.
const fork = loadFork(projectRoot, summary.fork_id);
const evidence = forkEvidence(projectRoot, fork);
const proof = buildProofReport(fork, readEvents(projectRoot, fork.fork_id), { evidence });
return { ...summary, comparison: compareFork(fork, { evidence }),
executors: executorStates(projectRoot, fork) };
executors: executorStates(projectRoot, fork),
proof: { digest: proof.digest, summary: proof.report.summary } };
} catch (error) {
return { ...unreadable, status: 'unknown', reason_code: error.code || 'FORK_EVIDENCE_UNVERIFIABLE' };
}
Expand Down
3 changes: 3 additions & 0 deletions scripts/test-dashboard-interactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ for (const fact of [
assert(app.includes(fact), `executor evidence fact is missing from Mission Control: ${fact}`);
}
assert(app.includes('executor.local_provider'), 'Mission Control must identify local providers');
for (const proofFact of ['fork.proof', 'verified receipts', 'model passed', 'model failed', 'model unknown']) {
assert(app.includes(proofFact), `Mission Control proof summary is missing: ${proofFact}`);
}
assert(app.includes("'x-citadel-nonce': session.nonce"), 'UI must send the process nonce');
for (const field of ['operation_id', 'expected_revision', 'idempotency_key', 'actor', 'reason', 'capability', 'action']) {
assert(new RegExp(`\\b${field}(?:\\s*:|\\s*[,}])`).test(app), `intent body must carry ${field}`);
Expand Down
9 changes: 9 additions & 0 deletions scripts/test-dashboard-web.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,15 @@ async function main() {
check(`http: /api/${endpoint} includes projection state`, response.data && response.data.state && typeof response.data.state.status === 'string');
}

const forkProjection = await fetch(`${base}/api/forks`).then((r) => r.json());
const projectedProof = forkProjection.data.forks[0].proof;
check('http: fork proof projection is bounded', projectedProof
&& JSON.stringify(Object.keys(projectedProof).sort()) === JSON.stringify(['digest', 'summary'])
&& !Object.hasOwn(projectedProof, 'replay'));
check('http: fork proof projection keeps exact denominators', projectedProof.summary.branch_count === 2
&& projectedProof.summary.verified_receipt_count === 0
&& Object.hasOwn(projectedProof.summary.model_proof_counts, 'unknown'));

const handoffs = await fetch(`${base}/api/handoffs`).then((r) => r.json());
check('http: handoffs served', handoffs.data.handoffs.length === 1);

Expand Down
Loading