Skip to content

refactor(deep-scan)!: simplify scan recovery and result saving - #1095

Closed
mldangelo-oai wants to merge 1 commit into
mdangelo/codex/pr939-stack-22-retire-protocolfrom
mdangelo/codex/deep-scan-cleanup
Closed

mldangelo-oai wants to merge 1 commit into
mdangelo/codex/pr939-stack-22-retire-protocolfrom
mdangelo/codex/deep-scan-cleanup

Conversation

@mldangelo-oai

@mldangelo-oai mldangelo-oai commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Superseded: The replacement PRs start at #1139; see the full stack index. This PR is retained as a reference, with its original description below.

Summary

Deep Scan runs ordinary Standard scans and combines their results. Saving and resuming it still involves copying evidence, rebuilding prior results, and preparing the same worker environment repeatedly. Keep one saved draft, store original findings once, and share the prepared worker setup.

Changes

  • Save the current draft before writing the result JSON files, so an interrupted write can finish without rebuilding accepted history. Keep pending findings and unfinished review work available for recovery.
  • Store each original finding and accepted revision once. Combined reports reference that evidence and retain distinct remediation details, locations, and the highest observed severity.
  • Read child completion and session records from the database. Save the final combined cost, or that it is unknown, before completing the parent scan.
  • Reuse prepared execution settings and a read-only knowledge snapshot across workers. A completed scan with saved launch settings can finish recording its result without Codex authentication or a model call when no follow-up is requested.
  • Add database migration 45 for execution sessions and the MCP dependency needed by installed SDK type declarations. Migration 46 recovers legacy severity assessments for unindexed findings; migration 47 removes the unused cross-scan severity lookup index. Earlier migrations stay unchanged.
  • Let the existing workbench write-scan-draft command read {documents, checkpoint} from stdin when --draft-path is omitted. Existing staged-file inputs remain supported.
  • Remove the unused combined event/publication wrapper. Event tests call the turn runner directly and no longer need completed-report fixtures.
  • Write an aggregate only when its contents change; pass registration and other progress updates write just the checkpoint metadata. Preserve errors from unsafe checkpoint paths and keep historical review totals accurate.

Testing

The complete stack passed these checks on Linux:

  • Full SDK suite on Bun 1.4.2 with --seed 12345: 3,443 passed, 46 skipped.
  • A separate full SDK run with the default test order: 3,443 passed, 46 skipped.
  • Database, migration, projection, receipt, checkpoint, and resume suites: 298 passed, 2 skipped.
  • Ruff lint and formatting, the CI script build, SDK and plugin type checks, SDK formatting, and plugin source compatibility and its tests.

Each earlier PR also passed source and type checks at its own rebuilt commit. Focused worker, comparison, cancellation, and publication tests are recorded on the relevant PRs. Windows execution remains for CI.

Risk and rollout

  • Checkpoints now use version 3. Unfinished version 2 scans need their original version to finish, or a new scan. Completed reports remain readable. Older sealed Deep Scans without a final cost record still need their original version when cost tracking is required.
  • Draft updates must retain saved finding and coverage IDs to reliably update existing records. Matching text alone no longer identifies an existing row.
  • Each discovery pass runs once. A failed pass consumes a discovery slot; publication retries reuse completed work. Merge retries keep their existing limit.
  • Native launches use CODEX_CLI_PATH or normal PATH lookup. They no longer search installer or package-cache directories. Create a new client after editing a custom plugin's source.

Part 23 of 23. Previous PR · Stack index. Review against the base branch.

Public disclosure review

  • No customer, partner, prospect, or user identities, data, or identifying details are included.
  • No credentials, personal data, private source, scan findings, or nonpublic links or tickets are included.
  • I reviewed the branch name, title, description, commits, changes, comments, logs, screenshots, attachments, and links for public disclosure.

@mldangelo-oai
mldangelo-oai marked this pull request as ready for review September 30, 2026 13:21
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-30T18:30:53.954456Z 24713fb New commits
🔒 Security Review ✅ Completed 2026-09-30T18:22:54.823681Z 24713fb New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

mldangelo-oai pushed a commit that referenced this pull request Sep 30, 2026
Keep a committed scan draft for saving results and recovery. Consolidate scan
execution settings, child completion records, and report preparation.

This commit preserves the code from PR #1095 through its last upstream sync.
@mldangelo-oai
mldangelo-oai force-pushed the mdangelo/codex/deep-scan-cleanup branch from 2a5796d to 3065926 Compare September 30, 2026 15:49
@mldangelo-oai mldangelo-oai changed the title refactor(deep-scan)!: simplify orchestration and result publication refactor(deep-scan)!: simplify scan recovery and result saving Sep 30, 2026
@mldangelo-oai
mldangelo-oai changed the base branch from mdangelo/codex/simplify-deep-scan to mdangelo/codex/pr939-stack-22-retire-protocol September 30, 2026 15:49
@mldangelo-oai

Copy link
Copy Markdown
Collaborator Author

@codex review

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.

Copilot review overview

🟡 Changes recommended

Post-turn result collection no longer preserves the public cancellation error contract.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Simplifies Deep Scan recovery and result publication by persisting reusable drafts, retaining original evidence, recording execution sessions, and sharing prepared worker settings.

Changes:

  • Reworks checkpoint, merge, evidence, and recovery persistence.
  • Adds execution-session accounting and reusable worker preparation.
  • Updates workbench publication, MCP completion, schemas, and tests.
File Description
sdk/​typescript/​src/​deep-scan.ts Revises pass recovery, persistence, merging, and publication.
sdk/​typescript/​src/​deep-scan-checkpoint.ts Introduces checkpoint v3 and aggregate hydration.
sdk/​typescript/​src/​scan-merge.ts Retains source evidence and reconciles accepted revisions.
sdk/​typescript/​src/​scan-publication.ts Centralizes draft publication and result completion.
sdk/​typescript/​src/​scan-events.ts Separates turn processing from result collection.
sdk/​typescript/​src/​runtime.ts Adds batched restoration and child projection support.
sdk/​typescript/​src/​execution-preparation.ts Reuses prepared execution settings across workers.
sdk/​typescript/​tests-ts/​support/​scan-publication.ts Removes the obsolete staged-file publication helper.
sdk/​typescript/​tests-ts/​support/​api-events.ts Adds synthetic plugin-variant setup.
sdk/​typescript/​tests-ts/​support/​api-client.ts Updates the artifact-restorer test double.
sdk/​typescript/​tests-ts/​scan-resume-permissions.test.ts Verifies resumed launch configuration.
sdk/​typescript/​tests-ts/​scan-projection-fixtures.test.ts Updates projection tests for retained evidence references.
sdk/​typescript/​tests-ts/​scan-merge-reconciliation.test.ts Adds reconciliation and validator-isolation coverage.
plugins/​codex-security/​scripts/​workbench_saved_results.py Commits drafts before exporting canonical results.
plugins/​codex-security/​scripts/​workbench_schema.py Adds execution-session migration and backfill.
plugins/​codex-security/​scripts/​workbench_scan_usage.py Accounts for persisted execution sessions.
plugins/​codex-security/​mcp-app/​server.ts Updates native completion and stopped-result handling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread sdk/typescript/src/scan-events.ts Outdated
Comment on lines +94 to +95
const completed = await runScanTurn(options);
return collectResult(
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 3065926f4f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sdk/typescript/src/scan-events.ts Outdated
throwScanFailure(error, options);
}
const completed = await runScanTurn(options);
return collectResult(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Remove the unused event/publication facade

runScanEvents has no production callers left: the API uses runScanTurn and publishScan, while only the event tests call this combined path. It is internal and absent from the package exports. Delete this wrapper and its api.ts re-export, and have the event tests exercise runScanTurn directly. That also removes collectResult/ScanResult, pluginRoot, and workbenchValidated from the event layer and lets those tests stop copying completed-report fixtures merely to test event callbacks. I verified completion, thread callbacks, finalization, and null finalized usage through runScanTurn with nonexistent artifact directories; artifact validation/publication can remain covered by the existing contract/API tests.

Comment on lines +168 to +173
await input.writer.restoreMany([
...revisions,
...(contents === undefined
? []
: [{ path: aggregatePath!, contents: Buffer.from(contents) }]),
{ path: DEEP_SCAN_CHECKPOINT, contents: Buffer.from(snapshot) },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Keep metadata saves from rewriting the unchanged aggregate

Reserving or registering a pass changes the checkpoint snapshot, so the snapshot comparison above does not prevent this block from rewriting the same content-addressed aggregate. Running the existing composition fixture with one worker and three passes produced three distinct aggregate files but nine aggregate writes. Each metadata save also serializes and hashes the full retained findings and coverage again. Separate aggregate persistence from metadata saves: retain the successfully persisted aggregate reference/path, update it when merge acceptance or coverage replacement changes the aggregate, and otherwise write only checkpoint.json. The aggregate is already replaced rather than mutated, so this can remove report-sized work from pass bookkeeping while preserving the existing write queue and failure semantics.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 95bbfbe176

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1165 to +1166
elif version == 43:
backfill_composition_children(connection)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add the composition backfill as a new migration

For a database that already applied migration 43, apply_migrations skips this branch, leaving existing child rows with parent_scan_role = NULL. Since composition_children() now selects only rows whose role is deep_pass (workbench_composition.py:105-110), resuming or recovering an existing Deep Scan can omit all prior children, including their findings and costs. Move this backfill into a new migration version so previously upgraded databases execute it.

Useful? React with 👍 / 👎.

@mldangelo-oai
mldangelo-oai force-pushed the mdangelo/codex/pr939-stack-22-retire-protocol branch from e30421d to 2348b94 Compare September 30, 2026 17:19
@mldangelo-oai
mldangelo-oai force-pushed the mdangelo/codex/deep-scan-cleanup branch from 95bbfbe to 121c362 Compare September 30, 2026 17:19
@mldangelo-oai
mldangelo-oai force-pushed the mdangelo/codex/deep-scan-cleanup branch from 121c362 to 24713fb Compare September 30, 2026 18:17
@mldangelo-oai
mldangelo-oai force-pushed the mdangelo/codex/pr939-stack-22-retire-protocol branch from 2348b94 to e29cdc2 Compare September 30, 2026 18:17

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 24713fb088

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +955 to +958
FROM scan_severity_classifications AS classification
JOIN json_each(classification.finding_ids_json) AS selected
JOIN finding_severity_assessments AS assessment ON assessment.finding_id = selected.value
JOIN findings AS finding ON finding.id = assessment.finding_id"""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Match rubric hashes when backfilling severity assessments

When an older database contains an unindexed assessment and the same scan's classification was restarted with a different rubric or knowledge-base digest before migration, this join still selects the stale global assessment solely because its occurrence ID matches the scan. Migration 46 then persists that assessment as the scan's result, whereas migration 42 deliberately required both hashes to match. Add the same rubric and knowledge-base predicates here so an interrupted reassessment cannot corrupt the recovered classification.

Useful? React with 👍 / 👎.

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

Reviewed final draft commit ordering, immutable source findings/revisions, checkpoint persistence, child/session accounting, and reuse of prepared execution settings. I did not confirm another runtime defect in those paths, and did not find a further deletion that I could justify without removing recovery behavior. The credential-fixture issue inherited from #1123 is now posted there.

At 24713fb, local checks produced 680 passes and four skips across focused SDK, native lifecycle, Python migration, result-saving, composition, cost, and resume suites. The 28 initial native-dependent failures passed after building this source's macOS module with Rust 1.97.1. build:ci and types also passed; the pnpm launcher used Node 25.8.1 outside the declared engine range. A real Codex 0.159.0 permission preflight passed without executing a model turn.

Leaving COMMENT because this was a focused review of a large change, with universal package, local Windows, and live-model validation incomplete. The checkpoint-v2 compatibility break, retained-ID requirement for draft updates, and failed-pass slot behavior are explicit in the description and should stay visible in release notes.

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

Completed the follow-up review at 24713fb. The earlier platform/package validation gap is closed: the current CI run succeeded, including Windows test shards, standalone plugin checks and installed packages. I also built the universal bundled plugin locally on Node 24.21.0 using this run's native artifact.

The remaining issue is the saved-recipe reference-document drift from #1125, which still reproduces here. A scan started without a knowledge base can resume with newly configured documents because prepareNativeScan falls back to the current environment when the saved field is absent, and the digest comparison only runs when an old digest exists. A synthetic SDK/database reproduction completed one worker without documents, then ran another worker with a new knowledge snapshot under the same scan ID. Reproduction details and a verified minimal correction. I am leaving this head unapproved until that case is fixed.

Two other concerns are resolved by this validation:

  • The relative-evidence-link probe that fails on #1117/#1125 passes here because the child tree is retained.
  • Migration 46 can restore stale rows, but SeverityStore.read filters their rubric/knowledge hashes and rejects an incomplete classification. Both interrupted-reclassification probes passed; I did not reproduce stale assessments being accepted for publication.

The focused severity, projection, resume-permission and installed-native-registration suites passed all 26 cases. One initial permission-test failure was caused by my restricted test PATH omitting python; both permission cases passed after restoring the Python path. These results supplement the earlier composition/recovery/accounting validation; no live model scan was used.

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.

5 participants