Skip to content

fix(coverage): reconcile contradictory LCOV opener counts - #538

Open
seonghobae wants to merge 45 commits into
mainfrom
fix/contradictory-zero-count-records
Open

seonghobae wants to merge 45 commits into
mainfrom
fix/contradictory-zero-count-records

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Main-target successor authority

This PR is the protected-main successor carrying #523's foundation/lifecycle delta, #526's rustls >=0.23.45 advisory repair, #538's denominator-preserving LCOV reconciliation, and the current CodeQL-required workflow repair through ordinary-forward history.

Current exact head: f335624cea977fea7d7fe6f36871868557fe2bb7. Protected base remains main@a243f18da4a4ca8a8d068c39922537f1f8ed6ad0.

Inherited repairs

#594 CodeQL Actions RED → causal repair

Canonical .github dispatch run 35276762974 for required CodeQL run 35045658451 produced two actions/cache-poisoning/poisonable-step findings in .github/workflows/hourly-nim-product-development.yml. Both findings are in the package_product_increment verifier after the immutable generated proposal has been applied. The verifier then restored ~/.cargo/bin with actions/cache@v5; on a miss, the post action could persist bytes mutated while release-quality gates execute proposal code under static default-branch cache keys.

Ordinary-forward RED af3e0bc5dcbf4d5248ca5ace862680b09378dca8, corrected without removing the RED at 24241780ee791d4811e06b9ec1dc3a04556836c3, adds tests/quality/test_hourly_nim_cache_boundary.py. It requires the verifier to contain no actions/cache@ and to retain pinned direct installs of cargo-nextest 0.9.140, cargo-deny 0.19.7, and cargo-llvm-cov 0.8.6.

Causal repair f335624cea977fea7d7fe6f36871868557fe2bb7 removes the two writable cache actions and their cache-hit branches, and installs the same pinned tools directly before any proposal code is executed. The immutable artifact/patch identity checks, exact-base checkout, credential stripping, Python/Rust/rustdoc/dependency/coverage gates, and separate late publication boundary remain unchanged. No CodeQL suppression, SARIF-gate weakening, cache-rule exclusion, force push, or destructive rebase is used.

The same central dispatch also showed a separate Python-shard failure at Verify GHAS base/head CodeQL configuration identity; Python SARIF itself had zero findings. That remains an independent GHAS configuration-identity prerequisite and is not claimed fixed by #594.

Promotion boundary

This exact head must reacquire all evidence before merge: denominator-preserving authored line/branch 100%, repository/Python branch 100%, Live PostgreSQL, rustfmt/Clippy/tests/rustdoc, dependency policy free of RUSTSEC-2026-0285, Documentation Quality, Security Scan, Semgrep, exact-head CodeQL with the two Actions cache-poisoning findings removed, organization-required workflows, resolved valid findings, and qualifying independent approval.

Issue #498 remains fail-closed because repository Dependency Graph support is an administrator-owned prerequisite. Predecessor PRs #523 and #526 stay open until normal #538 landing or separately verified complete inheritance. No bypass, self-approval, advisory suppression, predecessor-head evidence transfer, destructive rebase, or force push is permitted.

Summary by CodeRabbit

  • 보안 업데이트

    • TLS 핸드셰이크 취약점 해결을 위해 보안 라이브러리를 업데이트했습니다.
  • CI 개선

    • 초안 상태의 풀 리퀘스트에서는 일부 검증 작업이 실행되지 않아 불필요한 대기와 리소스 사용을 줄입니다.
    • 풀 리퀘스트 상태 변경 이벤트에 맞춰 필요한 검증이 실행됩니다.
  • 품질 개선

    • Rust 코드의 주석, 문자열, match 구문을 포함한 커버리지 계산의 정확도를 높였습니다.
  • 문서

    • 시간별 제품 개발 작업의 실행 방식과 대기열 동작에 대한 안내를 최신화했습니다.

seonghobae and others added 22 commits September 15, 2026 02:59
PR #490 removed the local `schedule` trigger from the hourly
contextual-orchestrator workflow so the organisation `.github`
development coordinator owns the cadence, but the contract test still
required `cron: "47 * * * *"`. The shared Python branch-coverage job has
been failing on main since that merge.

The test now asserts the absence of any local `schedule` trigger instead
of a cron expression, and the runbook describes central admission rather
than minute 47.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A draft pull request iterating rapidly cancels and re-enqueues the two
repository-local workflows on every push. Measured on 2026-09-14 at
19:07Z, all 90 cancelled runs among the 100 most recently completed runs
belonged to one draft branch, against 10 successful and 2 failed runs.
Queued work was spread evenly at nine runs per branch, so the queue
itself was fair; the churn was one branch cancelling and replacing its
own runs faster than they could finish.

Both workflows now guard every job on the pull request not being a draft,
and `ci.yml` adds `ready_for_review` to its trigger types so the gates it
skipped run in full the moment a draft is marked ready. No gate is
removed and no gate is weakened: a draft cannot merge, and a job skipped
by `if` satisfies a required check.

The paired contract test asserts the guard appears once per job in each
workflow, so a future job cannot be added without it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The draft guard in this branch covers exploratory iteration on drafts. It
cannot cover a pull request that is ready for review, where cancelling a
superseded run is correct behaviour and the waste comes from push cadence
rather than CI configuration.

Records the remaining half as a contract: while the queue is behind, an
intermediate head cannot merge, so the runner time its cancelled run
consumed is taken from work that can.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The batching contract as written could be read as a reason to delay a fix
for a failing required check. That inverts the intent: batching exists
because an intermediate head cannot merge, so a commit that changes what
the queue can merge must not be held back.

Names the three cases explicitly, following the same exemptions a peer
session recorded for contextual-orchestrator.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`is_executable_source_line` excluded any line that is only a string
literal, to drop formatting noise from the authored-line denominator. A
Rust match arm whose entire body is one literal has exactly that shape,
so every such arm was invisible to the line-coverage gate and a zero
count for it could never fail the contract.

Four arms in `psychometric_core`'s error Display had never been executed.
The gate reported PASS at 11141/11141 over the same LCOV report that
contained their zero counts.

The exclusion now yields when the previous meaningful line ends the arm
pattern with `=>` or `=> {`, which distinguishes an arm body from a
literal continuing an ordinary binding. Comment lines between the pattern
and the body are skipped.

Adds the four missing Display assertions so the newly counted arms are
covered, and two checker tests pinning both directions of the narrowed
rule.

With the narrowed rule the authored-line denominator grows from 11141 to
11360. It fails at 11356/11360 on the report taken before the Display
tests, and passes at 11360/11360 after them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`Ok(())` on its own line was listed with structural punctuation such as
`});` and `};` and dropped from the authored-line denominator. It is not
punctuation: it is the success path of a fallible function, and a zero
count on it means that function never succeeded under test.

Removing it from the exclusion set adds 148 lines to the workspace
denominator, all of them already covered, so this is a regression guard
rather than a repair. The gate reports 11507/11507 where it previously
reported 11360/11360.

The existing noise-filter fixture used that line as its example of a
structural record; it now asserts the opposite, which also restores
coverage of the two checker branches that fixture was the only caller of.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Preserve #523 queue-control work while inheriting #525's valid coverage-gate delta through an ordinary two-parent merge. The inherited change makes standalone string match-arm bodies and Ok(()) success returns count as executable authored production lines, adds the corresponding checker regressions, and covers the four MANIFESTVARstd Display arms that the corrected denominator exposes.

No force update, no denominator weakening, and no predecessor check transfer.
RED contracts for the two current review findings on #523: both repository-local PR workflows must subscribe to converted_to_draft so an in-flight ready run can be cancelled, and authored-line coverage must retain match-arm string bodies after one-line or multiline Rust block comments.

No implementation change in this commit.
…nt arm bodies

Repair both current #523 review findings after the RED contracts in 4279910. Repository-local PR workflows now subscribe to converted_to_draft so the PR-scoped concurrency group cancels an in-flight ready run when the PR returns to draft. The authored-line classifier now skips standalone one-line and multiline Rust block comments while walking backward from a string-literal match-arm body, including the LCOV denominator path.

Keep the fix narrow: no gate weakening, no coverage exclusion, and no runner bypass.
RED for the current #523 review finding. A match-arm label with a trailing Rust line comment must still make its standalone string body executable for authored-line and LCOV denominator accounting, including a string-pattern URL containing `//`.

No classifier implementation change in this commit.
`cargo deny check` fails on main. RUSTSEC-2026-0285
(GHSA-2mjx-qc3c-rqvc, CVE-2025-61730) reports that rustls accepted TLS
1.3 handshake messages across encryption level boundaries, and the
workspace pinned `rustls = "=0.23.43"`, below the fixed `0.23.45`.

The pin reaches the dependency graph twice, directly through
`service_tls` and transitively through `sqlx-core` under
`persistence_postgres`, so the whole workspace carried the vulnerable
version. Because the requirement is an exact pin, `cargo update -p
rustls` could not move it; the manifest had to change.

This is a patch-level move within 0.23 and touches only the pin and the
lockfile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The block-comment handling added for #523's review findings left the
Python gate at 99%: four statements and three partial branches in
`_is_match_arm_body` had no test.

Four fixtures reach them: a blank line between the arm label and its
literal body, a multi-line comment whose opener owns its line, a trailing
`/* note */` on the arm label, and a multi-line comment opened by the arm
label itself.

One branch could not be reached. A line starting with `/*` is consumed by
the earlier guard, so the text before the opener in the combined
`/* ... */` case is never empty and its emptiness check was dead. Removed,
with the reason recorded where it stood.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tract' into fix/rustls-tls-handshake-advisory
My earlier commit on this branch added a `## [Unreleased]` heading above
`## [0.2.0]` without noticing the file already had one below it, leaving
two sections with the same name.

The advisory entry moves into the existing Unreleased `### Security`
subsection and the duplicate heading is gone.

The pre-existing ordering, where `[0.2.0]` sits above `[Unreleased]`,
is left alone. Keep a Changelog puts Unreleased first, so that is a real
defect, but it belongs with GAP-014's remaining CHANGELOG work rather
than a security-fix branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Preserve the rustls 0.23.45 security delta while inheriting #523's ordinary non-force successor history for #517/#525 and the current authored-coverage repairs. The merged tree is #52307b5dc0 plus only #526's Cargo.toml, Cargo.lock, and CHANGELOG.md delta.
Restore the stacked parent's root CHANGELOG entry and preserve #526's
security release note as a CHANGELOG.d fragment, matching the repository's
existing non-force conflict-disposition pattern.

The fragment records only RUSTSEC-2026-0285 / GHSA-2mjx-qc3c-rqvc as the
rustls advisory identity and explicitly distinguishes CVE-2025-61730 as
the functionally similar Go crypto/tls issue. This removes the incorrect
rustls CVE attribution from the tree without discarding the security note.
`main` fails its own line-coverage gate at 11140/11141. The single missing
line is `persistence_postgres/src/migration.rs:140`, and the record is
impossible: line 140 opens an `if` whose body on line 141 reports two
executions, so the condition cannot have run zero times.

Nothing in the source is uncovered. The counter is wrong, and the gate
counts it as a production gap, so every branch based on `main` inherits a
failing job regardless of content.

`drop_contradictory_zero_counts` removes a zero count when the line opens
a brace-delimited block and the first line inside it carries a positive
count. That pairing is a logical contradiction, so the zero cannot be
evidence of uncovered behavior.

The rule is deliberately narrow. A zero whose body also reports zero is a
real gap and is kept. A zero on a line that opens no block is kept. A zero
with no measured line beneath it is kept. Tests pin all three, so the
exclusion cannot widen into hiding genuine gaps.

With it, plain `main` reports PASS at 11140/11140.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 7881c7d9-cb9a-4b86-b213-80eb5defaf69

📥 Commits

Reviewing files that changed from the base of the PR and between 680790b and f335624.

📒 Files selected for processing (5)
  • .github/workflows/hourly-nim-product-development.yml
  • scripts/check_coverage.py
  • tests/quality/test_check_coverage_block_comment_line_comment_trivia.py
  • tests/quality/test_check_coverage_contradictory_zero.py
  • tests/quality/test_hourly_nim_cache_boundary.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

CI의 pull request 이벤트와 draft 실행 조건을 조정했습니다. Rust 커버리지 판정과 LCOV 집계를 수정했습니다. rustls 버전, 시간별 운영 방식, 오류 메시지 테스트를 갱신했습니다.

Changes

CI 큐 제어

Layer / File(s) Summary
Pull request 이벤트 및 draft 조건
.github/workflows/ci.yml, .github/workflows/docs-quality.yml, tests/quality/test_workflow_queue_hygiene.py
Pull request 트리거를 지정된 이벤트로 제한했습니다. draft pull request에서는 관련 작업을 건너뜁니다. ready_for_reviewconverted_to_draft 이벤트를 검증합니다.

Rust 커버리지 집계

Layer / File(s) Summary
실행 가능 라인 판정
scripts/check_coverage.py, tests/quality/test_check_coverage.py, tests/quality/test_check_coverage_block_comments.py, tests/quality/test_check_coverage_match_arm_line_comments.py, tests/quality/test_check_coverage_block_comment_line_comment_trivia.py
match arm의 문자열 본문과 Ok(()) 성공 반환을 실행 가능 라인으로 판정합니다. 주석과 문자열 내부의 //를 구분합니다.
LCOV 0 hit 조정
scripts/check_coverage.py, tests/quality/test_check_coverage_block_comments.py, tests/quality/test_check_coverage_contradictory_zero.py, tests/quality/test_check_coverage_block_comment_line_comment_trivia.py
블록 시작 라인의 0 hit가 후속 의미 있는 라인의 양수 hit와 모순되면 covered로 조정합니다. 블록 주석, 빈 줄, 잘못된 입력 및 블록 경계를 검증합니다.

rustls 보안 업데이트

Layer / File(s) Summary
rustls 버전 고정 및 기록
Cargo.toml, CHANGELOG.d/rustls-tls-handshake-advisory.md
rustls 고정 버전을 0.23.43에서 0.23.45로 변경했습니다. 관련 보안 권고를 변경 로그에 기록했습니다.

시간별 NIM 운영 방식

Layer / File(s) Summary
중앙 dispatch 수용과 도구 설치
docs/operations/HOURLY_NIM_PRODUCT_DEVELOPMENT.md, .github/workflows/hourly-nim-product-development.yml, tests/quality/test_hourly_nim_product_development.py, tests/quality/test_hourly_workflow_triggers.py, tests/quality/test_hourly_nim_cache_boundary.py
로컬 schedule 트리거 설명과 캐시 기반 도구 설치를 제거했습니다. 중앙 workflow_dispatch 수용 방식과 고정 버전 도구 설치를 문서와 테스트에 반영했습니다.

오류 메시지 계약 검증

Layer / File(s) Summary
오류 메시지 안정성 테스트
crates/psychometric_core/src/error.rs
네 가지 표준화된 manifest variance 오류의 표시 문자열을 검증하는 테스트를 추가했습니다.

Priority: ⬆️ High

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix · Severity of issue fixed: High

Possibly related PRs

  • ContextualWisdomLab/TEPP#523: 동일한 Rust coverage 계약과 draft CI guard를 수정하며, 이 PR의 coverage 변경이 해당 구현을 이어갑니다.

Merge Risk: ⚪ Minimal · up to f3356

The reviewed changes include regression coverage for the revised coverage accounting and workflow boundaries. No concrete remaining merge-blocking risk is identified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 70 functions across 11 files. (1 skipped: 1…
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 모순된 LCOV opener count를 조정하는 이번 변경의 핵심 목적을 정확하고 간결하게 설명합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Second independent sample, different author and different subsystem

I said in the description that I had verified the mechanism on main and on one branch, and would not claim the other 17 without evidence. Here is a second sample.

#416 (fix(analysis): exclude future location evidence from historical census) touches analysis_engine, not persistence_postgres. Measuring that crate alone on its head:

Line #416 #326 plain main
138 9 9 9
139 9 9 9
140 0 0 0
141 2 2 2
142 7 7 7

Three trees, two of them other people's work on unrelated subsystems, all showing the identical impossible record. The counts around it match to the digit, which is what you would expect if the artifact is a property of the file and toolchain rather than of any change.

That is now strong enough to say the 18 pull requests failing Production line and branch coverage and nothing else are failing on this, without having measured each one. I have measured three and the mechanism is deterministic.

What it does not change

The fix here is still the narrow rule, not a coverage exemption. A zero count is dropped only when a line strictly inside the block it opens carries a positive count, which cannot both be true. Genuine gaps keep failing, and the four tests pin that in both directions.

Neither branch was modified. Both were fetched read-only into a scratch worktree.

@seonghobae
seonghobae changed the base branch from fix/hourly-central-admission-contract to fix/skip-ci-on-draft-pull-requests September 15, 2026 14:59
@seonghobae
seonghobae marked this pull request as draft September 15, 2026 15:00

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Valid finding, but the current causal repair violates the repository's own coverage-denominator rule. drop_contradictory_zero_counts deletes the authored opener from line_counts, and the claimed result changes 11140/11141 into 11140/11140. The evidence proves the opener's zero count is contradictory because a nested body executed; it does not prove the authored opener ceased to exist. Preserve the denominator and repair the measurement instead: when an executable block opener has count 0 and the immediately nested measured body has a positive count, promote/canonicalize the opener to a positive covered count (or equivalent evidence-preserving representation), so the expected result is 11141/11141, while opener/body both zero, non-block zeros, and unproven cases remain uncovered. Add a regression that asserts both total count and covered count stay 3/3 for the synthetic (2,9),(3,0),(4,2),(6,7) case. Carry this correction only through the #523 successor lineage; the current stale-base synthetic merge ref is not authority.

Copy link
Copy Markdown
Contributor Author

Fresh exact-head settlement on f335624cea977fea7d7fe6f36871868557fe2bb7 materially changes the promotion state but does not authorize merge.

  • Rust Foundation CI 35389817094: SUCCESS.
  • Documentation Quality 35389817160: SUCCESS.
  • SAST Semgrep 35389817177: SUCCESS.
  • Security Scan 35389817143: FAILURE.
  • CodeQL PR 35389817149: still queued.

Security RCA is exact and external to this branch's product/source delta. Dependency-review job 105811205491 acquired a GitHub-hosted runner, verified exact checkout, then the central support probe queried the dependency-graph compare API for protected base a243f18da4a4ca8a8d068c39922537f1f8ed6ad0 → this head and received HTTP 403, curl exit 0. The pinned dependency-review action was skipped because the reusable workflow correctly fails closed when authoritative comparison evidence is unavailable. Scorecard and OSV succeeded in the same Security Scan generation.

Canonical owner paths are TEPP #498 for the repository-specific dependency-graph incident and .github#810 for the fail-closed central contract/configuration incident; both now carry this exact specimen. Do not modify #538 source, create a wake commit, rerun blindly, substitute OSV/Scorecard for Dependency Review, or weaken the gate. #538 still lacks terminal CodeQL, successful Dependency Review evidence, and a qualifying independent current-head approval.

@seonghobae seonghobae added bug Something isn't working priority: high labels Sep 19, 2026 — with ChatGPT Codex Connector
@seonghobae

Copy link
Copy Markdown
Contributor Author

Lead dig (2026-09-19T130411Z) — merge-prep, not hold-and-forget

Owner: @seonghobae (PR author). Diff validated as substantive/valid (coverage LCOV opener reconciliation + rustls advisory + hourly NIM cleanup). Core repo/python/coverage checks are GREEN; 6 RED are bot/advisory/platform — not grounds to abandon.

FAILURE ownership

Gate Class Next
dependency-review HTTP 403 외부차단 Diagnose exact-head evidence; no gate weaken
CodeQL compatibility (py/actions) 외부대기 Ensure terminal CodeQL verdict on f335624…
opencode-review (no verdict on head) 재실행 Wait/re-dispatch; no self-approve
strix exit 2 수리담당 Job-log root cause
noema adversarial-probe validation 수리/검증 Check FP in PR text/diff

Repair worker: Orca ctx_8d05be17f519 (tepp-538-merge-prep).

Independent review: same shared GitHub identity authored this PR → cannot APPROVE own PR. Needs a different identity when gates are green.

Evidence dig: lead worktree TEPP-TRIAGE-DIG-20260919T130411Z.md (also mirrors close/hold classification for the 12 closes / 137 holds from worker PR_TRIAGE.md).

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

Labels

bug Something isn't working priority: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant