Repository navigation
feat(fix-path): direct upgrades name the command that keeps how they are declared (E8, C2); security placeholders hold for any advisory (L4); H2 vectors - #972
Merged
Conversation
runyourempire
added a commit
that referenced
this pull request
Oct 16, 2026
… the manifest declares, from its own source - S4: the declared spec (npm, Cargo), go.mod requirement or == pin must admit the INSTALLED copy before any fix is named; otherwise the row is about another copy than this manifest declares. - B1 PyPI: only the version token after == changes; extras, environment markers and comments stay. Hashed pins (\, --hash on the line or the next) and pip-compile output name nothing. - B2 Cargo: a git, path or alternate-registry dependency names nothing (cargo add <crate>@<v> re-points it at crates.io). - S1: a holding placeholder is only npm's own 0.0.<n>-security shape; a publisher's 1.0.0-security prerelease stays affected (ho-006). - S2: cargo --target is double-quoted. Live through cmd.exe 2026-10-17: single quotes failed to parse as a cfg expression. - S3: a yarn workspace member names nothing (yarn up / upgrade rewrite every workspace); the root itself still does. - S5: direct_fixes / direct_fix_note move into osv/direct_upgrade.rs (upgrade_plan.rs 981 -> 920 lines); the inline-table reader is its own DeclFields. - N1: every direct vector carries its own source, saying whether it was a tool run (and which version) or a rule; fc-043 pins the instruction text, and the runner checks command and instruction through direct_fix on a project built from the vector. - N2: a Go module under a replace directive names nothing. - New vectors fc-046..fc-053, ho-006. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH
runyourempire
force-pushed
the
fix/c2-direct-upgrade-commands
branch
from
October 16, 2026 23:19
d556211 to
46e4d3e
Compare
runyourempire
enabled auto-merge
October 16, 2026 23:22
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 16, 2026
runyourempire
added a commit
that referenced
this pull request
Oct 17, 2026
…68 (#972 holds ft-065/066) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7
This was referenced Oct 17, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Oct 17, 2026
runyourempire
added a commit
that referenced
this pull request
Oct 17, 2026
…68 (#972 holds ft-065/066) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hjX3pEMmC7CHfG41PiPj7
runyourempire
added a commit
that referenced
this pull request
Oct 17, 2026
… the manifest declares, from its own source - S4: the declared spec (npm, Cargo), go.mod requirement or == pin must admit the INSTALLED copy before any fix is named; otherwise the row is about another copy than this manifest declares. - B1 PyPI: only the version token after == changes; extras, environment markers and comments stay. Hashed pins (\, --hash on the line or the next) and pip-compile output name nothing. - B2 Cargo: a git, path or alternate-registry dependency names nothing (cargo add <crate>@<v> re-points it at crates.io). - S1: a holding placeholder is only npm's own 0.0.<n>-security shape; a publisher's 1.0.0-security prerelease stays affected (ho-006). - S2: cargo --target is double-quoted. Live through cmd.exe 2026-10-17: single quotes failed to parse as a cfg expression. - S3: a yarn workspace member names nothing (yarn up / upgrade rewrite every workspace); the root itself still does. - S5: direct_fixes / direct_fix_note move into osv/direct_upgrade.rs (upgrade_plan.rs 981 -> 920 lines); the inline-table reader is its own DeclFields. - N1: every direct vector carries its own source, saying whether it was a tool run (and which version) or a rule; fc-043 pins the instruction text, and the runner checks command and instruction through direct_fix on a project built from the vector. - N2: a Go module under a replace directive names nothing. - New vectors fc-046..fc-053, ho-006. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH
runyourempire
force-pushed
the
fix/c2-direct-upgrade-commands
branch
from
October 17, 2026 15:03
46e4d3e to
cf8c922
Compare
runyourempire
added a commit
that referenced
this pull request
Oct 17, 2026
…ercased finding path Findings carry project paths lowercased (normalize_project_path). That still opens on Windows and macOS, but on a case-sensitive filesystem `/home/runner/work/4DA/4DA/...` lowercased does not exist, so every manifest read failed and the direct row named no command. The merge-queue run of #972 caught it on Linux; locally the end-to-end test never ran (its `c2-e2e-` tempdir prefix tripped the scaffolding exclusion and it printed SKIPPED). - fix_path::on_disk resolves each missing component case-insensitively against its parent's entries; two entries that differ only by case resolve to nothing. - direct_fix and Manager::detect (the transitive refresh commands) read through it, so Linux users get the same commands Windows users do. - The end-to-end test's tempdir prefix no longer reads as scaffolding: it runs (no SKIPPED line with --nocapture). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH
runyourempire
enabled auto-merge
October 17, 2026 15:03
runyourempire
added a commit
that referenced
this pull request
Oct 17, 2026
… the manifest declares, from its own source - S4: the declared spec (npm, Cargo), go.mod requirement or == pin must admit the INSTALLED copy before any fix is named; otherwise the row is about another copy than this manifest declares. - B1 PyPI: only the version token after == changes; extras, environment markers and comments stay. Hashed pins (\, --hash on the line or the next) and pip-compile output name nothing. - B2 Cargo: a git, path or alternate-registry dependency names nothing (cargo add <crate>@<v> re-points it at crates.io). - S1: a holding placeholder is only npm's own 0.0.<n>-security shape; a publisher's 1.0.0-security prerelease stays affected (ho-006). - S2: cargo --target is double-quoted. Live through cmd.exe 2026-10-17: single quotes failed to parse as a cfg expression. - S3: a yarn workspace member names nothing (yarn up / upgrade rewrite every workspace); the root itself still does. - S5: direct_fixes / direct_fix_note move into osv/direct_upgrade.rs (upgrade_plan.rs 981 -> 920 lines); the inline-table reader is its own DeclFields. - N1: every direct vector carries its own source, saying whether it was a tool run (and which version) or a rule; fc-043 pins the instruction text, and the runner checks command and instruction through direct_fix on a project built from the vector. - N2: a Go module under a replace directive names nothing. - New vectors fc-046..fc-053, ho-006. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH
runyourempire
added a commit
that referenced
this pull request
Oct 17, 2026
…ercased finding path Findings carry project paths lowercased (normalize_project_path). That still opens on Windows and macOS, but on a case-sensitive filesystem `/home/runner/work/4DA/4DA/...` lowercased does not exist, so every manifest read failed and the direct row named no command. The merge-queue run of #972 caught it on Linux; locally the end-to-end test never ran (its `c2-e2e-` tempdir prefix tripped the scaffolding exclusion and it printed SKIPPED). - fix_path::on_disk resolves each missing component case-insensitively against its parent's entries; two entries that differ only by case resolve to nothing. - direct_fix and Manager::detect (the transitive refresh commands) read through it, so Linux users get the same commands Windows users do. - The end-to-end test's tempdir prefix no longer reads as scaffolding: it runs (no SKIPPED line with --nocapture). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH
runyourempire
force-pushed
the
fix/c2-direct-upgrade-commands
branch
from
October 17, 2026 15:56
cf8c922 to
ee8cc21
Compare
…are declared (audit E8, C2); npm security placeholders hold for any advisory id (L4) E8, direct half: an Upgrade Plan row for a declared dependency now names how to move it, read from the declaring project's own manifest (osv::direct_upgrade). Before, it said only "Fixable now via a direct dependency bump". Each command was run against the tool on 2026-10-15/16, and several naive forms rewrote the declaration: - npm: `npm install x@v` wrote ^v over an exact pin and over ~. Now --save-exact for an exact pin, and the declared operator otherwise. - yarn 1 `upgrade` and yarn 4 `up` wrote an exact pin over ^ and ~ unless the operator is passed. pnpm `up` keeps the style either way. - Specs carrying ^ are quoted, because ^ is cmd.exe's escape character. - cargo `add`: --dev / --build / --target / --rename follow the declaring table, and the = / ~ operator is kept. On a `workspace = true` dependency, cargo add replaced the inheritance with a local pin, so that case gets an instruction to bump [workspace.dependencies] instead. - go: `go get mod@vX` for a direct requirement. - PyPI: an exact edit of a requirements.txt `==` line (pip install changes only the environment). - Anything uncertain names nothing: a dependency declared twice; git, path or workspace: specs; >= and || ranges. The rule is pinned in fix_command vectors fc-028..fc-045 (`kind: "direct"`). L4 (decision recorded by recovery-lead, 2026-10-16): npm's `*-security` holding placeholder has no code, so no advisory applies to it, whichever database's id flags the name. The predicate drops its `MAL-` condition in fourda-depengine, so both engines and the wasm build agree. - crossenv@0.0.2-security under GHSA-c2m4-w5hm-vqjw read as installed malware. - New shared vectors: holding.jsonl ho-001..ho-005. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH
…low two-part bounds (readiness audit H2) version_order vo-086..vo-091 and fix_target ft-065 (symfony/process v5.1.0 -> v5.4.51) and ft-066 (rack 2.0.6 -> 2.2.23 on the pinned records). The truth comes from the ecosystems' own implementations, run in docker on 2026-10-17: composer/semver and PHP version_compare, and Gem::Version. The fix_target lines use live OSV querybatch per published release, restricted to the pinned ids. The Packagist 6.4.0/6.4 pair is deliberately unpinned, because composer/semver's normaliser and comparator disagree on it. The app engine already passes; the @4da/mcp-server TS engine did not (it sent symfony/process to 8.0.5 and rack to 3.2.6). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH
… the manifest declares, from its own source - S4: the declared spec (npm, Cargo), go.mod requirement or == pin must admit the INSTALLED copy before any fix is named; otherwise the row is about another copy than this manifest declares. - B1 PyPI: only the version token after == changes; extras, environment markers and comments stay. Hashed pins (\, --hash on the line or the next) and pip-compile output name nothing. - B2 Cargo: a git, path or alternate-registry dependency names nothing (cargo add <crate>@<v> re-points it at crates.io). - S1: a holding placeholder is only npm's own 0.0.<n>-security shape; a publisher's 1.0.0-security prerelease stays affected (ho-006). - S2: cargo --target is double-quoted. Live through cmd.exe 2026-10-17: single quotes failed to parse as a cfg expression. - S3: a yarn workspace member names nothing (yarn up / upgrade rewrite every workspace); the root itself still does. - S5: direct_fixes / direct_fix_note move into osv/direct_upgrade.rs (upgrade_plan.rs 981 -> 920 lines); the inline-table reader is its own DeclFields. - N1: every direct vector carries its own source, saying whether it was a tool run (and which version) or a rule; fc-043 pins the instruction text, and the runner checks command and instruction through direct_fix on a project built from the vector. - N2: a Go module under a replace directive names nothing. - New vectors fc-046..fc-053, ho-006. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH
…ercased finding path Findings carry project paths lowercased (normalize_project_path). That still opens on Windows and macOS, but on a case-sensitive filesystem `/home/runner/work/4DA/4DA/...` lowercased does not exist, so every manifest read failed and the direct row named no command. The merge-queue run of #972 caught it on Linux; locally the end-to-end test never ran (its `c2-e2e-` tempdir prefix tripped the scaffolding exclusion and it printed SKIPPED). - fix_path::on_disk resolves each missing component case-insensitively against its parent's entries; two entries that differ only by case resolve to nothing. - direct_fix and Manager::detect (the transitive refresh commands) read through it, so Linux users get the same commands Windows users do. - The end-to-end test's tempdir prefix no longer reads as scaffolding: it runs (no SKIPPED line with --nocapture). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH
runyourempire
force-pushed
the
fix/c2-direct-upgrade-commands
branch
from
October 17, 2026 16:42
ee8cc21 to
6ba7691
Compare
This was referenced Oct 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
This finishes audit finding E8, the direct-dependency half. The transitive half was #962.
An Upgrade Plan row for a declared dependency said only "Fixable now via a direct dependency bump". It now names how to move it, read from the declaring project's own manifest (
osv::direct_upgrade).The PR also carries two decisions recorded by recovery-lead and the shared vectors for readiness finding H2.
Every command was run against the tool (2026-10-15/16)
Several naive forms would have rewritten the declaration:
1.2.5npm install x@1.2.8^1.2.8npm install x@1.2.8 --save-exact~2.1.1npm install ms@2.1.3^2.1.3npm install "ms@~2.1.3"~2.1.1yarn upgrade ms@2.1.32.1.3yarn upgrade "ms@~2.1.3"^1.2.5yarn up minimist@1.2.81.2.8yarn up "minimist@^1.2.8"pnpm up x@vpnpm upwith the operator (pnpm addat a workspace root needs-w)cargo add x@v[dependencies]entrycargo add x@v --dev(also--build,--target "<cfg>",--rename <key>)=/~pincargo add x@vcargo add "x@=v"/"x@~v"x.workspace = truecargo add x@v[workspace.dependencies]in the rootgo get mod@vX(not for// indirect)requirements.txt==pip installchanges only the env^is cmd.exe's escape character.workspace:or alias spec; a>=/||range; a yarn workspace member; a Goreplace; a hashed or pip-compiled requirements file; an unknown tool.Pinned by
fix_commandvectors fc-028..fc-053 (kind: "direct", withdeclared,manifest,go_modorrequirements). The runner builds a project from each vector and callsdirect_fixitself, checkingcommandandinstruction.Review fixes (recovery-lead's REQUEST CHANGES, 2026-10-17)
requirement_admits), the Cargo requirement (Requirement::cargo), thego.modrequire version or the==pin must admit the installed version. Otherwise the row is about a different copy than the one this manifest declares, so nothing is named. A workspace-inherited crate is judged at the root and still gets its instruction.direct_fixnow takesinstalled. Tests:a_declaration_that_does_not_admit_the_installed_copy_names_nothingand the Go/PyPI cases. Vectors: fc-046 (npm~1.2.5vs installed 0.0.8) and fc-047 (Cargo~1.0.5vs 0.4.8).==and the first;, whitespace,\or#is replaced, so extras, markers and comments stay. A line ending in\, carrying--hash, or followed by a--hashline names nothing, because--require-hasheswould fail. pip-compile output also names nothing: edit the.infile instead (N2). Vectors fc-050..fc-052.git,pathandregistryare tracked inCargoDecl::other_source, and those name nothing. Vector fc-048.0.0.<n>-securitycounts as a holding placeholder. Vector ho-006. The TS mirror lands with the MCP integration PR.--target "cfg(...)"uses double quotes. I re-ran it through cmd.exe today: with single quotes cargo failed (failed to parse `'cfg(windows)'` as a cfg expression); with double quotes it moved winapi to 0.3.9. fc-040's source records this.yarn.lockis not in the project's own directory.yarn upandyarn upgraderesolve across every workspace and would rewrite siblings' declarations. The workspace root still gets its command. Test:a_yarn_workspace_member_names_nothing. Vector fc-053 (member: true).direct_fixesanddirect_fix_notemoved intoosv/direct_upgrade.rs;upgrade_plan.rsis 981 → 920 lines. The inline-table/field reader is nowDeclFields, socargo_declarationsonly walks lines.source: the tool and version it was run with plus what that run did, or "Rule, not a tool run" for declines. fc-043 pins the instruction text.replace(single-line or block) names nothing. Vector fc-049.L4 (recovery-lead's decision, 2026-10-16)
npm's
*-securityholding placeholder has no code, so no advisory applies to it, whatever database's id flags the name.MAL-ids were held. crossenv0.0.2-securityunder GHSA-c2m4-w5hm-vqjw ("crossenv is malware", introduced 0, last_affected 1.0.1) read as installed malware.fourda_depengine::matching::is_npm_security_holding(ecosystem, version)drops the id condition, so the app, the crate and the wasm build agree. It matches only npm's own placeholder shape0.0.<n>-security; a publisher's1.0.0-securityprerelease stays affected.holding.jsonl(ho-001..ho-006).H2 shared vectors (readiness audit of @4da/mcp-server 6.2.5)
The TS engine couldn't order a two-part OSV bound like
6.4. It sent symfony/process 5.1.0 to 8.0.5 and rack 2.0.6 to 3.2.6.version_compare(composer:2), and Gem::Version (ruby 3.3), run in docker.6.4.0/6.4is deliberately unpinned: composer/semver's normaliser says equal and its comparator says greater.Not here
FixPath::Bump): the variant is shared with morning_audit/morning_floor. Recovery-lead cleared that for a follow-up PR from me.UpgradeStep(the MCP work-order envelope): unchanged, so no schema bump. The command is in the item text.Checks
osv::andevidence::upgrade, including the vector gate and the end-to-end plan testa_direct_row_names_the_command_for_its_declarationon a real project dir (tilde kept). depenginecargo testpasses.cargo clippy --locked -- -D warnings, native and wasm32;cargo test. (--all-targetsreports lints in existing test files that this PR doesn't touch:osv.rs,version_order_tests.rs,tests/version_order_vectors.rs.)cargo clippy --locked -- -D warningsand rustfmt are clean; the vector gate holds with the new lines.🤖 Generated with Claude Code
https://claude.ai/code/session_015KSXWNneouUjTiVV3Rc3FH