feat(ci): baseline diff + strict mode + diff-scan flags (closes #57 phase 1+2)#141
Merged
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This was referenced Jul 1, 2026
78a5a8f to
6c88d5e
Compare
Wolfvin
added a commit
that referenced
this pull request
Jul 3, 2026
Two fixes for PR #141 per issue #171: 1. Add missing @WHO/@WHAT/@PART/@entry file headers to the 3 new files introduced by PR #141: - scripts/baseline_diff.py - scripts/exit_policy.py - scripts/git_integration.py (issue #171 explicitly mentions baseline_diff.py; exit_policy.py and git_integration.py have the same gap — fixed for consistency since CONTRIBUTING.md mandates the header on all new files.) 2. Restore the `-f` shortcut conflict guard in scripts/codelens.py that was removed by PR #153 (graphml, issue #59 Phase 3). The guard checks `existing_option_strings` before adding `-f` to a subparser, so commands like `affected` (issue #62) that use `-f` for `--filter` don't conflict with the global `--format -f` shortcut. This bug made `codelens --help` and every CLI invocation crash with `argparse.ArgumentError: argument --format/-f: conflicting option string: -f`. It was a pre-existing regression on main (introduced when PR #153 was merged) that blocked PR #141's tests from running. The fix restores the pre-#153 logic: ```python if "format" not in existing_dests: format_args = ["--format"] if "-f" not in existing_option_strings: format_args.append("-f") sub.add_argument(*format_args, choices=[...], ...) ``` Verified: - `codelens --command-count` works (returns 75) - `codelens --help` works - 99 PR #141 tests pass (test_baseline_diff + test_check_ci_flags + test_exit_policy + test_git_integration) - 196 passed regression (test_cli + test_formatters + test_command_count + test_command_registry + 4 PR #141 test files) - 135 passed (test_graphml_formatter + test_diff_scope + test_secrets_gitleaks — confirms the format change doesn't regress graphml/diff-base/gitleaks) - sync_command_count.py --check: all docs in sync (count=75) Findings (per pre-flight SKILL.md — flag to BOS): - The `-f` conflict bug was introduced by PR #153 (issue #59 Phase 3, graphml export). PR #153 simplified the format-arg logic and accidentally dropped the `existing_option_strings` check. This fix restores the check while keeping the `graphml` choice. No regression to graphml functionality (test_graphml_formatter.py: 35 passed). - PR #141 was already rebased on main; no merge conflicts. The rebase + these fixes make PR #141 mergeable.
6c88d5e to
23487af
Compare
5 tasks
…hase 1+2) Issue #57 — Phase 1 (baseline + diff scan) + Phase 2 (strict mode). Phase 1 — baseline + diff scan: - New scripts/git_integration.py: thin wrapper over git_aware._run_git with CI/CD-specific helpers (list_staged_files, list_working_tree_changes, list_diff_vs, resolve_baseline_sha, detect_ci_environment). - New scripts/baseline_diff.py: finding identity hash (rule_id|file|line|severity), diff_findings() that classifies findings into new/preexisting/resolved, save/load_baseline() persisting to .codelens/baseline_<SHA>.json, filter_to_changed_files(). - check.py: new --baseline-commit, --save-baseline, --diff-scan, --staged, --diff-vs flags. When --baseline-commit is set the gate operates on NEW findings only (preexisting ones are surfaced but don't fail). --save-baseline persists the current findings as the baseline for a future run. - formatters/sarif.py: to_sarif() and format_sarif() now accept automation_guid (issue #57 spec) — emitted as SARIF automationDetails.guid so CI dashboards can group related runs. Phase 2 — strict mode + thresholds: - New scripts/exit_policy.py: ExitDecision dataclass + evaluate_exit_policy() implementing --strict (threshold=low), --error (threshold=high), --severity-threshold <level>, --max-findings N. Pure function — does not call sys.exit; the caller (codelens.py main dispatcher) handles the exit code via the existing 'gate' field. - check.py: --strict / --error / --severity-threshold flags wired in. When none of the new flags are set, the legacy --severity/--max-findings gate runs unchanged (backward-compat for existing CI configs). Acceptance criteria satisfied (Phase 1+2 subset): - [x] codelens check --baseline-commit <SHA> reports only new findings - [x] codelens check --strict --error exits non-zero on high-severity - [x] SARIF automationDetails.guid emitted when --baseline-commit set - [x] --diff-scan / --staged / --diff-vs narrow to git-changed files Out of scope for this PR (will be separate PRs): - Phase 3: 'codelens ci' orchestration command + 'codelens install-ci' - Phase 4: manifest-driven test suite - Phase 5: rule quality harness + golden snapshots - Phase 6: git sync hooks - Phase 7: agent benchmark harness Tests: - tests/test_baseline_diff.py — 33 unit tests (identity, diff, persistence) - tests/test_exit_policy.py — 32 unit tests (strict/error/threshold/max-findings) - tests/test_git_integration.py — 21 unit tests (staged/working-tree/diff-vs, CI env detection, non-git graceful failure) - tests/test_check_ci_flags.py — 13 integration tests (end-to-end codelens check with new flags, real git repos) - Total new: 99 tests, all green Full test suite (excluding test_integration.py per CONTEXT.md and tree-sitter-dependent tests that require optional deps): 1294 passed, 90 skipped, 4 pre-existing failures (test_codelensignore::test_actual_target_dir_is_ignored + 3× test_universal_grammar_loader — verified via git stash to fail identically on unmodified main, unrelated to this PR).
Two fixes for PR #141 per issue #171: 1. Add missing @WHO/@WHAT/@PART/@entry file headers to the 3 new files introduced by PR #141: - scripts/baseline_diff.py - scripts/exit_policy.py - scripts/git_integration.py (issue #171 explicitly mentions baseline_diff.py; exit_policy.py and git_integration.py have the same gap — fixed for consistency since CONTRIBUTING.md mandates the header on all new files.) 2. Restore the `-f` shortcut conflict guard in scripts/codelens.py that was removed by PR #153 (graphml, issue #59 Phase 3). The guard checks `existing_option_strings` before adding `-f` to a subparser, so commands like `affected` (issue #62) that use `-f` for `--filter` don't conflict with the global `--format -f` shortcut. This bug made `codelens --help` and every CLI invocation crash with `argparse.ArgumentError: argument --format/-f: conflicting option string: -f`. It was a pre-existing regression on main (introduced when PR #153 was merged) that blocked PR #141's tests from running. The fix restores the pre-#153 logic: ```python if "format" not in existing_dests: format_args = ["--format"] if "-f" not in existing_option_strings: format_args.append("-f") sub.add_argument(*format_args, choices=[...], ...) ``` Verified: - `codelens --command-count` works (returns 75) - `codelens --help` works - 99 PR #141 tests pass (test_baseline_diff + test_check_ci_flags + test_exit_policy + test_git_integration) - 196 passed regression (test_cli + test_formatters + test_command_count + test_command_registry + 4 PR #141 test files) - 135 passed (test_graphml_formatter + test_diff_scope + test_secrets_gitleaks — confirms the format change doesn't regress graphml/diff-base/gitleaks) - sync_command_count.py --check: all docs in sync (count=75) Findings (per pre-flight SKILL.md — flag to BOS): - The `-f` conflict bug was introduced by PR #153 (issue #59 Phase 3, graphml export). PR #153 simplified the format-arg logic and accidentally dropped the `existing_option_strings` check. This fix restores the check while keeping the `graphml` choice. No regression to graphml functionality (test_graphml_formatter.py: 35 passed). - PR #141 was already rebased on main; no merge conflicts. The rebase + these fixes make PR #141 mergeable.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Issue #57 — CI/CD integration suite, Phase 1 + Phase 2
Closes #57 (partial — Phase 1 + Phase 2 only).
Scope of this PR
Issue #57 has 7 phases. This PR implements Phase 1 (baseline + diff scan) and Phase 2 (strict mode + thresholds). Phases 3–7 (codelens ci command, manifest tests, golden snapshots, git hooks, agent benchmark) will be separate PRs.
Phase 1 — baseline + diff scan
New files:
scripts/git_integration.py— thin wrapper overgit_aware._run_gitwith CI/CD-specific helpers:list_staged_files,list_working_tree_changes,list_diff_vs,resolve_baseline_sha(resolution order: explicit arg →$CODELENS_BASELINE_SHAenv →HEAD~1),detect_ci_environment(GitHub/GitLab/Jenkins/Bitbucket/CircleCI).scripts/baseline_diff.py— finding identity hash(rule_id|file|line|severity)(deliberately excludes message text and column for stability across parser updates),diff_findings()classifying into new/preexisting/resolved,save_baseline()/load_baseline()persisting to.codelens/baseline_<SHA>.json,filter_to_changed_files().Modified:
scripts/commands/check.py— new flags:--baseline-commit <SHA>— only NEW findings fail the gate; preexisting ones are surfaced in output but don't fail--save-baseline— persist current findings as the baseline for a future--baseline-commitrun--diff-scan— restrict to working-tree changes (vs HEAD)--staged— restrict to staged files (git diff --cached)--diff-vs <ref>— restrict to files changed vs ref (branch/tag/SHA)scripts/formatters/sarif.py—to_sarif()/format_sarif()acceptautomation_guidparam, emitted as SARIFautomationDetails.guidso CI dashboards (GitHub code scanning, SonarQube) can group related runs.Phase 2 — strict mode + thresholds
New file:
scripts/exit_policy.py—ExitDecisiondataclass +evaluate_exit_policy()implementing:--strict→ threshold = low (any finding fails)--error→ threshold = high--severity-threshold <level>→ explicit--max-findings N→ cap (0 = no cap)sys.exit; the existingcodelens.pyexit-on-gate-failed dispatcher handles it via thegatefield.Modified:
scripts/commands/check.py—--strict/--error/--severity-thresholdflags wired in. When none of the new flags are set, the legacy--severity/--max-findings/--health-mingate runs unchanged (backward-compat for existing CI configs).Acceptance criteria
Phase 1+2 subset:
codelens check --baseline-commit <SHA>reports only new findingscodelens check --strict --errorexits non-zero on any high-severity findingautomationDetails.guidemitted when--baseline-commitis set--diff-scan/--staged/--diff-vsnarrow to git-changed filesPhase 3+ acceptance criteria (out of scope):
codelens ciauto-detects GitHub Actions and uploads SARIF — Phase 3 (separate PR)codelens install-cigenerates workflow file — Phase 3 (separate PR)Tests
tests/test_baseline_diff.pytests/test_exit_policy.pytests/test_git_integration.pytests/test_check_ci_flags.pycodelens checkwith new flags, real git repos, SARIF guid emissionTest results
The 4 pre-existing failures are unrelated to this PR (verified via
git stash+ rerun on unmodified main):test_codelensignore::test_actual_target_dir_is_ignoredtest_universal_grammar_loader::test_auto_installs_when_env_var_settest_universal_grammar_loader::test_returns_language_after_successful_installtest_universal_grammar_loader::test_available_languages_returns_listAll four fail identically on unmodified
main(caused by missing optionaltree_sitterdependency and an unrelatedtarget/ignore-rule quirk).Design notes
(rule_id, file, line, severity). This means parser updates that change message wording or shift a column by 1–2 chars will NOT re-flag the same issue as "new" against the baseline..codelens/baseline_<SHA>.json. Human-readable JSON so they can be committed to a repo or attached as CI artifacts. The SHA in the filename makes it easy to find the right baseline for a given PR base.$CODELENS_BASELINE_SHAenv var. Phase 3 (codelens cicommand) will set this automatically from the PR base SHA. For now users can set it manually in their CI workflow.sys.exitside effect. This makes it trivially testable and reusable by Phase 3'scodelens ciorchestrator.codelens checkwith none of the new flags behaves identically to before (legacy severity/max-findings gate runs unchanged).