Skip to content

refactor(deep-scan)!: compose ordinary scans and simplify recovery - #939

Open
mldangelo-oai wants to merge 235 commits into
mainfrom
mdangelo/codex/simplify-deep-scan
Open

mldangelo-oai wants to merge 235 commits into
mainfrom
mdangelo/codex/simplify-deep-scan

Conversation

@mldangelo-oai

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

Copy link
Copy Markdown
Collaborator

Summary

Deep Scan repeatedly reviews a repository to find additional issues and combines the results. This change runs those reviews as batches of ordinary Standard scans, sharing their execution, authentication, permissions, and artifact lifecycle. A merge model groups duplicates and selects representative originals; host code retains the findings, evidence, coverage, and costs. Batches with no findings need no merge-model turn.

Changes

  • Finish and merge each discovery batch before starting the next. Apply the no-new-findings threshold after each batch, crediting an issue to the first scan that found it; failed scans do not count as clean results.
  • Verify completed inputs against saved integrity records and the repository version they belong to before combining them. Preserve original finding identities, source records, evidence, coverage, and report references instead of asking the merge model to rewrite narratives.
  • Save intermediate findings and deferred candidates in canonical files, with a pending checkpoint index for recovery. Restore discovery and merge cost records before enforcing a resumed budget, retaining known costs and explicitly unknown costs.
  • Keep provider and MCP replay configuration in existing protected profile files while preserving saved runtime settings. Sealed publication without a follow-up retains its credential-free CLI and native recovery paths.
  • Share prepared runtime inputs and fresh/resumed worker settings while isolating concurrent scans. Extract knowledge documents once and verify their saved content on resume. Deep workers close at completed turns; ordinary Standard scans still validate late process-exit failures.
  • Simplify recovery and severity persistence, recover already-sealed historical bulk attempts in place, and cover the installed native launcher in package checks.
  • Allow Windows artifact replacement while readers retain verified snapshots, and coordinate status reads with publication for the same scan. Other scans remain independent.

Testing

  • All five portable plugin source checks passed: Ruff lint and format, SDK build:ci, source compatibility, and the source-compatibility test suite.
  • SDK generated-model checks, MCP/SDK type checks, and formatting passed.
  • Windows shard job budgets are 40 minutes after repeated passing runs reached the prior job limit. The budget adjustment preserves each job’s tests and per-test timeouts.
  • Focused regressions cover selected Python during result reload, fresh/resumed discovery and reducer settings, native provider startup and authentication, concurrent CLI/SDK attribution, credential reuse, opaque saved scope metadata, and stopped-result publication retries.
  • The npm package content check and installed smoke suite passed, including public imports and NodeNext declarations, CLI/SDK lifecycle, native execution locking, 149 bundled plugin files, and composed Deep Scan with ordinary children, a reducer, and sealed recovery.
  • The Windows publication follow-up at 13084da10d5 passed 158 focused Python tests on Python 3.13.14, with 11 Windows-only tests skipped locally, and six affected SDK resume cases. All five portable plugin checks were repeated successfully on this follow-up.
  • Both complete local SDK suites at 2ff5df0a177 passed 4,867 tests with 66 skipped and no failures. The later fixed-seed and randomized runs at f38509061c9 completed with one and eight 30-second timeouts respectively; those exact cases passed hosted Ubuntu baseline and parallel runs at 0e8ad8c0592. The original local failures remain recorded.

Tests use synthetic local artifacts, credentials, and model responses; these checks do not assess live model quality.

Risk and rollout

Ship the plugin and bundled SDK together. Interrupted v1 scans and unsealed v1 worker fragments require the prior release; completed historical reports remain readable. Historical checkpoints without a pending checkpoint index are no longer imported automatically into unfinished scans. Finish those scans with the prior release or start a fresh scan.

get-cli-scan-resume --migrate and implicit npm, managed-package, and desktop-cache executable discovery are removed. Configure CODEX_CLI_PATH or expose the real executable on PATH. Unreleased database snapshots that inferred child membership from artifact paths are not backfilled; start fresh scans for those snapshots. Schema migrations remain append-only.

The selected original supplies each merged finding's current narrative; earlier accepted narratives and every source finding remain in provenance. This does not claim improved precision, recall, or latency. Credential, unsafe-path, target/claim, and artifact-seal protections remain. If a limit stops discovery before any child starts, the empty result retains partial coverage and may have a null thread ID.

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.

Comment thread plugins/codex-security/mcp-app/scripts/build_mcp_app.mjs Fixed
Comment thread plugins/codex-security/mcp-app/src/artifact-discovery.ts Fixed
Comment thread plugins/codex-security/mcp-app/src/artifact-io.ts Fixed
Comment thread plugins/codex-security/mcp-app/server.ts Fixed

@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: 57984f86c6

ℹ️ 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 +124 to +129
const inheritedEnvironment = await snapshotNativeEnvironment();
const codex = await resolveTrustedCodex(
inheritedEnvironment,
(await gitMarkerRoot(input.scan.targetPath, signal, "outermost")) ??
input.scan.targetPath,
);

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 Skip Codex resolution for sealed native recovery

When the host stops after artifacts are sealed but before complete-scan commits the parent, the next invocation still enters prepareNativeScan because the database status remains running. This eagerly requires a trusted Codex executable before publicationOnly is detected below, so if CODEX_CLI_PATH or PATH changed during the restart—for example, while the CLI was upgraded—the already-completed scan cannot be published even though the sealed-result branch in api.ts performs no model turn. Detect sealed publication before resolving Codex, or otherwise avoid requiring an executable on this recovery-only path.

Useful? React with 👍 / 👎.

Comment on lines +102 to +105
if (
record.parentScanId !== input.scanId ||
record.targetPath !== input.repository
)

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 Reject child scans from a different repository revision

When the repository changes between Deep Scan batches, a newly registered Standard child captures the new revision, but this acceptance check verifies only its parent ID and repository path. The projection helper then validates that child against its own receipt, not the parent's original revision, so the reducer can combine findings from multiple code states while the parent manifest remains bound to the original target revision; a final target-change warning does not make those findings internally consistent. Compare each child's saved target revision or diff snapshot with the parent's registered target identity before accepting it.

AGENTS.md reference: sdk/typescript/AGENTS.md:L23-L24

Useful? React with 👍 / 👎.

@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: 2ff5df0a17

ℹ️ 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".

externalStop.abort(error);
if (discoverySignal.aborted) throw error;
if (attempt >= retries.length) {
await failPass(error);

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 Preserve projection errors for completed child scans

When projectChild keeps failing after client.run has already sealed the ordinary child, the final retry calls failPass on that completed scan. The workbench rejects that transition (a completed scan cannot be marked failed), so this secondary error escapes before exhaustPassRetries and replaces the actual projection or artifact-integrity failure. Only mark a still-running child failed, or retain and rethrow the original projection error when failure recording is rejected.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Something went wrong. Try again later by commenting “@codex review”.

Unknown error
ℹ️ 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".

@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: 13084da10d

ℹ️ 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 +202 to +206
knowledgeBasePaths:
recipe.knowledgeBasePaths ??
(environment.CODEX_SECURITY_KNOWLEDGE_BASE
? [environment.CODEX_SECURITY_KNOWLEDGE_BASE]
: undefined),

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 Do not import ambient knowledge into resumed scans

When a native scan was created without a knowledge base, its recipe omits knowledgeBasePaths; if CODEX_SECURITY_KNOWLEDGE_BASE is set before a later rejoin, this fallback treats that new path as part of the saved scan. The resume branch then calls restoreScanKnowledge, but the original scanInputs records a null knowledge base, so rejoining—including sealed-result publication—fails with “no saved knowledge-base snapshot” instead of preserving the scan’s original inputs. Apply the environment fallback only for fresh scans; resumed scans should use only the recipe.

AGENTS.md reference: AGENTS.md:L31-L35

Useful? React with 👍 / 👎.

with completion_lock(scan_id):
with pytest.raises(RuntimeError, match="nested failure"), completion_lock(scan_id):
raise RuntimeError("nested failure")
assert acquire.call_count == 1
):
assert acquire.call_count == 2
assert release.call_count == 1
with completion_lock(scan_id):
release_completion_file_lock=mock.Mock(),
),
):
acquire = lock_globals["acquire_completion_file_lock"]
),
):
acquire = lock_globals["acquire_completion_file_lock"]
release = lock_globals["release_completion_file_lock"]
@@ -10,6 +10,7 @@
import sys
import tempfile
import threading
import unittest

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change Breaking change called out in generated release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants