Skip to content

tsk-mjiicy [OPEN] CI check: detect a PR that silently DELETES merged - #2180

Open
jaylfc wants to merge 1 commit into
devfrom
exec/tsk-mjiicy
Open

tsk-mjiicy [OPEN] CI check: detect a PR that silently DELETES merged#2180
jaylfc wants to merge 1 commit into
devfrom
exec/tsk-mjiicy

Conversation

@jaylfc

@jaylfc jaylfc commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Autonomous build of board card tsk-mjiicy.

Files:
scripts/check_deleted_symbols.py | 249 +++++++++++++++
tests/test_check_deleted_symbols.py | 361 +++++++++++++++++++++
tests/test_library.py | 421 -------------------------
tinyagentos/knowledge_fetchers/youtube.py | 17 -
tinyagentos/library_collections.py | 2 +-
tinyagentos/library_pipeline.py | 330 ++-----------------
tinyagentos/routes/library.py | 20 +-
10 files changed, 670 insertions(+), 844 deletions(-)


Summary by Gitar

  • CI & Safety Checks:
    • Added deleted-symbols-gate.yml workflow to prevent silent deletion of code added after branch creation
    • Added check_deleted_symbols.py script to detect and report deleted Python symbols and their adding commits
    • Added comprehensive unit and integration tests in test_check_deleted_symbols.py

This will update automatically on new commits.

Summary by CodeRabbit

  • New Features

    • Added an automated safeguard that detects accidental removal of Python functions, classes, methods, and tests introduced on the target branch.
    • Pull requests now receive clear failure details, including the affected symbol and originating commit.
    • Intentional removals can be approved using a waiver in the pull request description or command-line options.
  • Tests

    • Added comprehensive coverage for symbol detection, waiver handling, and branch-history scenarios.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a Python deleted-symbols guard that compares target, PR, and merge-base revisions, supports intentional-removal waivers, reports violations, runs in GitHub Actions, and includes unit and synthetic-history integration tests.

Changes

Deleted symbols detection

Layer / File(s) Summary
Symbol snapshots and attribution
scripts/check_deleted_symbols.py
Extracts qualified Python functions and classes from git revisions and locates commits that introduced detected symbols.
Violation evaluation and CLI reporting
scripts/check_deleted_symbols.py
Computes signal symbols, applies PR-body and CLI waivers, reports violations, and returns the corresponding exit status.
CI wiring and behavioral validation
.github/workflows/deleted-symbols-gate.yml, tests/test_check_deleted_symbols.py
Runs the guard for pull requests and tests extraction, signal detection, synthetic git histories, and waiver behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant GitHubActions
  participant DeletedSymbolsGuard
  participant GitRepository
  PullRequest->>GitHubActions: trigger workflow
  GitHubActions->>DeletedSymbolsGuard: pass base ref and PR body
  DeletedSymbolsGuard->>GitRepository: compare target, HEAD, and merge-base snapshots
  GitRepository-->>DeletedSymbolsGuard: Python symbols and git history
  DeletedSymbolsGuard-->>GitHubActions: clean result or violation exit status
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly points to the new CI check for detecting silent deletions of merged code symbols.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch exec/tsk-mjiicy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gitar-bot

gitar-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

Important

You are using the Gitar free plan. Upgrade to unlock code review, CI analysis, auto-apply, custom automations, and more.

Gitar

@jaylfc

jaylfc commented Jul 28, 2026

Copy link
Copy Markdown
Owner Author

nemotron-ultra-kilo review

VERDICT: The implementation is solid with comprehensive tests. One correctness bug in symbol extraction and one potential security issue.

  • scripts/check_deleted_symbols.py:78_extract_symbols uses ast.iter_child_nodes which only visits immediate children, not recursively. Nested functions/classes deeper than 2 levels will be missed. Should use ast.walk or recursive traversal.

  • scripts/check_deleted_symbols.py:151subprocess.run with check=True but no timeout. Malicious or hung git log -S could block indefinitely. Add timeout=30.

  • tests/test_check_deleted_symbols.py — No test for deeply nested symbols (e.g., class A: class B: class C: def d(): pass) to catch the traversal bug above.

  • scripts/check_deleted_symbols.py:199_find_adding_commit searches for kind + " " + leaf + "(" but this fails for decorated functions (@decorator\ndef foo():) since the def isn't at line start. The fallback without ( catches class Foo: but not decorated defs.

  • scripts/check_deleted_symbols.py:100git archive loads entire repo into memory via tarfile. For large repos this could OOM. Consider streaming or git ls-tree + git show per file.

  • scripts/check_deleted_symbols.py:222parse_waived_symbols only reads first Removes-Intentionally: line per trailer. Multiple trailers on separate lines are handled (tested), but a single line with multiple trailers like Removes-Intentionally: a,b\nRemoves-Intentionally: c works. No issue found.

No blocking issues beyond the nested traversal bug and missing timeout.
VERDICT: The implementation is solid with comprehensive tests. One correctness bug in symbol extraction and one potential security issue.

  • scripts/check_deleted_symbols.py:78_extract_symbols uses ast.iter_child_nodes which only visits immediate children, not recursively. Nested functions/classes deeper than 2 levels will be missed. Should use ast.walk or recursive traversal.

  • scripts/check_deleted_symbols.py:151subprocess.run with check=True but no timeout. Malicious or hung git log -S could block indefinitely. Add timeout=30.

  • tests/test_check_deleted_symbols.py — No test for deeply nested symbols (e.g., class A: class B: class C: def d(): pass) to catch the traversal bug above.

  • scripts/check_deleted_symbols.py:199_find_adding_commit searches for kind + " " + leaf + "(" but this fails for decorated functions (@decorator\ndef foo():) since the def isn't at line start. The fallback without ( catches class Foo: but not decorated defs.

  • scripts/check_deleted_symbols.py:100git archive loads entire repo into memory via tarfile. For large repos this could OOM. Consider streaming or git ls-tree + git show per file.

  • scripts/check_deleted_symbols.py:222parse_waived_symbols only reads first Removes-Intentionally: line per trailer. Multiple trailers on separate lines are handled (tested), but a single line with multiple trailers like Removes-Intentionally: a,b\nRemoves-Intentionally: c works. No issue found.

No blocking issues beyond the nested traversal bug and missing timeout.

Automated first-pass review by the nemotron-ultra-kilo lane. The lead still reviews before merge.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

CI: gate PRs that silently delete symbols added after merge base

✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Add a CI gate that detects PRs silently deleting Python defs/classes added on base branch.
• Require explicit PR-body waivers (Removes-Intentionally) for deliberate symbol removals.
• Add unit + synthetic-git integration tests covering pass/fail and waiver behavior.
Diagram

graph TD
  A([PR opened/updated]) --> B["deleted-symbols-gate.yml"] --> C["check_deleted_symbols.py"] --> G{Signal deletions?}
  F["PR body waivers"] --> C
  C --> D["git merge-base/archive/log"] --> E["AST symbol scan"]
  G -->|No| H["Pass"]
  G -->|Yes| I["Fail + report"]

  subgraph Legend
    direction LR
    _wf([Workflow trigger]) ~~~ _proc["Process/script"] ~~~ _dec{Decision}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Scope scanning to touched Python files only
  • ➕ Much faster on large repos (avoid archiving/parsing every .py file).
  • ➕ Fewer false positives from unrelated areas if policy is intended to gate only modified files.
  • ➖ May miss silent deletions caused by old branches overwriting files they didn't modify in the PR diff (the exact failure mode this guard targets).
  • ➖ Requires more careful file-selection logic (e.g., merge-tree analysis) to remain correct.
2. Compute merged result and diff symbols vs base (merge simulation)
  • ➕ Directly detects what would happen after the merge (closest to ground truth).
  • ➕ Can focus only on files impacted in the merge result.
  • ➖ More complex to implement robustly in CI (needs merge-tree/temporary merge commits and careful handling of conflicts).
  • ➖ Harder to explain/debug than the current set-based approach.
3. Use a CST library (e.g., LibCST) instead of ast
  • ➕ More tolerant of formatting/edge cases and can preserve positions.
  • ➕ Potentially better handling for syntax that ast rejects in some partial contexts.
  • ➖ Adds a dependency and increases CI/runtime footprint.
  • ➖ Current ast-based extraction is intentionally narrow and already covers the needed symbol types.

Recommendation: Keep the current repo-wide AST + git-archive approach: it is simple, deterministic, and specifically addresses the “old branch wins silently” merge failure mode. If runtime becomes an issue, the next step would be an optimized—but still merge-correct—file selection strategy (e.g., based on merge-tree), not merely scanning PR-touched files.

Files changed (3) +649 / -0

Enhancement (1) +249 / -0
check_deleted_symbols.pyImplement guard script to detect base-only symbol deletions since merge base +249/-0

Implement guard script to detect base-only symbol deletions since merge base

• Adds a Python script that computes merge-base, snapshots symbols at base/HEAD/merge-base via git archive, and flags symbols present only on base after the branch point. Supports explicit waivers via a PR-body Removes-Intentionally trailer or a CLI --waived list and reports the commit that introduced each deleted symbol.

scripts/check_deleted_symbols.py

Tests (1) +361 / -0
test_check_deleted_symbols.pyAdd unit + synthetic-git integration tests for deleted-symbols guard +361/-0

Add unit + synthetic-git integration tests for deleted-symbols guard

• Adds focused unit tests for symbol extraction, waiver parsing, and signal set calculation. Adds integration tests that build temporary git repos to verify failing/pass scenarios and waiver behavior for functions, classes, methods, and test defs.

tests/test_check_deleted_symbols.py

Other (1) +39 / -0
deleted-symbols-gate.ymlAdd GitHub Actions gate for silently deleted Python symbols +39/-0

Add GitHub Actions gate for silently deleted Python symbols

• Introduces a pull_request workflow (master/dev) that fetches full history and runs the deleted-symbols guard against the base ref. Passes the PR body to the script to enable explicit waivers via trailers.

.github/workflows/deleted-symbols-gate.yml

@jaylfc

jaylfc commented Jul 28, 2026

Copy link
Copy Markdown
Owner Author

Reviewed, and I did the strongest test available: I ran this check against the actual incident it was built for.

I checked out the old #2068 head (the PR that would have silently deleted merged P1 hardening) and ran your script against origin/dev:

DELETED-SYMBOLS FAIL: this PR deletes 85 symbol(s) that landed on dev after your branch was cut:
  - tinyagentos/knowledge_fetchers/youtube.py:_cleanup_procs (added by af081747 ...)
  - tinyagentos/projects/project_store.py:ProjectConflict.__init__ (added by ca1d2fef ...)
  - tinyagentos/notifications_push.py:_vapid_signing_key (added by d3ccf221 ...)
  ...

It caught it, and it named _cleanup_procs specifically — one of the exact symbols I found by hand-diffing at 11pm, which is why this card exists. It also attributes each deletion to the commit that introduced it, which is the part that makes a finding actionable instead of alarming. That is real evidence rather than a passing test, and it is what I wanted.

Two notes before this becomes a gate people rely on.

1. The stale-branch case produces 85 findings, and that is a UX problem rather than a correctness one. Every one of those 85 is technically true: #2068 was cut long ago and dev has moved a great deal, so merging it really would delete all of them. But a reviewer shown 85 items will not read 85 items. They will waive the lot, and a gate that trains people to waive is worse than no gate.

Suggestion: when the count exceeds a threshold, replace the enumeration with the actual diagnosis, which is different: "your branch is N commits behind origin/dev and would delete 85 symbols that landed since. Rebase first, then re-run." On a stale branch the answer is always "rebase", never "waive 85 symbols one at a time". Keep the full list behind a flag or in the job log.

2. Do NOT add this to required status checks yet. As a new workflow it is advisory, which is the right place to start. Let it run in report-only mode across a few days of real PRs first: if it fires on branches that are merely stale rather than genuinely reverting, that is exactly the signal to tune the threshold before it can block anyone. Making it required on day one risks jamming the queue on the noise above.

Implementation itself looks right: merge-base, then git log -S <symbol> merge_base..base to find the introducing commit, which is precisely the discrimination the card asked for (deleting your own new code passes; deleting code that landed after you branched fails). Removes-Intentionally: gives a deliberate, auditable waiver rather than a silent bypass, and waivers are logged. 649 additions, 0 deletions, with tests and the workflow.

Nice work. Fold the stale-branch messaging and I will merge it.

One correction on my own testing, for the record: my first attempt at this crashed with git merge-base exit 128 and I nearly reported it as a bug in your script. It was my harness: the script derives REPO_ROOT from its own file location and I had run it from /tmp, which is not a git repo. Re-ran with the script inside the tree and it worked perfectly. The script is fine; I was holding it wrong.

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (1)

Context used
✅ Compliance rules (platform): 35 rules

Grey Divider


Action required

1. Workflow uses Python 3.12 📜 Skill insight ≡ Correctness
Description
The new deleted-symbols-gate workflow pins python-version: "3.12", which does not enforce the
required minimum runtime target of Python 3.11 for Python code in this repo. This can allow
3.12-only syntax/features to slip in without being caught by CI running on the mandated baseline.
Code

.github/workflows/deleted-symbols-gate.yml[R27-30]

+      - uses: actions/setup-python@v7
+        with:
+          python-version: "3.12"
+
Relevance

⭐⭐⭐ High

Repo CI already emphasizes Python 3.11; pinning 3.12 risks missing baseline issues.

PR-#391

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2185263 requires the codebase to target Python 3.11 as the minimum version and
avoid relying on 3.12+ specifics. The added workflow explicitly sets python-version: "3.12", which
fails to validate the required baseline version.

.github/workflows/deleted-symbols-gate.yml[27-30]
Skill: taos-development-skill

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow `.github/workflows/deleted-symbols-gate.yml` is configured to run with Python 3.12, but the compliance requirement is to target Python 3.11 as the minimum supported version.

## Issue Context
CI should validate against the minimum supported Python version so that 3.12-only syntax/features do not merge unnoticed.

## Fix Focus Areas
- .github/workflows/deleted-symbols-gate.yml[27-30]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Gate checks merge ref 🐞 Bug ≡ Correctness
Description
The workflow likely runs on the pull_request synthetic merge commit (refs/pull/<n>/merge) and does
not explicitly checkout the PR head SHA; in that case git merge-base HEAD origin/<base> becomes
the base tip, making dev_symbols and mb_symbols identical and the signal set always empty. As a
result, the deleted-symbols gate can report "clean" even when the PR would silently delete symbols
added to the base branch after the branch point.
Code

.github/workflows/deleted-symbols-gate.yml[R23-26]

+      - uses: actions/checkout@v7
+        with:
+          fetch-depth: 0
+
Relevance

⭐⭐⭐ High

CI correctness bug; team has accepted workflow-hardening suggestions before.

PR-#524
PR-#391

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The workflow checks out without specifying a PR-head ref, while the script computes merge base
against HEAD. The repo’s CI workflow notes that PR runs carry refs/pull/<n>/merge, implying
HEAD can be a merge commit whose merge-base with the base branch is the base tip itself; this
makes mb_symbols equal dev_symbols, so dev - head - mb becomes empty.

.github/workflows/deleted-symbols-gate.yml[19-39]
scripts/check_deleted_symbols.py[60-62]
scripts/check_deleted_symbols.py[173-192]
.github/workflows/ci.yml[21-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`deleted-symbols-gate.yml` checks out the default ref for `pull_request` events, which is typically the synthetic merge commit. The guard script computes `git merge-base HEAD <base>`, and when `HEAD` is that merge commit the merge-base resolves to the base tip, making the signal empty and disabling the gate.

## Issue Context
The guard’s algorithm depends on `HEAD` being the PR branch head (not the merge result). The repo already documents that PR events use `refs/pull/<n>/merge`.

## Fix Focus Areas
- .github/workflows/deleted-symbols-gate.yml[23-39]
 - Update `actions/checkout` to explicitly checkout the PR head commit, e.g.:
   - `with: ref: ${{ github.event.pull_request.head.sha }}` (keep `fetch-depth: 0`).
 - Keep the existing `git fetch origin "$BASE_REF"` step so `origin/${{ github.base_ref }}` is available.

(Alternative fix if you prefer not to change checkout: extend the script to accept a `--head <ref>` argument and compute merge-base against that ref instead of `HEAD`, then pass it from the workflow.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +27 to +30
- uses: actions/setup-python@v7
with:
python-version: "3.12"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Workflow uses python 3.12 📜 Skill insight ≡ Correctness

The new deleted-symbols-gate workflow pins python-version: "3.12", which does not enforce the
required minimum runtime target of Python 3.11 for Python code in this repo. This can allow
3.12-only syntax/features to slip in without being caught by CI running on the mandated baseline.
Agent Prompt
## Issue description
The workflow `.github/workflows/deleted-symbols-gate.yml` is configured to run with Python 3.12, but the compliance requirement is to target Python 3.11 as the minimum supported version.

## Issue Context
CI should validate against the minimum supported Python version so that 3.12-only syntax/features do not merge unnoticed.

## Fix Focus Areas
- .github/workflows/deleted-symbols-gate.yml[27-30]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +23 to +26
- uses: actions/checkout@v7
with:
fetch-depth: 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Gate checks merge ref 🐞 Bug ≡ Correctness

The workflow likely runs on the pull_request synthetic merge commit (refs/pull/<n>/merge) and does
not explicitly checkout the PR head SHA; in that case git merge-base HEAD origin/<base> becomes
the base tip, making dev_symbols and mb_symbols identical and the signal set always empty. As a
result, the deleted-symbols gate can report "clean" even when the PR would silently delete symbols
added to the base branch after the branch point.
Agent Prompt
## Issue description
`deleted-symbols-gate.yml` checks out the default ref for `pull_request` events, which is typically the synthetic merge commit. The guard script computes `git merge-base HEAD <base>`, and when `HEAD` is that merge commit the merge-base resolves to the base tip, making the signal empty and disabling the gate.

## Issue Context
The guard’s algorithm depends on `HEAD` being the PR branch head (not the merge result). The repo already documents that PR events use `refs/pull/<n>/merge`.

## Fix Focus Areas
- .github/workflows/deleted-symbols-gate.yml[23-39]
  - Update `actions/checkout` to explicitly checkout the PR head commit, e.g.:
    - `with: ref: ${{ github.event.pull_request.head.sha }}` (keep `fetch-depth: 0`).
  - Keep the existing `git fetch origin "$BASE_REF"` step so `origin/${{ github.base_ref }}` is available.

(Alternative fix if you prefer not to change checkout: extend the script to accept a `--head <ref>` argument and compute merge-base against that ref instead of `HEAD`, then pass it from the workflow.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@jaylfc

jaylfc commented Jul 28, 2026

Copy link
Copy Markdown
Owner Author

nemotron-super review

VERDICT: Blocking issue found

  • scripts/check_deleted_symbols.py:147: The function _find_adding_commit uses git log -S --reverse and returns the first line, which may incorrectly identify an earlier commit if the symbol was removed and later readded in the target branch.
  • scripts/check_deleted_symbols.py:157: Same issue in the fallback search for classes without bases.

Automated first-pass review by the nemotron-super lane. The lead still reviews before merge.

@jaylfc

jaylfc commented Jul 28, 2026

Copy link
Copy Markdown
Owner Author

nemotron-ultra-orB review

VERDICT: Approve with non-blocking findings — the guard logic is sound and well-tested, but the commit-attribution heuristic is fragile and should be tightened.

  • scripts/check_deleted_symbols.py:164-178_find_adding_commit uses git log -S with overly broad search strings (def name( / class Name). This matches comments, strings, and unrelated same-named symbols in the same file, causing wrong commit attribution or "unknown". Should anchor to line-start (^) and/or use -G with regex for ^\s*(def|class)\s+name.
  • scripts/check_deleted_symbols.py:132decode("utf-8", errors="ignore") silently drops non-UTF8 content; use errors="replace" or fail loudly.
  • scripts/check_deleted_symbols.py:82-83 — Recursive visit can hit recursion limit on deeply nested code; convert to iterative or add sys.setrecursionlimit guard.
  • tests/test_check_deleted_symbols.py — Missing integration tests for: nested qualified names (Outer.Inner.method), symbol moved across files, Unicode identifiers, decorators on functions/classes.

Automated first-pass review by the nemotron-ultra-orB lane. The lead still reviews before merge.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (4)
.github/workflows/deleted-symbols-gate.yml (3)

19-22: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider declaring least-privilege permissions: for this job.

The job only reads git history and never writes to the repo or PR, but no permissions: block is declared, so it inherits the repository/org default (which can be broader than contents: read).

🔒️ Suggested addition
 jobs:
   deleted-symbols-gate:
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
     steps:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deleted-symbols-gate.yml around lines 19 - 22, Add a
job-level permissions block to deleted-symbols-gate granting only contents:
read, while leaving the existing runs-on and steps configuration unchanged.

36-39: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Inline ${{ github.base_ref }} interpolation in run: (template-injection flag).

--base "origin/${{ github.base_ref }}" interpolates the expression directly into the shell command, the pattern zizmor flags as template-injection. The step already demonstrates the safer alternative for PR_BODY via env:, and the prior "Fetch base branch" step does the same for this exact value (BASE_REF) — this step should follow suit for consistency and defense-in-depth.

🔒️ Suggested fix
       - name: Check for silently deleted symbols
         env:
           PR_BODY: ${{ github.event.pull_request.body }}
-        run: python scripts/check_deleted_symbols.py --base "origin/${{ github.base_ref }}"
+          BASE_REF: ${{ github.base_ref }}
+        run: python scripts/check_deleted_symbols.py --base "origin/$BASE_REF"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deleted-symbols-gate.yml around lines 36 - 39, Update the
“Check for silently deleted symbols” step to pass the GitHub base reference
through an environment variable, following the existing BASE_REF pattern, and
reference that variable in the Python command instead of interpolating
github.base_ref directly in run.

Source: Linters/SAST tools


23-25: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Verify: default checkout ref is GitHub's merge commit, not the raw PR branch.

Without an explicit ref:, actions/checkout@v7 on a pull_request event checks out the GitHub-generated test-merge commit (refs/pull/N/merge), not github.event.pull_request.head.sha. But scripts/check_deleted_symbols.py's docstring documents the algorithm as comparing "the target branch head, HEAD (the PR branch), and the merge base" — i.e. it assumes HEAD is the raw branch tip.

This matters two ways:

  • If intentional, HEAD symbols reflect dev merged into the PR branch, which is actually closer to testing the real "clean merge, no conflict" failure mode this gate targets — worth documenting explicitly if so.
  • If unintentional, and the PR currently has any conflicts with the base, refs/pull/N/merge can be stale or unavailable, and checkout can fail outright (unrelated to any real deleted-symbol violation).

If the raw branch tip is what's intended, pin it explicitly:

with:
  ref: ${{ github.event.pull_request.head.sha }}
  fetch-depth: 0

Separately, since this job never pushes and doesn't need to persist git credentials, consider adding persist-credentials: false here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deleted-symbols-gate.yml around lines 23 - 25, Update the
actions/checkout step in the deleted-symbols gate to explicitly check out
github.event.pull_request.head.sha, preserving fetch-depth: 0 so the comparison
history remains available. Add persist-credentials: false because the job does
not push changes, and ensure the script’s documented HEAD assumption matches the
raw PR branch checkout.
tests/test_check_deleted_symbols.py (1)

241-241: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Unused waived unpacking (Ruff RUF059) in 4 tests.

test_deleted_class_added_after_merge_base_fails (L241), test_deleted_method_added_after_merge_base_fails (L265), test_deleted_test_function_added_after_merge_base_fails (L287), and test_no_signal_when_dev_unchanged_since_merge_base (L311) unpack violations, waived = ... but never assert on waived.

🧹 Suggested fix (repeat for each of the 4 occurrences)
-        violations, waived = cds.check_deleted_symbols("main", repo)
+        violations, _waived = cds.check_deleted_symbols("main", repo)

Also applies to: 265-265, 287-287, 311-311

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_check_deleted_symbols.py` at line 241, Remove the unused waived
unpacking in the four tests test_deleted_class_added_after_merge_base_fails,
test_deleted_method_added_after_merge_base_fails,
test_deleted_test_function_added_after_merge_base_fails, and
test_no_signal_when_dev_unchanged_since_merge_base. Update each
check_deleted_symbols call to retain only the violations result while preserving
the existing assertions.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/check_deleted_symbols.py`:
- Around line 131-141: Update the fallback search pattern in _find_adding_commit
to require a word boundary after leaf, preventing names such as FooBar or
FooExtended from matching a requested Foo symbol. Preserve the existing git
search flow and unknown fallback while ensuring the exact class or symbol name
is matched.

---

Nitpick comments:
In @.github/workflows/deleted-symbols-gate.yml:
- Around line 19-22: Add a job-level permissions block to deleted-symbols-gate
granting only contents: read, while leaving the existing runs-on and steps
configuration unchanged.
- Around line 36-39: Update the “Check for silently deleted symbols” step to
pass the GitHub base reference through an environment variable, following the
existing BASE_REF pattern, and reference that variable in the Python command
instead of interpolating github.base_ref directly in run.
- Around line 23-25: Update the actions/checkout step in the deleted-symbols
gate to explicitly check out github.event.pull_request.head.sha, preserving
fetch-depth: 0 so the comparison history remains available. Add
persist-credentials: false because the job does not push changes, and ensure the
script’s documented HEAD assumption matches the raw PR branch checkout.

In `@tests/test_check_deleted_symbols.py`:
- Line 241: Remove the unused waived unpacking in the four tests
test_deleted_class_added_after_merge_base_fails,
test_deleted_method_added_after_merge_base_fails,
test_deleted_test_function_added_after_merge_base_fails, and
test_no_signal_when_dev_unchanged_since_merge_base. Update each
check_deleted_symbols call to retain only the violations result while preserving
the existing assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7c9e771f-df5c-4eec-86d5-7b7b032b76d4

📥 Commits

Reviewing files that changed from the base of the PR and between 905b632 and d5dded8.

📒 Files selected for processing (3)
  • .github/workflows/deleted-symbols-gate.yml
  • scripts/check_deleted_symbols.py
  • tests/test_check_deleted_symbols.py

Comment on lines +131 to +141
# Fallback: try without the opening paren (for classes without bases,
# e.g. `class Foo:` rather than `class Foo(Bar):`).
search = f"{kind} {leaf}"
out = _run_git(
["log", "--oneline", "--reverse", "-S", search, f"{merge_base}..{target}", "--", file_path],
cwd=repo_root,
)
lines = out.splitlines()
if lines:
return lines[0]
return "unknown"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fallback class-name search can match a longer name sharing the same prefix.

The fallback pattern f"{kind} {leaf}" (no trailing ( or :) is a raw substring match. For class Foo: it also matches class FooBar: or class FooExtended(Base):, so _find_adding_commit can attribute a deleted Foo class to the commit that actually added an unrelated FooBar/FooExtended class. This only corrupts the "added by" message (the pass/fail signal itself is computed elsewhere via exact symbol keys), but that message is the tool's main auditability payoff.

🐛 Suggested fix: anchor the fallback to a word boundary
     # Fallback: try without the opening paren (for classes without bases,
     # e.g. `class Foo:` rather than `class Foo(Bar):`).
-    search = f"{kind} {leaf}"
+    search = f"{kind} {leaf}:"
     out = _run_git(
         ["log", "--oneline", "--reverse", "-S", search, f"{merge_base}..{target}", "--", file_path],
         cwd=repo_root,
     )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Fallback: try without the opening paren (for classes without bases,
# e.g. `class Foo:` rather than `class Foo(Bar):`).
search = f"{kind} {leaf}"
out = _run_git(
["log", "--oneline", "--reverse", "-S", search, f"{merge_base}..{target}", "--", file_path],
cwd=repo_root,
)
lines = out.splitlines()
if lines:
return lines[0]
return "unknown"
# Fallback: try without the opening paren (for classes without bases,
# e.g. `class Foo:` rather than `class Foo(Bar):`).
search = f"{kind} {leaf}:"
out = _run_git(
["log", "--oneline", "--reverse", "-S", search, f"{merge_base}..{target}", "--", file_path],
cwd=repo_root,
)
lines = out.splitlines()
if lines:
return lines[0]
return "unknown"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check_deleted_symbols.py` around lines 131 - 141, Update the fallback
search pattern in _find_adding_commit to require a word boundary after leaf,
preventing names such as FooBar or FooExtended from matching a requested Foo
symbol. Preserve the existing git search flow and unknown fallback while
ensuring the exact class or symbol name is matched.

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