Plan skip restoration leaves false-positive findings with stale reopened metadata
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 25/100
Research direction
Start with the reproduction steps, which use only in-memory state: call upsert_issues in desloppify/engine/_state/merge_issues.py, then reconcile_plan_after_scan in desloppify/engine/_plan/scan_issue_reconcile.py, and compare the row's note, reopen_count, and resolution fields. The maintainers have not decided which side owns the fix, so confirm the contract with them before editing. Done means a regression test asserts the agreed terminal fields for a plan-skipped false positive.
Written by the indexing model from the issue text.
Description
Problem
A finding with a durable plan skip --false-positive disposition can be returned by the next scan, briefly reopened by scan merge, and then restored to false_positive during post-scan plan reconciliation. The terminal state can retain the scan's Reopened (×N) note, a higher reopen_count, and null resolved_at/resolution_attestation even though the final status is false_positive and the plan still contains the accepted skip evidence.
This makes the terminal state ambiguous: it looks both accepted and unresolved, and the reopen counter reports churn that was immediately superseded by the durable plan disposition.
Minimal in-memory reproduction
No project files or persisted state are required:
- Create one synthetic
test_coveragework item with statusfalse_positive, a priorresolved_at, and aresolution_attestation. - Add a matching plan entry under
plan["skipped"]with kindfalse_positive, noteaccepted, and attestationreviewed. - Pass the same finding through
engine._state.merge_issues.upsert_issues. - Pass the plan and state through
engine._plan.scan_issue_reconcile.reconcile_plan_after_scan.
Observed after upsert_issues:
status = open
reopen_count = 1
note = "Reopened (×1) — reappeared in scan (was false_positive)"
resolved_at = null
resolution_attestation = null
Observed after reconcile_plan_after_scan:
status = false_positive
reopen_count = 1
note = "Reopened (×1) — reappeared in scan (was false_positive)"
resolved_at = null
resolution_attestation = null
plan["skipped"][id]["kind"] = "false_positive"
plan["skipped"][id]["note"] = "accepted"
plan["skipped"][id]["attestation"] = "reviewed"
Code path
desloppify/engine/_state/merge_issues.py::upsert_issuesincrementsreopen_count, clears resolution metadata, and writes theReopenednote when a previously resolved finding is present in current detector output.desloppify/engine/_plan/scan_issue_reconcile.py::_sync_skipped_issue_statusesrestores an open skipped finding to the skip-kind status by assigningstatusonly.desloppify/app/commands/scan/workflow.pypersists state after scan merge and again after post-scan reporting, so the restored terminal status can be persisted.
Expected behavior / question
Please clarify the supported contract for a durable plan skip:
- If the plan skip is the canonical disposition, should scan merge avoid treating the accepted finding as a user-resolution reopen, or should reconciliation restore coherent state metadata from the plan skip?
- If the reopen event is intentionally retained as history, should it be represented separately so a final
false_positiverow does not carry an unresolved-looking note and null resolution metadata?
A regression test should assert the chosen terminal contract for status, reopen count, note, resolved_at, resolution_attestation, and plan skip evidence.
Related work
- PR836 preserves deliberate skip dispositions across scans and cleans stale queue/cluster references. This report concerns the state-row metadata left after status restoration.
- PR798 persists reconciled scan scores and history. This report concerns per-finding terminal metadata, not score persistence.
- Issue807 tracks conflicting scan scores in one invocation and is related to the pre/post-reconciliation visibility problem.
- Dominant language
- Python
- Stars
- 3.8k
- Forks
- 301
- PR merge metrics
- No merged PRs in 30d
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from peteromallet/desloppify
-
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
peteromallet/desloppify#950 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 79/100
peteromallet/desloppify#947 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
peteromallet/desloppify#946 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
peteromallet/desloppify#942 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
peteromallet/desloppify#936 ·
All issues in peteromallet/desloppify
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
huggingface/deep-rl-class#723 ·
-
[tool] bug: Qwen3 XML tool parser raises on `...` argument values (Ellipsis is not JSON serializable)Possibly taken @super-yuki claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 87/100
verl-project/verl#8559 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
TencentCloud/octop-harness#228 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
google/osv-scalibr#2585 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
NousResearch/hermes-agent#149323 ·
Maintainers usually reply within 1 day