Skip to content

feat: add stable review contract identity core#80

Open
Pigbibi wants to merge 2 commits into
mainfrom
codex/pr-review-contract-identity-core
Open

feat: add stable review contract identity core#80
Pigbibi wants to merge 2 commits into
mainfrom
codex/pr-review-contract-identity-core

Conversation

@Pigbibi

@Pigbibi Pigbibi commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • define stable contract_key, behavior_digest, and severity-independent fingerprint_v2
  • serialize bounded history v2 while preserving legacy v1 compatibility
  • recompute v2 identities during parsing and fail closed on mismatches
  • add sanitized fix: classify adapter dispatch outcomes #75/#125 identity replay fixtures
  • keep the existing live streak/matching behavior unchanged until the state reducer lands

This is the C2a replacement slice for #79. Conflict reduction, clear/supersession semantics, and state-machine activation are intentionally deferred to C3.

Verification

  • targeted unittest: 58 passed
  • full unittest discover: 624 passed, 1 skipped
  • ruff check passed
  • compileall passed
  • actionlint passed
  • fixture JSON validation passed
  • git diff check passed

Co-Authored-By: Codex <noreply@openai.com>
@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown

🤖 Codex PR Review

🚫 Merge blocked: 2 serious issue(s) found in high-risk files

🚫 Blocking Issues

These issues must be fixed before this PR can be merged:

1. 🟠 [HIGH] Logic in scripts/run_codex_pr_review.py

build_finding_history_marker() now writes only the codex-pr-review-history:v2 marker, but older workers treat unknown history markers as “no history” instead of a fail-closed state. In a mixed deployment or rollback, unresolved blocking history can disappear from persisted state; this is especially dangerous on rounds blocked only by prior history, because the published comment may have empty live finding_fingerprints, leaving the v2 marker as the only record. (line 1208)

Suggestion: Keep emitting a v1-readable history representation until every reader is upgraded, or preserve the existing marker namespace and gate versioning inside the payload so older workers cannot silently drop active history.

2. 🟠 [HIGH] Logic in scripts/run_codex_pr_review.py

The PR attaches contract_key/fingerprint_v2 to findings, but the runtime still matches history with the legacy blocking_finding_fingerprint() key (file + category + severity). Distinct findings in the same file/category/severity still alias together, so previous_matching_findings() can pick the wrong prior contract or drop one entirely; the new crypto_pr_125 replay fixture is exactly this shape. (line 2060)

Suggestion: Switch repeated-finding detection, history matching, and streak tracking to prefer fingerprint_v2 when present, falling back to the legacy fingerprint only for old comments that do not carry v2 identity fields.


Review by Codex PR Review bot • PR

@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: 654a225450

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



def _normalize_contract_text(value: Any) -> str:
text = _sanitize_history_text(value, 240).lower()

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 Stop redacting code anchors in v2 fingerprints

Because this normalizer now feeds _contract_subject()/_contract_key(), using _sanitize_history_text() here makes the secret redactor run on code anchors before tokenization. Common identifiers that contain digits and are 8-39 chars long, such as parse_v1_history, parse_v2_history, or fingerprint_v2, are all normalized to redacted, so unrelated findings in the same file/category can get the same contract_key/fingerprint_v2 and be persisted as the same contract. That corrupts the new v2 history identity for versioned APIs or symbols; the identity path needs a sanitizer that preserves code identifiers while still scrubbing secrets from stored text.

Useful? React with 👍 / 👎.

Comment thread scripts/run_codex_pr_review.py Outdated
if not isinstance(findings, list):
findings = []
findings = [
{**finding, **_contract_finding(finding)}

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 full file paths for blocking evaluation

This enrichment overwrites the live file field with _contract_finding()'s history-safe value before evaluate_findings() runs, and that path is truncated to 300 characters by _sanitize_history_path(). For a high-severity finding on a changed file whose repository path is longer than 300 characters, file_path in changed_paths no longer matches the full GitHub filename, so the serious finding is treated as non-blocking and the PR can pass. The contract fields should be added without replacing the original file path used for risk/blocking decisions.

Useful? React with 👍 / 👎.

"with", "must", "should", "will", "return",
}
}
return " ".join(sorted(words))

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 Keep word order in behavior digests

This collapses each finding's behavior into a sorted set of tokens before hashing, so opposite mappings with the same words produce the same behavior_digest/fingerprint_v2. For example, suggestions like “treat pending jobs as blocked and completed jobs as clear” and “treat pending jobs as clear and completed jobs as blocked” normalize identically when they reference the same anchor. That persists contradictory contracts as the same behavior in v2 history, so the digest should retain enough ordering or relational structure to distinguish swapped requirements.

Useful? React with 👍 / 👎.

Co-Authored-By: Codex <noreply@openai.com>

@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: 8da2171463

ℹ️ 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 +1239 to +1241
marker_version = 1
else:
# Unknown marker versions are ignored so mixed deployments can roll back safely.

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 Fail closed on unknown history markers

When a trusted comment was written by a newer history namespace, such as codex-pr-review-history:v3 during a rollback or mixed deployment, this branch treats the marker as absent and valid. That makes finding_history empty, so active blocking history can be forgotten and low-risk or clean runs can proceed without the required arbitration; unknown history markers should be treated as malformed/fail-closed rather than silently ignored.

Useful? React with 👍 / 👎.

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.

1 participant