Skip to content

fix: attribute strategist work to scored dimensions - #937

Open
jemoll wants to merge 1 commit into
peteromallet:mainfrom
jemoll:fix/strategist-dimension-attribution
Open

jemoll wants to merge 1 commit into
peteromallet:mainfrom
jemoll:fix/strategist-dimension-attribution

Conversation

@jemoll

@jemoll jemoll commented Oct 31, 2026

Copy link
Copy Markdown

The triage strategist reports zero recent investment for reviewed dimensions when findings store canonical keys such as logic_clarity but scores use labels such as Logic clarity. Mechanical findings usually have no dimension in their detail, so they are also grouped as unknown and lose their investment attribution.

Normalize known subjective keys to the existing display catalog and use the existing detector scoring policy for mechanical findings. Keep explicit custom dimension names and genuinely unknown detectors intact. This changes planner reporting only; it does not change scores, findings, or resolution policy.

Validation: two new regression tests fail before the change and pass afterward; all seven strategist-data tests pass. Read-only validation against a real repository restores both subjective and mechanical investment attribution and reduces unknown backlog classification. Full suite: 5,662 passed, 152 skipped, three Bash unused-import failures; those same three failures reproduce on the unmodified baseline in this environment.

github-actions Bot added a commit to citizenadam/desloppify that referenced this pull request Oct 31, 2026
Dvorinka added a commit to Dvorinka/desloppify that referenced this pull request Nov 2, 2026
…llet#937)

Ported upstream PR peteromallet#937: mechanical findings fall back to the scoring
policy's detector→dimension mapping and detail labels normalize via
DISPLAY_NAMES — same labels as score trajectories. Supersedes the
state-derived map added for peteromallet#900 (canonical source wins).

Authored By: TDvorak <info@tdvorak.dev>
Dvorinka added a commit to Dvorinka/desloppify that referenced this pull request Nov 3, 2026
* docs: PORTS.md — triage upstream issues/PRs with port verdicts

Authored By: TDvorak <info@tdvorak.dev>

* docs: README rewrite — community continuation, repoint links to fork

Authored By: TDvorak <info@tdvorak.dev>

* fix(go): derive unused-import identifiers from package name, not path segment

Port of upstream PR peteromallet/desloppify#703 (issue #640). Go's
in-code package identifier comes from the dependency's package clause,
which frequently differs from the last import-path segment (versioned
modules like .../v8, gopkg.in-style yaml.v3, hyphenated repos). The
generic path-segment heuristic flagged plainly-used imports as unused.

- skip Go blank (_) and dot (.) imports entirely — never 'unused'
- resolve versioned path segments (.../v2, pkg.v3) to the real segment
- return None (no finding) when the identifier can't be determined —
  a false negative is cheaper than a false positive

Authored By: TDvorak <info@tdvorak.dev>

* fix(security): gate hardcoded_secret_name on the literal's value

The detector fired on any variable/field with a secret-sounding name
regardless of the assigned value, flagging translation strings and
field-name constants (upstream #544, #842, #885 class). Add a value
gate: known secret formats (AWS/GitHub/JWT/...) always fire; everything
else must be >= 12 chars and >= 3.0 bits/char entropy, and
identifier-shaped camelCase constants like "clientSecret" are never
secrets.

Authored By: TDvorak <info@tdvorak.dev>

* fix(ts): skip safe innerHTML/dangerouslySetInnerHTML uses

The security detector flagged every dangerouslySetInnerHTML and
.innerHTML occurrence, including sanitized content, in-file static
markup (local SVG constants), and '' clears. Add _html_sink_is_safe:
skip comment lines, sanitizer-wrapped operands (DOMPurify.sanitize,
sanitizeHtml, xss, ...), quoted literals without ${ interpolation,
and identifiers defined in-file as pure literals.

Authored By: TDvorak <info@tdvorak.dev>

* fix(scan): merge results under state_lock — concurrent writes no longer clobbered

Scan loaded state at command start and saved the mutated in-memory copy
at merge time, so any concurrent command's write in between was lost
(e.g. two scans on the same language, or a resolve during a scan —
upstream #254 class). merge_scan_results and persist_reminder_history
now run under state_lock: state is reloaded from disk under the lock,
the scan delta is merged into that fresh state, and saved on release.
Scan-prep mutations (lang_capabilities, review_cache, subjective
resets) are carried over explicitly.

Also sync desloppify/data/global/SKILL.md with docs/SKILL.md (bundled
copy guard).

Authored By: TDvorak <info@tdvorak.dev>

* fix(review,reporting): stop threatening resets the disabled policy can't perform

Upstream #923: _apply_subjective_integrity_policy is disabled (blind
reviews cannot anchor to the target), yet the review importer warned of
an impending reset-to-0.0 and the scan reporter kept emitting the
at-target gaming notice. Both now honor subjective_integrity.status —
'disabled' means no reset can happen, so no warning is printed. Also
documents the attested-external requirements (attest phrases, claude
blind provenance, literal dimension keys) and the triage report
contract (literal issue IDs, Coverage Ledger) in SKILL.md.

Authored By: TDvorak <info@tdvorak.dev>

* feat(scan): add --rescan — sanctioned mid-cycle rescan

The queue gate blocked every mid-cycle scan behind a 130-char
attestation (upstream #563; also unblocks #787, #856-class flows).
Mid-cycle plan reconciliation already preserves clusters, queue state,
and the plan baseline, so the only real blocker was the gate itself.
--rescan bypasses it without --attest and skips nothing else — no
synthetic-item removal, no baseline refresh, no boundary reconcile.
The gate message now points at --rescan as the light path; --force-rescan
remains for intentional cycle resets.

Authored By: TDvorak <info@tdvorak.dev>

* fix(scan): default scan path falls back to project root when src/ absent

Auto-detect always resolved <root>/src and failed on monorepo/flat
layouts (upstream #934 class). get_default_scan_path now returns the
project root when the language's default source dir does not exist.

Authored By: TDvorak <info@tdvorak.dev>

* feat(scan): --diff PR review mode + reusable action.yml

desloppify-as-PR-reviewer: 'scan --diff <base>' resolves base...HEAD
changed line ranges, maps open findings onto them (file-level findings
on changed files included), prints annotations + strict-score delta,
emits GHA ::warning commands, and can write --annotations-json for CI
consumers. Purely mechanical — no LLM.

Ships action.yml (composite action: install -> scan --diff -> optional
sticky PR comment) and examples/pr-review.yml demonstrating the wiring
including an optional score-regression gate.

Authored By: TDvorak <info@tdvorak.dev>

* docs: CHANGELOG — honest delta vs upstream v1.0

Authored By: TDvorak <info@tdvorak.dev>

* test: align default-path tests with src/ fallback contract

Authored By: TDvorak <info@tdvorak.dev>

* docs: fill ported-commit hashes in PORTS.md

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #620 — fix: security (bandit) detector ignores config-level exclude

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #699 — fix: recognize sourced bash library usage in unused-import d

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #762 — fix: honour config excludes in bandit, detect module-install

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #802 — Fix exact issue ID precedence over prefix matching

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #852 — fix: ignore future-only Python facade imports

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #860 — fix(cxx): avoid security findings from parser and unused-sym

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #861 — fix: recognize compiled C++ translation units as build roots

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #864 — fix: use C++ header dialect and surface cppcheck analysis li

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #868 — fix: return nonzero status for invalid show usage

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #874 — fix: retain JavaScript dependency edges for relative paths a

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #875 — fix: ignore overlapping source spans in duplicate matching

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #890 — fix: resolve C# dependencies precisely and preserve iterator

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #911 — fix: run generic autofix tools and report per file

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #914 — fix: keep excluded and git-ignored paths out of findings

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #924 — fix: resolve TypeScript aliases against each importer config

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #925 — fix: resolve test coverage aliases from importer tsconfig

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #633 — fix(go): credit package-level test coverage instead of name-

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #710 — fix(java): use PMD -f text instead of unparseable textcolor

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #712 — fix: scale and correct Rust coverage mapping

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #713 — fix: harden TypeScript project and async detection

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #739 — fix: resolve JVM imports in Gradle/Maven module source roots

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #741 — fix(rust): respect member and nested-worktree scan boundarie

Authored By: TDvorak <info@tdvorak.dev>

* fix(jvm): add src/main/kotlin to fallback source roots

Upstream PR #739 discovers Gradle/Maven roots but its fallback list
carried app/src/main/kotlin without the scan-root twin.

Authored By: TDvorak <info@tdvorak.dev>

* docs: record port outcomes in PORTS.md

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #920 — resolve JS import edges across scan root

Three-way merge: took the _canonical normalizer over #874's
absolute_to_file — handles relative, absolute, and scan-relative
paths in one namespace.

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #904 — absolute paths from collect_exclude_dirs

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #897 — resolve relative scan roots before tool exclusions

Superseded in the shared hunk by #904's absolute-pattern handling.

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #889 — external scanner exclusions to absolute paths

Merged: kept #904's superset impl + both tests.

Authored By: TDvorak <info@tdvorak.dev>

* docs: mark resolved three-way ports DONE in PORTS.md

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #926 — recognize Next.js entrypoints in nested packages

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #735 — stop reporting reachable C# code as unreachable

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #722 — bound Rust coverage dependency resolution

Merged: kept both adjacent test additions.

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #721 — harden TypeScript scanning and plan resolution

Merged: kept #924/#925's per-importer _find_nearest_tsconfig and
reinstated the project_root binding the new code requires.

Authored By: TDvorak <info@tdvorak.dev>

* docs: mark 926/735/722/721 DONE in PORTS.md

Authored By: TDvorak <info@tdvorak.dev>

* docs: HANDOFF.md — continuation guide for next agent

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #723 — cppcheck include-path harvesting

Hand-merged onto the fork's per-language batching and analysis-notice
classification: keep the {id} template and C/C++ batch split, add -I args
harvested from header parents + compile_commands.json, stricter cppcheck
flags, and drop header "is never used" diagnostics.

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #862 — cxx header deps traversed transitively

Hand-merged: keep the fork's malformed-entry guard and TU is_entry_point
marking, add the per-include-context pending expansion so headers pulled
in via compile_commands.json contribute their own include edges.

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #869 — cxx unused-function reconciled across batches

Batch-local cppcheck unusedFunction claims are unproven; a whole-program
pass via a generated compile_commands.json now verifies them. Hand-merged
onto the include-args batch runner and the analysis-notice classification.

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #899 — cxx false API matches + security fallback

New cppcheck_diagnostics gate turns configuration/parse failures into a
tool_configuration error so the regex security fallback and coverage
accounting activate. Kept the fork's escaped-identifier API matching.

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #901 — cxx response-file + transitive header includes

Compiler @file response files now expand in _parse_command_tokens (cycle
and depth guarded). Kept the #862 traversal with its include_specs cache
in place of the visited_by_context variant — same per-context semantics.

Authored By: TDvorak <info@tdvorak.dev>

* port: upstream PR #910 — cxx compilation languages in AST analysis

Adopts the shared compile_commands.py loader and per-file grammar
selection (C_SPEC for .c, CPP_SPEC otherwise). Hand-merge preserves the
fork's additions: response-file expansion moved into
load_compile_commands, empty-command guard, TU is_entry_point marking,
and the #862 transitive per-context include traversal.

Authored By: TDvorak <info@tdvorak.dev>

* docs: mark cxx-family PENDING ports DONE in PORTS.md, changelog entries

Authored By: TDvorak <info@tdvorak.dev>

* fix: python unused detector surfaces missing ruff/pyflakes (#853)

sys.executable -m ruff exits 1 with empty stdout when the module is
absent, which read as a clean zero-finding run and bypassed the pyflakes
fallback. Module availability is now checked up front; when neither tool
exists the phase reports reduced coverage instead of a clean pass.

Authored By: TDvorak <info@tdvorak.dev>

* fix: lru_cache_mutable skips immutable constructor globals (#854)

re.compile, frozenset, tuple, and MappingProxyType over a fresh immutable
literal no longer mark a module global as mutable. Proxies over named
mappings and unknown calls remain conservatively mutable.

Authored By: TDvorak <info@tdvorak.dev>

* fix: python orphan + import resolution conventions (#770/#769/#746/#678/#849/#915)

- Absolute imports resolve against the importer's directory (nested
  packages under script dirs) and <root>/src (src layout).
- Files with a __main__ guard count as entry points via a language hook.
- Django (urls*/admin/apps/middleware/models/tasks/templatetags/...) and
  Alembic (env.py, versions/*) runtime modules are convention entries,
  detected from manage.py / alembic.ini respectively.
- find_python_dynamic_imports uses the exclusion-aware file finder.

Authored By: TDvorak <info@tdvorak.dev>

* fix: python extractor ignores defs inside string fixtures (#772)

Regex-based def matching picked up function-shaped text in multiline
strings; real FunctionDef lines from the AST now gate which matches are
extracted, with fallback to the old behavior for unparseable files.

Authored By: TDvorak <info@tdvorak.dev>

* fix: mixin contract resolves methods through explicit bases (#847)

self.<method>() calls satisfied by the class itself or by in-project base
classes no longer count as undeclared host attributes.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS.md ledger + changelog for python/orphan batch; handoff refresh

Authored By: TDvorak <info@tdvorak.dev>

* fix: props detector ignores multiline type fragments (#838)

Count only property-member lines at interface depth 1 — member name
followed by :, ?, (, or < — and skip lines inside unclosed parens or
brackets. Union/intersection alternatives and call/tuple continuations
no longer inflate prop_count.

Authored By: TDvorak <info@tdvorak.dev>

* fix: sort_no_comparator skips string-keyed Object sources (#811)

Object.keys/entries/getOwnPropertyNames return strings, so the default
UTF-16 sort is the intended canonical ordering — not a missing numeric
comparator.

Authored By: TDvorak <info@tdvorak.dev>

* fix: move rewrites imports with explicit TS extensions (#927)

Replacement search now matches every spelling a specifier can take —
extensionless, explicit .ts/.tsx/.js/.jsx, and index-module forms —
and rewrites it to the equivalent spelling at the destination. A bare
`./x.ts` is never rewritten for an index-module move, since it names a
sibling file.

Authored By: TDvorak <info@tdvorak.dev>

* fix: TS resolvers follow linked workspace package exports (#933)

Bare specifiers that no tsconfig alias claims now resolve through
node_modules: linked workspace packages exposing TS source via
package.json exports (subpath, conditional, wildcard) map to their in-
scan targets in both the dependency graph and coverage import mapping.
Targets resolving outside the scan root stay out of the graph.

Authored By: TDvorak <info@tdvorak.dev>

* fix: run ESLint directly when installed Next.js is 16+ (#709)

`next lint` was removed in Next.js 16 — the tool phase would fail or
report nothing on newer apps. ToolIntegration gains a cmd_resolver hook;
the Next.js spec resolves the installed next major from node_modules and
swaps to `npx --no-install eslint --format json .` (same output shape
parse_next_lint already consumes). Nested packages find hoisted installs
via parent-dir walk.

Authored By: TDvorak <info@tdvorak.dev>

* fix(go): golangci-lint v2 flag, flat-dir test exclusion, receiver-scoped methods (#887, #643, #641)

- #887: golangci-lint v2 removed --out-format; make_tool_phase gains a
  cmd_fn hook and the Go spec resolves the installed major via
  `golangci-lint version` (v2 -> `--output.json.path stdout`).
- #643: *_test.go colocated by Go convention no longer counts toward
  flat-directory overload (flat_dirs_filter hook on the shared phase).
- #641: methods extract as pkg.Recv.Name; signature variance no longer
  merges unrelated receivers across packages.
- #642 verified already fixed: map_test_to_sources maps tests
  package-wide (3bac86a3).

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — go batch done (#887/#643/#642/#641)

Authored By: TDvorak <info@tdvorak.dev>

* fix(csharp): FQ refs + property-receiver edges, unknown harness quality (#683/#893/#892)

- #683: parse_file_symbols also yields PascalCase qualified refs;
  build_dep_graph resolves the longest namespace prefix declaring the
  next segment, so `Ns.Type.Member()` needs no using to create an edge.
- #893: parse_member_bindings binds `var s = new Store()` + `s.Items.X()`
  through Store.Items's declared type -> direct edge on Inventory.cs
  instead of transitive_only. Lexical, collisions over-link.
- #892: test files with assertion-shaped calls but no recognized test
  functions classify as "unknown" rather than "no_tests"; C#
  ASSERT_PATTERNS gains X.That(/Expect( spellings. Unknown emits no
  quality issue — it just stops claiming absence.
- #726/#683 cycle side verified already mitigated by #890's
  referenced-symbol gating (namespace co-membership requires identifiers).

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — csharp batch done

Authored By: TDvorak <info@tdvorak.dev>

* fix(rust): multiline attrs in metadata walk, Cargo target entry roots (#824/#756)

- #824: _preceding_metadata now walks up through the tail of a multiline
  attribute to its `#[` opener instead of stopping at the `)]` line, so
  `#[non_exhaustive]` above a multiline derive is no longer hidden.
  _preceding_attributes keeps continuation lines (excludes doc comments).
- #756: _cargo_target_paths collects [[bin]]/[lib]/[[test]]/[[example]]/
  [[bench]] `path` entries per Cargo.toml; the orphaned detector treats
  them as entry roots in both scan and `detect orphaned` paths
  (entry_patterns_fn hook on make_cmd_orphaned).

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — rust batch done

Authored By: TDvorak <info@tdvorak.dev>

* fix: cxx keywords/owner/param normalization, header-impl coverage, shellcheck per-file (#903/#866/#873/#806)

- #903: language keywords (if/else/for/...) can no longer extract as
  function names; `A::EndPlay` keeps its owner qualifier; params
  normalize to canonical types (const/by-value/name don't change it).
- #866: promote_owner_covered_files promotes a covered header's
  same-stem implementation file (widget.h -> widget.cpp).
- #873: verified already fixed — overlapping source spans are skipped
  in all three dup-pair paths (4fa23bba, upstream #875).
- #806: shellcheck runs one file per invocation via -print0/-0/-n 1 —
  multi-file invocation crashes silently on some platforms.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — cxx/bash batch done

Authored By: TDvorak <info@tdvorak.dev>

* fix(security): log_sensitive needs a payload, json_parse accepts validators (#786)

- log_sensitive: strip static string text before matching; a sensitive
  noun inside a literal ("Obtaining auth tokens…") is not leaked data.
  Template ${…} and f-string {…} interpolations count as payloads; a
  sensitive label plus a real argument still flags.
- json_parse_unguarded: schema.validate/parse/safeParse wrapping
  JSON.parse is a validated boundary — fail-loud is intended behavior.

Authored By: TDvorak <info@tdvorak.dev>

* docs: ledger #786 + handoff refresh for session II

Authored By: TDvorak <info@tdvorak.dev>

* feat: --max-regression score gate for scan --diff + action input (W2)

- scan --diff BASE --max-regression N exits 3 when the strict score
  drops >N vs the stored baseline — the missing gate half of the PR
  review mode (annotations + delta already existed).
- action.yml: fail-on-regression input passes it through; example
  workflow at .github/workflows/desloppify-pr-review.example.yml.

Authored By: TDvorak <info@tdvorak.dev>

* fix(python): runpy.run_path targets count as test imports (#814)

parse_test_import_specs emits .py string literals inside runpy.run_path
calls; resolve_import_spec resolves file-path specs by basename, suffix,
or test-sibling path before falling back to dotted modules. Hyphenated
script names that can't be imported normally now map correctly.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #814 done

Authored By: TDvorak <info@tdvorak.dev>

* fix(ts): coverage resolver parity for ~/ and .js specifiers (#858)

The dep-graph resolver and the coverage resolver diverged on two
specifier forms, so directly-imported/rendered components could be
reported transitive_only/untested:

- `~/x` bare specifiers resolved via the src/ convention only when no
  tsconfig existed; with a tsconfig lacking `~/*` (babel/Metro alias
  projects) both resolvers missed the edge. `~/` now joins `@/` in the
  shared tsconfig-paths fallback; declared mappings still win.
- NodeNext `./x.js` specifiers resolved to .ts/.tsx stems in the dep
  graph but not in coverage's resolve_import_spec, which now shares
  iter_resolve_candidates.

The original memo-ri repro is unrecoverable (repo deleted); this closes
the proven resolver-parity gap matching the reported signature
(directly-imported components, importer_count stuck at 1).

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #858 done
Authored By: TDvorak <info@tdvorak.dev>

* fix(python): scan-root import mapping + windows graph path separators (#907)

Two coverage-mapping gaps for tests living outside the scanned root:

- resolve_import_spec now falls back to an unambiguous suffix match, so
  `from routes.math_ops import x` resolves `service/routes/math_ops.py`
  when service/ is the import root. Same-named modules across parallel
  services stay honestly unresolved.
- _normalize_graph_paths and the extra-test-file path conversion now
  normalize backslashes to forward slashes, matching zone-map keys on
  Windows.

Also corrects the coverage phase summary label: potential is a
sqrt(LOC)-weighted sum, not a production-file count.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #907 done
Authored By: TDvorak <info@tdvorak.dev>

* fix(python): importlib file-load paths count as test imports (#905)

spec_from_file_location / SourceFileLoader / imp.load_source carry the
target as a .py literal inside the call — same treatment as
runpy.run_path (#814). Hyphenated CLI modules loaded explicitly by
importlib now map as directly tested instead of untested_module.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #905 done
Authored By: TDvorak <info@tdvorak.dev>

* fix(python): dict_keys provenance for escape, class scope, and conditional writes (#801, #846)

Five false-positive classes in DictKeyVisitor:

- self.x dicts registered only inside __init__/setUp, so dicts created in
  ordinary methods were analyzed before sibling methods consumed them.
  They now live at class scope and are analyzed once per class.
- Dicts passed through call boundaries or rebound to non-literal values
  produced phantom_read claims; both now mark provenance as unknown.
- Writes inside if/else, loops, try, and match bodies compared as
  sequential overwrites; overwritten_key now requires two unconditional
  writes. Conditional dict-literal creations count as conditional too.
- Whole-dict moves through for-iter containers (tuple aliases) escaped
  via mark_returned_or_passed on the iterable.

Genuine dead_write/phantom_read/overwritten_key findings verified
preserved.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #801/#846 done
Authored By: TDvorak <info@tdvorak.dev>

* fix(python): *_selftest.py files classify as tests and map by convention (#771)

X_selftest.py suites invoked from a module's --selftest entry point were
scored as untested production modules. They now classify Zone.TEST (both
the *_selftest.py suffix and a bare selftest.py basename), and
map_test_to_source/strip_test_markers cover the X_selftest.py -> X.py
naming convention, so a selftest's imports credit the module directly.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #771 done
Authored By: TDvorak <info@tdvorak.dev>

* fix(python): executable in-file --selftest entry points count as coverage (#758)

has_inline_tests now recognizes the --selftest convention: a selftest
check function plus a reachable __main__/argv entry point. A bare
`def selftest` without entry wiring stays honestly untested; def test_*
functions in a __main__-guarded tool file also count.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #758 done
Authored By: TDvorak <info@tdvorak.dev>

* docs: CHANGELOG delta + handoff for session III (detector queue drained)
Authored By: TDvorak <info@tdvorak.dev>

* fix(plan): skip/unskip/backlog exit nonzero on zero-match patterns (#674)

Port upstream PR #706 intent plus the sibling commands: a pattern that
matches nothing now raises CommandError(exit 1) instead of printing a
warning and exiting 0, so scripted triage can distinguish "skipped 12"
from "skipped nothing".

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #674 done
Authored By: TDvorak <info@tdvorak.dev>

* fix(plan): cluster update --depends-on appends instead of replacing (#675)

Repeated --depends-on updates now merge with existing edges (deduped,
order preserved) instead of silently dropping earlier dependencies
(ports upstream PR #708).

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #675 done
Authored By: TDvorak <info@tdvorak.dev>

* fix(plan): resolve exits nonzero on queue-order guard reject (#922)

_check_queue_order_guard rejection now raises CommandError(exit 1)
instead of returning None through _load_state_with_guards, so callers
see a failure rather than a clean no-op. The plan resolve `done` log
entry is also appended only after cmd_resolve succeeds — a rejected
resolution no longer leaves a misleading log entry.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #922 done
Authored By: TDvorak <info@tdvorak.dev>

* docs: handoff — TRACK started (#674/#675/#922 done)
Authored By: TDvorak <info@tdvorak.dev>

* feat(review): --batch-mode grouped|single for run-batches

Subagent review cost scales with batch count: per-dimension mode runs one
agent per dimension (~20 runs). Add --batch-mode to collapse the run:

- grouped: merge dimensions sharing a holistic evidence collector
  (_DIMENSION_FILE_MAPPING) into one batch (~9 runs). Related dimensions
  are assessed together with a shared persona and merged evidence.
- single: merge all selected dimensions into one batch (1 run) — cheapest,
  shallowest.
- per-dimension (default): unchanged.

Merged batches carry unioned dimensions/prompts/files, summed finding
counts, concatenated concern signals, and merged issue-history focus. The
prompt already renders multi-dimension rubrics; wording pluralizes for
multi-dim batches. run_summary.json records batch_mode so --import-run
replays the same grouping.

Authored By: TDvorak <info@tdvorak.dev>

* fix(plan): queue machinery batch — skipped items, backlog dupes, step refs (#906 #919 #928 #929 #930 #931 #701)

- #906: postflight assessment/review partitions now filter plan.skipped —
  a skipped subjective assessment request could select a phase that the
  finalize pass then emptied, leaving `next` reporting 0 items while open
  planned work sat in the backlog.
- #919: resolve queue-order guard mirrors `next` when active_cluster is
  set — filter_cluster_focus instead of no transform — so resolving the
  focused cluster is no longer blocked by synthetic subjective items
  leading the raw queue.
- #928/#929: backlog dedupes by canonical ID — the same finding can
  surface in multiple partitions (e.g. a subjective assessment request as
  both a state work item and a synthetic item), doubling rows and burning
  --count budget.
- #930: plan cluster add refuses skipped issue IDs upfront with a clear
  unskip hint instead of mutating then crashing in validate_plan.
- #931/#701: auto_complete_steps gains an optional state work-item map —
  a step ref is only resolved when absent from the plan AND no open
  finding still matches; absence from queue_order alone is not
  resolution. Both resolve call sites pass state.

Authored By: TDvorak <info@tdvorak.dev>

* fix(next): honor --state when loading the living plan (#780)

`next --state` loaded the issue state for the given path but always read
the default project plan.json, so a state in a sibling directory
(e.g. .desloppify/browser/) showed the wrong plan's queue and frozen
baseline. Route the queue's plan loader through
plan_path_for_state(runtime.state_path), the same sibling mapping scan
and review import already use. `backlog` shared the identical read-path
bug and is fixed the same way.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger + changelog + handoff — TRACK batch II

Authored By: TDvorak <info@tdvorak.dev>

* fix(detect): exclusion-aware language fallback count + wider C# markers (#727)

Auto-detect's marker-less and multi-candidate file counting ignored the
project's configured exclusions, so a repo whose excluded dirs hold many
vendored C/C++ headers detected cxx over csharp — silently invalidating
state and reporting 0.0 for every score. Count only files scan would
actually see (DEFAULT_EXCLUSIONS + configured globs/dirs), and widen C#
detect_markers to .sln/.slnx/.csproj/.fsproj/Directory.Packages.props so
real .NET solutions short-circuit the fallback entirely.

Authored By: TDvorak <info@tdvorak.dev>

* docs: handoff — #727 done, #700 residual noted

Authored By: TDvorak <info@tdvorak.dev>

* fix(plan): clean stale reopen metadata when restoring durable skips (#855)

A scan merge reopens false_positive findings before plan reconcile
restores the skip-kind status, leaving a Reopened note, null
resolved_at/attestation, and a spurious reopen_count bump. Reconcile
now repairs the terminal row from the skip entry so it mirrors the
adjudicated disposition.

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): align staged prompt contract with reflect validator (#784)

Staged observe/reflect prompts embed the generic triage auto-cluster
guidance advertising defer/break_up, while the Backlog Decisions
validator accepts only promote/skip/supersede — runners emitted defer
and failed accounting. Ported upstream PR #637: staged prompts now
omit the legacy auto_cluster_decisions guidance; strategist contract
unchanged.

Authored By: TDvorak <info@tdvorak.dev>

* fix(plan): plan_path_for_state accepts str state paths (#780 follow-up)

CommandRuntime.state_path may arrive as a plain string; coerce via
Path() instead of calling .parent on the raw value. Test stub for
load_plan updated to accept the derived path argument.

Authored By: TDvorak <info@tdvorak.dev>

* fix(scan): zero-reviewable-file policy — warn loudly, no subjective queue (#700)

A misdetected language (Swift/Xcode as TypeScript) or a config-only
package produces a vacuous 100.0 scan plus 20 unfulfillable subjective
review requests. Now the scan warns for ANY zero-reviewable-file run
(not only explicit --lang, and not only zero discovered files), and
build_subjective_items returns nothing when zone_distribution shows
zero production files or codebase_metrics shows zero discovered files.

Authored By: TDvorak <info@tdvorak.dev>

* fix(scoring): exempt tool-verified auto-resolutions from strict (#863)

Ported upstream PR #751: record resolution_kind on auto-resolved
findings — file_deleted and zone_policy are facts the tool establishes
itself, not inferences, and leave nothing a person could attest to
fixed. They no longer pin strict. Inferred resolutions ("absent from
detector output") still fail strict by design — a vanished finding may
be hidden, not fixed (#309 verdict). Historical rows backfill from the
note each branch already wrote. Distinction documented in scoring.md.

Authored By: TDvorak <info@tdvorak.dev>

* docs(skill): document wontfix → assessment-stale contract (#872)

Resolving a subjective review finding as wontfix marks the dimension
stale and queues a re-review even with no source changes — deliberate
per test_resolve_wontfix_review_marks_assessment_stale (re-grounds the
score after disposition; prevents accepting every finding to freeze
it). Now stated honestly in the skill doc instead of "fixed".

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #855 #784 #700 #863 #872 done

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): upsert strategy items instead of erasing lifecycle evidence (#882)

A repeated strategist identifier replaced the whole work-item dict,
losing note, attestation, created_at, and reopen_count. Now the content
fields are refreshed while lifecycle metadata is preserved; a repeated
recommendation on a closed item records a proper reopen transition
(kind=strategist_reopen) instead of silently resetting history.

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): window recent_investment to the score trajectory (#883)

dimension_trajectories windowed strict scores but counted every
retained resolved work item as recent investment — a 2000-era receipt
sat beside a one-scan trajectory. Now only resolutions at/after the
earliest windowed history timestamp count; untimestamped resolutions
are not counted (cannot be shown recent). Unboundable windows (no
timestamps anywhere) keep legacy count-all behavior.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #882 #883 #884 done

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): strategist schema drift — dim mapping, done clusters, step hints (#900 partial)

backlog_by_dimension classified every open item unknown; mechanical
findings now fall back to the detector→dimension wiring in
dimension_scores (also applied to recent_investment and rework loops).
completed_clusters ignored clusters carrying execution_status=done —
they now surface as a fallback. Printed fix hints taught the hidden
legacy --steps flag; they now show --add-step.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS + handoff — session V, #900 partial

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): accept consolidated steps whose issue_refs cover members (#888)

The organize prompt tells runners to consolidate steps by file or
logical change, but unenriched_clusters required >=1 step per issue on
small clusters — runners emitted correct consolidated plans and were
rejected. Coverage via step issue_refs now satisfies the requirement;
uncovered members still trigger the gap with a hint to add refs.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS + handoff — #888 partial

Authored By: TDvorak <info@tdvorak.dev>

* fix(plan): commit records attribute the unique owning cluster (#827)

Commit records always wrote cluster_name=null even when retained
cluster membership uniquely identified the owner, so the strategist
kept asking to restore attribution. Records now carry the single
cluster owning the recorded ids; multi-cluster commits remain
explicitly unassigned rather than guessing one owner.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS + handoff — #827 done

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): resolve summary_hash citations for holistic review ids (#845)

Holistic issue ids carry no hex suffix, so agents citing
detail.summary_hash recorded 0 citations and observe dropped every
per-issue verdict. A summary_hash→id index now feeds citation
counting, YAML verdict parsing, and short-hash resolution —
collision-aware (ambiguous hashes resolve to nothing).

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS + handoff — #845 done

Authored By: TDvorak <info@tdvorak.dev>

* fix(resolve): cluster-name resolution follows member queue policy (#898)

_resolve_target_ids added the cluster token to resolved_ids, so a
cluster spelled by name skipped the persisted-queue fast path and was
judged against the synthetic-laden built queue — blocked even when its
exact members resolved fine. The token now expands to members only;
cluster and member spellings are equivalent.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #898 done

Authored By: TDvorak <info@tdvorak.dev>

* fix(plan): preserve deliberate skip dispositions across scans (#836)

Ported upstream PR #836: permanent/false-positive skips detach from
queue, promoted IDs, cluster members, and step references while
keeping skip evidence, and earlier superseded tombstones no longer
delete a fresh re-skip before status synchronization.

Authored By: TDvorak <info@tdvorak.dev>

* fix(queue): honor queue targets and scope plans to explicit state files (#835)

Ported upstream PR #835: execution/backlog thresholds resolve from the
QueueContext target instead of a hardcoded 100, and commands with an
explicit --state file default their plan path to the sibling
plan.json rather than the root plan.

Authored By: TDvorak <info@tdvorak.dev>

* fix(review): preserve imported state and detector verification scope (#837)

Ported upstream PR #837: the follow-up scan after a review import now
targets the imported state file and runtime project root, and
review-only merges protect detectors outside the merge inventory
instead of stamping absent detectors scan-verified.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #835 #836 #837 done

Authored By: TDvorak <info@tdvorak.dev>

* fix(state): require detector evidence for manual scan verification (#938)

Ported upstream PR #938.

Authored By: TDvorak <info@tdvorak.dev>

* fix(resolve): persist strategy work-item resolution (#879)

Ported upstream PR #879 and completed its queue cleanup: strategy::
patterns route through the canonical resolve path (matching, evidence
validation, persistence) instead of the synthetic purge, and resolved
strategy ids are dropped from queue_order/skipped/clusters —
wildcards included.

Authored By: TDvorak <info@tdvorak.dev>

* fix(review): preserve scan scope through review imports (#857)

Ported upstream PR #857.

Authored By: TDvorak <info@tdvorak.dev>

* fix(review): use configured target in review preflight (#851)

Ported upstream PR #851.

Authored By: TDvorak <info@tdvorak.dev>

* fix(next): distinguish filtered empty views from completed queues (#848)

Ported upstream PR #848.

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): respect frozen review scope in triage collection (#841)

Ported upstream PR #841 plus one completion it needs: an empty
active_triage_issue_ids sentinel now means "no freeze" for coverage
purposes (all live review issues required), while the enrich-stage
cluster scoping keeps its empty-frozen reading.

Authored By: TDvorak <info@tdvorak.dev>

* test: reconcile empty-frozen-scope contract with upstream #841

The pre-port snapshot test asserted empty active_triage_issue_ids
keeps coverage empty; upstream #841's contract is that empty means
"no freeze" — reflect requires every live review issue. Coverage
expands for reflect; cluster scoping keeps the frozen-empty reading.

Authored By: TDvorak <info@tdvorak.dev>

* docs: PORTS ledger — #938 #879 #857 #851 #848 #841 done

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): attribute strategist work to scored dimensions (#937)

Ported upstream PR #937: mechanical findings fall back to the scoring
policy's detector→dimension mapping and detail labels normalize via
DISPLAY_NAMES — same labels as score trajectories. Supersedes the
state-derived map added for #900 (canonical source wins).

Authored By: TDvorak <info@tdvorak.dev>

* fix(review): enforce trusted coverage within selected dimensions (#935)

Ported upstream PR #935. The fork already carried the equivalent
selected-dims filter; merged as comment/naming alignment.

Authored By: TDvorak <info@tdvorak.dev>

* fix(plan): preserve completed findings when deferring a plan cluster (#870)

Ported upstream PR #870: cluster-wide skips act only on actionable
members (open/deferred/synthetic) — fixed and auto_resolved members
keep their resolution history instead of being overwritten.

Authored By: TDvorak <info@tdvorak.dev>

* fix(state): keep unchanged scan corroboration from invalidating reviews (#880)

Ported upstream PR #880.

Authored By: TDvorak <info@tdvorak.dev>

* fix(state): resolve plan override IDs in one canonical batch (#877)

Ported upstream PR #877; restored the fork's fixed→all status filter
upstream's hunk dropped, which is what lets verify-fixed resolution
reach auto_resolved issues.

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): allow consolidated organize steps (#850)

Ported upstream PR #850: unenriched_clusters no longer gates small
clusters on one-step-per-issue — consolidation is permitted and step
detail/issue_refs are validated at the enrich stage. Supersedes the
issue_refs-coverage check added for #888 (upstream's is the canonical
fix for the same defect); printed hints keep the --add-step flag.

Authored By: TDvorak <info@tdvorak.dev>

* fix(review): allow fully covered selected-dimension reviews (#840)

Ported upstream PR #840: the trusted-import coverage gate no-ops when
no dimensions were explicitly selected, and only selected dimensions
count as missing coverage.

Authored By: TDvorak <info@tdvorak.dev>

* fix(queue): honor shared queue context review targets (#891)

Ported upstream PR #891: execution/backlog builders derive the queue
context through one canonical helper — an explicit context stays
authoritative, legacy threshold options still resolve via
resolve_queue_inputs.

Authored By: TDvorak <info@tdvorak.dev>

* fix(scan): scan isolation and review workflow consistency (#844)

Ported upstream PR #844 (3-way merge): shared queue context through
plan queue + resolve guard, skipped subjective candidates filtered
before phase selection, json_parse_unguarded multi-match merge keeping
the schema-validated exemption, weighted coverage summary text.

Authored By: TDvorak <info@tdvorak.dev>

* fix: preserve review freshness and queue prerequisites (#881)

Ported upstream PR #881. Only an active exact-ID canonical false
positive suppresses review freshness; raw reopen counters are kept and
the final canonical reconciliation preserves them. A pre-save plan
reconcile inside the state lock persists dispositions for reopen-cycle
counting, and the merge keeps plan-reconstruction reloads from
outvoting the runtime work rows (FP-only skip restore).

Authored By: TDvorak <info@tdvorak.dev>

* fix(queue): front clustered mechanical work past stale assessment marker (#888)

Second half of upstream #888: in the assessment-postflight phase a stale
subjective marker used to be the whole execution front, so `next`
rendered the collapsed mechanical cluster while `plan resolve` and the
review rerun gate both saw the marker first — each side waited on the
other. When no postflight scan is recorded, the execution partition is
now the cluster-fronted queued work followed by the marker; lone queued
findings stay parked (still resolvable by id via the queue guard's
front-planned branch) and an active postflight scan keeps new execute
work backlog-only.

Authored By: TDvorak <info@tdvorak.dev>

* docs: mark #888 deadlock resolved in port ledger

Authored By: TDvorak <info@tdvorak.dev>

* fix(plan): align strategist work and history with current schemas (#900)

- strategy::* ids name persisted work items, not phase markers. The new
  is_marker_id predicate (triage/workflow/subjective) now drives
  live_planned_queue_ids, live_planned_queue_empty, refresh-lifecycle
  objective detection, supersede reference sets, and force-rescan cycle
  reset — queued strategy work surfaces in `next` instead of "0 items"
  and is no longer silently unqueued. Strategist items get file "." so
  scoped scan paths cannot drop repo-global recommendations.
- Enrichment gates only clusters that can still execute: done clusters
  whose members all stayed resolved are history; a reopened member
  re-gates the cluster.
- Execution-log analysis separates operation counts from issue counts:
  cluster fronts expand to member ids via the plan, globs and marker ids
  never count as issues, and ids dedupe across entries.
- Done-log ordering was already fixed by #922.

Authored By: TDvorak <info@tdvorak.dev>

* docs: mark #900 done in port ledger

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): scope organise validation and structure prompt to live clusters (#825)

The structure sense-check rebuilt its prompt from the raw plan after
content-batch updates, so completed historical clusters re-entered the
file-touch graph and absorbed dependency edges. The reload is now
re-scoped through triage_scoped_plan. The organise stage's cluster
list — which drives both the operation-count minimum and the report
reference check — now comes from scoped_manual_clusters_with_issues, so
done/historical clusters no longer inflate the minimum or satisfy
confirmation.

Authored By: TDvorak <info@tdvorak.dev>

* fix(queue): keep subjective dims visible when covering reviews are masked (#813)

The postflight partition suppressed a subjective dimension item whenever
open review findings covered its dimension — but those findings are
themselves hidden while triage is stale or has never run, so the queue
collapsed to zero items while `plan queue` still listed the queued
subjective ids. Suppression now applies only when the covering review
issues are executable; otherwise the dim item stays as the actionable
front.

Authored By: TDvorak <info@tdvorak.dev>

* docs: mark #825 and #813 done in port ledger

Authored By: TDvorak <info@tdvorak.dev>

* fix(review): bound partial-import resolution to declared dimensions (#830)

A scoped trusted import built its resolution scope from every dimension
discovered inside the runner payload — issue dims and assessment keys —
so a stray dimension widened the scope and auto-resolve closed holistic
findings the packet never covered. ReviewImportConfig now carries
allowed_dimensions (the packet's declared dims for --import-run), and
import_holistic_issues intersects the collected scope with it.

Authored By: TDvorak <info@tdvorak.dev>

* docs: mark #830 done in port ledger

Authored By: TDvorak <info@tdvorak.dev>

* fix(review): refresh blind packet on review --prepare (#826)

`review --prepare` rebuilt the holistic context for query.json but never
rewrote `.desloppify/review_packet_blind.json`, so structure profiles
(directory_profiles, fan-in/out roles) went stale while scan refused
mid-cycle — blind reviews then scored from obsolete layout data. The
prepare path now writes the sanitized blind packet from the fresh
payload; it is derived data and touches no triage or issue state.

Authored By: TDvorak <info@tdvorak.dev>

* docs: mark #826 done in port ledger

Authored By: TDvorak <info@tdvorak.dev>

* fix(kotlin): build import graph from packages; shell tools without login shell (#912, #939)

Ported upstream PR #912: Kotlin dependency graph resolves imports via
package declarations instead of file paths. Ported upstream PR #939:
generic tool commands run with -c instead of -lc so PATH/login-shell
differences stop breaking tool invocation.

Authored By: TDvorak <info@tdvorak.dev>

* docs: note upstream sweep progress in handoff

Authored By: TDvorak <info@tdvorak.dev>

* fix(kotlin): stop flagging used Kotlin imports as unused (#913)

Ported upstream PR #913: wildcard imports are skipped, backtick-escaped
names (Mockito.`when`) resolve to the escaped identifier, and
language-spec implicit_import_uses patterns (Kotlin operator
conventions) act as usage evidence before flagging.

Authored By: TDvorak <info@tdvorak.dev>

* docs: record upstream sweep completion and remaining queue

Authored By: TDvorak <info@tdvorak.dev>

* docs: handoff prompt for next session

* test(typescript): pin JS/.mjs test discovery in coverage phase (#944)

The fork already carries the fix via the #844 port (widened
test_file_extensions + in-scan test dirs searched for non-production
extensions). These production-phase tests lock it in: root and
subdirectory scans across .js/.jsx/.mjs/.cjs, with an unrelated
production module remaining flagged.

Authored By: TDvorak <info@tdvorak.dev>

* fix(autofix): pass scan path through cascade cleanup (#943)

The core no-op was already closed by the #911 port (takes_scan_path
protocol + fail-closed generic fixer), but the cascade unused-import
cleanup still invoked fix() without path — the same omission, now a
crash for generic fixers instead of a silent no-op.

Authored By: TDvorak <info@tdvorak.dev>

* fix(swift): classify SwiftPM Tests/ directories as test zone (#942)

The case-sensitive common /tests/ rule missed SwiftPM's conventional
Tests/<Target>Tests/ layout, scoring test fixtures as production. Adds a
segment-bounded /Tests/ rule ahead of the generic rules — no global
case-folding, so Contests/ and Tests.swift stay production.

Authored By: TDvorak <info@tdvorak.dev>

* fix(jscpd): run adapter isolated from workspace package.json (#941)

npx inherited the scan workspace as cwd, so npm evaluated the project's
devEngines and died with EBADDEVENGINES in pnpm-only workspaces. The
adapter now runs jscpd from the neutral output tempdir with an absolute
scan path; report names also resolve when emitted scan-relative.

Authored By: TDvorak <info@tdvorak.dev>

* fix(lua): treat only require() as import; fix suppress ::rule globs (#940)

LUA_SPEC's import query matched any function_call with a string argument,
so load modes, string.pack formats, assert messages and table keys were
flagged as unused imports — now constrained to require.

Separately, detector::*::rule globs couldn't match issue IDs carrying a
trailing ::line component; the matcher now retries with an implicit ::*
tail, making the documented suppression form work.

Authored By: TDvorak <info@tdvorak.dev>

* fix(review): keep blind review navigation score-free (#908)

Suggested `desloppify show` commands in blind review prompts printed the
AGENT PLAN footer and subjective followup — prior dimension scores —
after the requested mechanical evidence, contaminating the blind review.
Adds `show --blind` to suppress those footers and emits it on every
show-command suggestion in the review prompts.

Authored By: TDvorak <info@tdvorak.dev>

* test(plan): pin --state sibling-plan resolution (#832)

Already fixed via the #835 port (runtime.plan_file wiring); this
regression test locks it in.

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): propagate --lang/--state through runner helper (#823)

run_desloppify.sh baked in the checkout but dropped the invocation's
language and state, so stage-issued commands read the default project
state in mixed-language workspaces.

Authored By: TDvorak <info@tdvorak.dev>

* fix(scan): failed detectors keep potential and mark coverage reduced (#821)

A jscpd failure dropped boilerplate_duplication's scoring potential
while its findings stayed open, crediting an improvement that never
happened. The phase now records reduced detector coverage, and the
scan merge restores the previous potential for detectors that failed
to produce one.

Authored By: TDvorak <info@tdvorak.dev>

* docs: close #815 — isolated by sibling-plan resolution

Authored By: TDvorak <info@tdvorak.dev>

* docs: refresh handoff prompt for session XIII

Authored By: TDvorak <info@tdvorak.dev>

* docs: close #809 — review imports cannot verify or stale mechanical state

Authored By: TDvorak <info@tdvorak.dev>

* docs: close #805 — coverage gate already packet-scoped

Authored By: TDvorak <info@tdvorak.dev>

* fix(cli): apply persisted exclusions before language detection (#785)

State path and default-path resolution ran before set_exclusions while
the scan handler resolved the language after, so exclusions that flip
auto-detection persisted findings to the wrong state-<lang>.json.

Authored By: TDvorak <info@tdvorak.dev>

* fix(scan): history records post-adjudication scores (#759)

scan_history was appended before canonical plan reconciliation restored
skip dispositions, so the recorded entry, printed output, and persisted
top-level scores could all disagree. Recompute stats after in-lock
mutations and rewrite the entry; runtime.state picks up final values.

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): organize stage refusal exits nonzero (#754)

Refused stage recording returned silently with exit 0, so the runner saw
"Organize stage not recorded" only later. Refusals now raise CommandError
(exit 1), matching the plan-resolve/skip guard convention.

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): strategize forwards --attestation to queue guard (#686)

The documented override was dropped before ensure_triage_started, making
the queue-guard attestation path unreachable from manual strategize runs.
Other #686 problems (synthetic-only queue hiding backlog, explicit empty
frozen scope) were already resolved by the #900/#841 work.

Authored By: TDvorak <info@tdvorak.dev>

* docs: close #658/#650 — triage execution handoff already working

Authored By: TDvorak <info@tdvorak.dev>

* fix(cxx): atomic groups bound qualified-name regex backtracking

Port of upstream PRs #729 + #733 (via meta-PR #744): the repeated
qualified-name alternation in _FUNCTION_RE and _FUNC_DECL_RE could
backtrack catastrophically on long `Type::Type::...` chains. Both
patterns now use atomic groups; timing regression tests pin the bound.

Authored By: TDvorak <info@tdvorak.dev>

* docs: record cloudreve closeout and Nothing_Modes progress

Authored By: TDvorak <info@tdvorak.dev>

* docs: record Nothing_Modes closeout — full sweep complete

Authored By: TDvorak <info@tdvorak.dev>

* fix(python): keep Bandit coverage aligned with discovered files

Port of upstream PR #695 (via meta-PR #744): Bandit now runs over the
scanner's discovered file list in batches of 250 instead of a blind
recursive scan, so config-level excludes and partial coverage are
honored. Fatal exits, per-file errors, missing target metrics, and
empty output now report reduced coverage instead of silently passing.
Legacy detect_with_bandit retained for direct callers.

Authored By: TDvorak <info@tdvorak.dev>

* fix(python): separate schema constructor drift contexts (#694)

Port of upstream PR #694 (via meta-PR #744). Dict literals passed to
*Schema constructors declare validation contracts and are no longer
drift-compared against generic runtime payloads. A semantic_corrections
channel carries detector-proven invalidations through LangRuntime into
merge_scan, marking legacy open findings false_positive with a
detector_semantic_correction attestation; reconcile purges them from
uncommitted_issues. Gated to full-scan confirmed detectors only.

Authored By: TDvorak <info@tdvorak.dev>

* fix(python): require pure forwarding shape for passthrough detection

Port of upstream PR #693 (via meta-PR #744): the detector now parses the
AST and only flags undecorated single-return wrappers whose sole
statement calls a lower-case target with every arg forwarded directly.
Decorated entrypoints, multi-step routers, constructor factories, and
constructed call targets are no longer misclassified.

Authored By: TDvorak <info@tdvorak.dev>

* fix(python): ignore duplicate constants in versioned migrations (#691)

Port of upstream PR #691 (via meta-PR #744): alembic/versions and
migrations/versions files are immutable history — their constants must
not feed the cross-file duplicate check.

Authored By: TDvorak <info@tdvorak.dev>

* fix(python): recognize compatibility import entry points (#690)

Port of upstream PR #690 (via meta-PR #744): dynamic-import discovery
now follows `from importlib import import_module` bindings, resolves
lazy-export `__getattr__` mapping targets to their child modules, and
treats explicit `install_legacy_module_alias(__name__, ...)` wrappers as
entry points — keeping those files out of the orphan report.

Authored By: TDvorak <info@tdvorak.dev>

* fix(python): ignore constant-return CLI main guarded by __main__ (#688)

Port of upstream PR #688 (via meta-PR #744): a top-level main() invoked
by an __name__ == "__main__" guard is a legitimate entrypoint, not a
stub — exempt it from the constant_return smell.

Authored By: TDvorak <info@tdvorak.dev>

* fix(python): preserve callable default None providers (#687)

Port of upstream PR #687 (via meta-PR #744): functions used as typed
dataclass callable defaults may legitimately fail closed with
`return None` — the dead-function smell now exempts exactly those
provider pairs, discovered project-wide in a pre-pass; pass and bare
return bodies stay flagged.

Authored By: TDvorak <info@tdvorak.dev>

* docs: record #744 mining progress

Authored By: TDvorak <info@tdvorak.dev>

* docs: overnight autonomous handoff prompt

Authored By: TDvorak <info@tdvorak.dev>

* fix(python): track open dict copy keysets (#673)

Port of upstream PR #673 (via meta-PR #744): dict copies of untracked
sources — dict(src), dict(**src), {**src}, update(src) — now mark their
keyset open, suppressing phantom reads and near-miss typos that cannot
be verified. Aliases share the tracked dict; closed copies preserve the
known keyset. dict()/.copy() calls no longer mark the source escaped.

Authored By: TDvorak <info@tdvorak.dev>

* fix(triage): accept displayed reflect dimension names (#685)

Port of upstream PR #685 (via meta-PR #744): recurring-dimension
mention validation now accepts the catalog display label (e.g.
"High elegance") in addition to the canonical snake_case key.

Authored By: TDvorak <info@tdvorak.dev>

* fix(csharp): link Razor/Blazor views into the dep graph (#682)

Port of upstream PR #682 (via meta-PR #744): .razor/.cshtml views now
contribute graph edges — type/extension references by name, tag-helper
conventions, partial/layout string refs, component refs, and
code-behind partials. Routable pages count as entry points, ambient
_Imports/_ViewImports usings inherit, and razor zone rules classify
view files.

Authored By: TDvorak <info@tdvorak.dev>

* style(csharp): sort razor support imports

Authored By: TDvorak <info@tdvorak.dev>

* fix(orphaned): recognize React Router/Remix route modules (#697)

Port of upstream PR #697 (via meta-PR #744): route modules under
routes/ and the root/entry.client/entry.server conventions are
framework entry points — resolved per-file against the nearest
react-router/remix project root, like the Next.js handling.

Authored By: TDvorak <info@tdvorak.dev>

* fix(cxx): map tested headers to unique same-stem sources (#732)

Port of upstream PR #732 (via meta-PR #744, closed unmerged): test
coverage now resolves header includes through declared-symbol matching
to a unique same-stem implementation, recognizes Catch2 TEST_CASE/
SCENARIO/REQUIRE assertions and Qt CMake target commands, and replaces
the catastrophic testability regex with a line scanner.

Authored By: TDvorak <info@tdvorak.dev>

* docs: refresh overnight handoff prompt after #744 mined

Authored By: TDvorak <info@tdvorak.dev>

* docs: record #744 port candidates landed

Authored By: TDvorak <info@tdvorak.dev>

* fix(detect): local TS cyclomatic ownership + live local-use py enums (#839, #843)

- TS smoke detector: blank nested function/arrow bodies before counting
  branches so complexity stays locally owned; nested callbacks are still
  assessed on themselves.
- Python unused_enums: enum Load uses in its defining module (incl.
  type annotations) keep it alive; self-references inside the enum body
  do not count.
- Ledger: #745 SKIP (codex runner plumbing), #747 DONE (#879 port), both
  fixes with issue-repro regression tests.

Authored By: TDvorak <info@tdvorak.dev>

* ci: stop executing the example consumer workflow on fork PRs

.desloppify-pr-review.example.yml still matched workflows/*.yml, so every
fork PR tried to run it; it references Dvorinka/desloppify@main, which
has no action.yml until PR #1 merges. Rename to .yml.example so GitHub
ignores it — it is documented as a copy-into-your-repo template.

Authored By: TDvorak <info@tdvorak.dev>

* test: repair fixtures after #694/#821/#823/#754 ports

Four long-failing suites predated this sweep (first regression pass they
received): canonical-skip-freshness runtime.lang fixture lacked
semantic_corrections (post-#694 contract); organize undecided-reflect
gate now raises CommandError(1) per #754; codex pipeline helper fake
adapted to the #823 (run_dir, args) signature; boilerplate None fixture
gains detector_coverage and pins the #821 reduced-coverage record on
jscpd loss.

Suite: 6453 passed; only the two known dry-run env failures remain.

Authored By: TDvorak <info@tdvorak.dev>

* docs: record session XV sweep, PR #1 CI fix, suite repairs

Authored By: TDvorak <info@tdvorak.dev>

* fix(scan): guard locked plan load against null state_path (mypy union-attr)

Authored By: TDvorak <info@tdvorak.dev>

* ci: install treesitter extras before test gates

tests-core/tests-full never installed the [treesitter] extra, so
tree-sitter-backed language tests (bash/lua/go unused imports, JS
import graph) ran without the language pack and failed. CI has never
been green on this repo for that reason.

Authored By: TDvorak <info@tdvorak.dev>

* test: force bandit importability miss in bandit-missing fixture

_bandit_available falls back to find_spec (#762 port); the old
shutil.which-only patch left the tests-full CI env (bandit installed)
reporting full coverage and failing the fixture. Patch find_spec too.

Authored By: TDvorak <info@tdvorak.dev>

* docs: record CI near-green closeout

Authored By: TDvorak <info@tdvorak.dev>

* docs: changelog backlog for sessions IX-XV

Record the review-freshness/queue family, the detector/resolver family,
the #744 meta-PR mining results, and the #839/#843 fixes in the fork
delta log (missed since the session III update).

Authored By: TDvorak <info@tdvorak.dev>

* docs: handoff closeout for the changelog backfill

Authored By: TDvorak <info@tdvorak.dev>

* chore(release): cut 1.0.1 for the community fork

- pyproject version 1.0 -> 1.0.1; CHANGELOG section marked released.
- python-publish + tweet-release workflows reduce to manual dispatch:
  the PyPI name and secret bindings belong to upstream, so automated
  publish/tweet from this fork can never succeed; explicit dispatch only.
- Contract test updated to pin the manual-dispatch trigger.

Authored By: TDvorak <info@tdvorak.dev>

* fix(cli): resolve project root for nested explicit state files (#833)

Port of upstream PR #833's remaining piece: explicit --state paths
nested under .desloppify/<lang>/ now infer the project root by walking
parents, matching the plan-routing plumbing already present.

Authored By: TDvorak <info@tdvorak.dev>

* fix(typescript): use actual project configs for unused checks (#834)

Port of upstream PR #834: the unused-symbol check now discovers each
source file's nearest tsconfig (including nested workspace packages and
project references), validates it via tsc --showConfig, and runs the
diagnostic pass per project with --pretty false and a scratch
tsbuildinfo. Unreadable configs raise CommandError instead of silently
falling back.

Authored By: TDvorak <info@tdvorak.dev>

* docs: adjudicate upstream sweep items #833 #834 #939

Authored By: TDvorak <info@tdvorak.dev>

* docs: record session XV — #744 mining complete

Authored By: TDvorak <info@tdvorak.dev>

* docs: mark overnight sweep completed

Authored By: TDvorak <info@tdvorak.dev>

---------

Co-authored-by: TDvorak <info@tdvorak.dev>

This branch has not been deployed

No deployments
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