GeezerVison is showing github.com — v5 design: staged patch rollout (socket.yml + scan limit) by mikolalysenko · Pull Request #290 · SocketDev/socket-patch
Conversation
Design only; no code. This PR adds docs/design/staged-rollout.md, updates docs/design/configuration.md (socket-patch now reads socket.yml for selection policy, with the trust boundary kept), and adds a WS9 entry to docs/design/v5-plan.md.
What the plan proposes
patches: block in socket.yml (version: 2, new top-level key; every existing parser strips or ignores it). Keys: enabled, includePaths, ignorePaths, ecosystems, packages, ignorePackages, minSeverity, maxNewPatches. Paths use the same gitignore semantics as projectIgnorePaths, which scan now also honors.
- Hard-coded filter moves: the in-memory engine's
test/tests/fixtures/__fixtures__/testdata root exclusions become overridable default ignores, applied on disk too. Every other hard-coded skip is safety, entitlement or correctness and stays (inventory in section 2.3, both repos).
scan --max-new-patches <N|none> (and the maxNewPatches key): caps patches added to packages that have none yet. Order: real severity, then advisory count, ecosystem, purl, uuid. Upgrades are exempt. Patches that can't land this run don't hold a slot. Repeated runs converge. Deferred patches are reported in a new rollout JSON block; exit code unchanged.
- Fail closed: an invalid policy stops scan before any write (
socket_yml_invalid, exit 1). Narrowing never removes or upgrades an already-applied patch.
- Two parallel work items: A (policy loading and filters) and B (limit, ordering, reporting), with a frozen interface (section 9.0). Merge order is A then B.
- depscan autopatch follow-up: section 7.
Candidate designs came from three angles (minimal, safety, user journey). Three independent judges scored them, and the result is a synthesis. Section 8 records each decision and why.
🤖 Generated with Claude Code
Generated by Claude Code
Note Low Risk
Documentation-only; no runtime or behavioral changes until follow-up implementation PRs land.
Overview
Design-only — no implementation in this PR. It adds the v5.0 staged rollout spec and aligns configuration docs with that direction.
New: docs/design/staged-rollout.md defines repo-owned gradual patching: a top-level patches: block in socket.yml (under version: 2) for paths, ecosystems, packages, severity floor, enabled, and maxNewPatches; scan --max-new-patches for severity-ordered caps on new patches (upgrades exempt); fail-closed validation; policy / rollout JSON blocks; and two parallel work items (A policy, B limit) with a frozen pipeline contract and depscan follow-ups.
Updated configuration.md: Reverses the v3.5 rule that socket-patch never reads socket.yml — v5 will read projectIgnorePaths plus patches only, with a trust boundary that repo files may narrow or pace but never widen or carry credentials/endpoints. Invalid patches blocks fail scan (exit 1); manifest setup.defaults is dropped from the deferred plan in favor of socket.yml.
Updated v5-plan.md: Adds WS9 (branches v5/rollout-policy / v5/rollout-limit, merge A then B).
Reviewed by Cursor Bugbot for commit c434039. Configure here.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Adds the design for rolling Socket patches out gradually: a
`patches:` block in socket.yml that narrows what scan may patch
(paths, ecosystems, packages, severity floor, on/off), and a
severity-ordered per-run cap on new patches so each scan lands the
next few most critical fixes.
The plan splits the work into two parallel items with a frozen
interface, lists every hard-coded filter and where it belongs, and
covers the depscan autopatch follow-up. configuration.md now records
that socket-patch reads socket.yml for selection policy only, with
the trust boundary unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Three independent reviews (ambiguity, churn, trust boundary) found
gaps that would have let the two implementations disagree or let a
repo file widen or stall the rollout. The plan now:
- matches paths against marker files with the backend's top-down
gitignore rules, so projectIgnorePaths means the same everywhere
- uses one data source for severity, supersession and ordering
- spends the budget only on patches the planning pass proves can
land, and admits nothing new when a lookup failed
- uses the merged recorded view in every mode and engine
- has depscan read the policy from the base commit for PR jobs
- hardens file handling (regular files, aliases, size, encoding,
trusted repo root) and reports what a policy hides
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
A final consistency pass found places where the two work items
would have produced incompatible code: base purls admitted in one
directory being charged again in the next, no defined hand-off of
the unfiltered offers from the severity filter to classification,
no shared repo-relative path helper, and override sources the JSON
must report but the interface could not carry. The shared contract
now defines each of these, and the parity tests match each engine's
budget scope.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
The plan said both that the selector returns the shared offers
struct (work item A) and that it returns admitted/deferred rows
(work item B). The selector now returns the offers, and B adds the
rollout stage after it.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
|
[agent] plan final
Summary. The staged-rollout plan is final at 82f5b00 on v5/staged-rollout-plan: docs/design/staged-rollout.md (full design) and docs/design/configuration.md §4 (socket.yml trust boundary).
- socket.yml: a new top-level
patches: block, kept at version: 2 so every existing parser strips or ignores it. Keys: enabled, includePaths, ignorePaths, ecosystems, packages, ignorePackages, minSeverity, maxNewPatches.
- Paths: matched against project marker files with the backend's gitignore rules, evaluated top-down.
projectIgnorePaths is also honored. The hard-coded test/tests/fixtures/__fixtures__/testdata root exclusions become overridable defaults.
- Validation: strict and fail-closed (
socket_yml_invalid, exit 1). Narrowing never removes or upgrades an applied patch.
scan --max-new-patches <N|none>: caps new patches per run, ordered by severity, then advisory count, ecosystem, purl and uuid. Upgrades are exempt. The budget is spent only on patches the planning pass proves can land. Repeated runs converge. Deferred patches are reported in a new rollout block; the exit code is unchanged.
- Build order: work items A and B are built in parallel against the shared contract below. Merge order is A then B, and B integrates.
- depscan follow-up: §7.3 of the doc.
- Process: three candidate designs were scored by three judges. Three adversarial reviews and one final consistency pass followed, and all their findings are folded in.
Updated at 82f5b00: in-memory path selection is now two-phase (the caller passes the root socket.yml text to selectHostedScanPaths, which applies the full path policy), per the Bugbot finding on §7.2. The work-item specs are otherwise unchanged.
Below are the work-item specs A and B in full (§9, verbatim). The sections they cite (§3–§5 semantics, §7.2 engine API) are normative; read them in docs/design/staged-rollout.md at 82f5b00.
Work items A and B (§9, verbatim)
9.0 Shared contract (frozen by this plan)
Scan pipeline, in order (disk and memory):
- load policy (A); fail closed before any write
- crawl; capture the prune universe (unchanged)
- root filter, ecosystem/package filter, retained set (A)
- batch API, by-package details (unchanged fetches)
- candidate severity filter on by-package records (A);
discover_selected
returns Offers (below) so B sees both the unfiltered and the
floor-filtered candidates
- per-package ranking (unchanged
ranking)
- classify, planning pass for eligibility, budget, deferral (B)
- writers (receive only admitted NEW rows, ALREADY rows with the recorded
uuid, and UPGRADE rows)
// crates/socket-patch-core/src/policy/mod.rs — OWNER A
pub struct SelectionPolicy { /* private fields */ }
pub enum PolicySource { None, File { path: String, sha256: String }, Bypassed }
pub enum FilterReason {
Disabled, PathExcluded { pattern: String, list: &'static str }, PathNotIncluded,
Ecosystem, PackageNotListed, PackageIgnored { spec: String },
Severity { found: Option<String>, floor: String },
}
impl FilterReason { pub fn code(&self) -> &'static str; pub fn detail(&self) -> String; }
pub enum PolicyError {
Invalid { file: String, key: String, message: String },
Ambiguous { files: [String; 2] },
}
impl PolicyError { pub fn code(&self) -> &'static str; } // socket_yml_invalid | socket_yml_ambiguous
pub enum RootFile { Absent, Present(Vec<u8>), PresentWithoutContent }
pub trait PolicyFs { fn read_root_file(&self, name: &str, cap: usize) -> std::io::Result<RootFile>; }
pub enum OverrideSource { Flag, Env }
pub struct PolicyOverrides { pub bypass: bool, pub min_severity: Option<(Option<u8>, OverrideSource)> } // (None, _) = "none"
pub struct PolicyWarning { pub code: &'static str, pub detail: String }
pub struct Root<'a> { pub rel_dir: &'a str, pub markers: &'a [String], pub explicit: bool }
impl SelectionPolicy {
pub fn unrestricted() -> Self; // built-in default ignores only
pub fn load(fs: &dyn PolicyFs, o: &PolicyOverrides) -> Result<(Self, Vec<PolicyWarning>), PolicyError>;
pub fn source(&self) -> &PolicySource;
pub fn enabled(&self) -> bool;
pub fn admits_root(&self, root: &Root) -> Result<(), FilterReason>;
pub fn admits_purl(&self, purl: &str) -> Result<(), FilterReason>; // ecosystem + packages
pub fn admits_severity(&self, severity_order: u8) -> Result<(), FilterReason>;
pub fn max_new_patches(&self) -> Option<u32>; // the file's value; None when source() is None or Bypassed, or the key is absent
}
pub fn package_spec_matches(spec: &str, purl: &str) -> bool; // moved from cli scan/mod.rs:383
pub fn find_repo_root(cwd: &Path) -> PathBuf; // 4.5
pub fn repo_relative(repo_root: &Path, dir: &Path) -> String; // "" for the repo root, `/` separators
// crates/socket-patch-core/src/policy/mod.rs — OWNER A (the step 5 → 7 seam)
pub struct Offers {
pub unfiltered: BTreeMap<String, Vec<PatchSearchResult>>, // purl → every offer (after tier)
pub selected: BTreeMap<String, PatchSearchResult>, // purl → winner among floor-admitted offers
}
// crates/socket-patch-core/src/rollout.rs — OWNER B
pub enum Recorded { None, Same, Kept { uuid: String }, Superseded { old_uuid: String } }
pub struct Candidate {
pub project: String, pub purl: String, pub base_purl: String, pub uuid: String,
pub ecosystem: &'static str, pub severity_order: u8, pub advisory_count: usize,
pub recorded: Recorded, pub eligible: bool, pub in_flight: bool,
}
pub enum MaxNewSource { Flag, Env, File, Default, Cap }
pub struct MaxNew { pub value: Option<u32>, pub source: MaxNewSource }
pub fn resolve_max_new(flag: Option<Option<u32>>, env: Option<Option<u32>>,
file: Option<u32>, cap: Option<u32>) -> MaxNew;
pub fn canonical_base_purl(purl: &str) -> String;
pub fn rollout_cmp(a: &Candidate, b: &Candidate) -> std::cmp::Ordering;
pub struct RolloutCounts { pub new: u32, pub deferred: u32, pub upgrade: u32, pub already: u32 }
pub struct RolloutPlan {
pub admitted: Vec<Candidate>, pub deferred: Vec<(Candidate, u32)>,
pub counts: RolloutCounts,
pub remaining: Option<u32>, // carried to the next directory
pub admitted_base_purls: BTreeSet<String>, // carried too
}
// Rows whose base_purl is in `already_admitted` are admitted without spending budget.
pub fn plan_rollout(candidates: Vec<Candidate>, max_new: &MaxNew, incomplete: bool,
already_admitted: &BTreeSet<String>) -> RolloutPlan; // pure
// crates/socket-patch-core/src/api/ranking.rs — OWNER B (addition)
pub fn search_result_supersedes(candidate: &PatchSearchResult, recorded: &PatchSearchResult) -> bool;
Rules both items follow:
- Severity input is always
max_severity_order over the by-package
record's vulnerabilities, never RankKey.severity, never the batch
list.
- Skip-reason strings are the stable codes in 4.7 and 5.5; warnings go to
scan's top-level warnings[].
- JSON: A owns the top-level
policy block; B owns the top-level
rollout block. Neither edits the other's.
- CLI args: A adds a
#[command(flatten)] SocketYmlArgs
(--no-socket-yml, --min-severity) in scan/socket_yml_args.rs; B
adds a flattened RolloutArgs (--max-new-patches) in
scan/rollout_args.rs. Both derive Default; each adds its field to
the ~18 ScanArgs struct literals. B resolves the adjacent-line
conflicts on rebase.
run_project_dirs changes: A adds the per-directory explicit flag;
B adds the carried remaining budget. B resolves the overlap on rebase.
9.1 Work item A — socket.yml loading and filtering
Scope:
crates/socket-patch-core/src/policy/{mod.rs, socket_yml.rs, paths.rs};
pub mod policy; in crates/socket-patch-core/src/lib.rs; move
package_spec_matches to core (the cli re-uses it).
- Dependencies, exact-pinned in
Cargo.toml: a maintained YAML 1.2 serde
crate that reports duplicate keys and can refuse aliases and bound depth
(e.g. serde_norway; prove each property with a test, pick another
crate otherwise), and ignore (for Gitignore::matched; the top-down
walk is ours). No other new deps.
- Loader: lookup (4.5, incl. ceiling dirs and ownership), regular-file,
size and symlink confinement on the opened handle, exact-name match,
encoding, both-files rule, strict validation with key paths and
did-you-mean (4.4), PolicyFs for disk and memory.
- Path matcher (4.3): marker-file subject, npm-
ignore top-down
semantics, defaults + lists in order, includePaths, pattern hygiene;
golden fixture generated from npm ignore (commit the generator script
under scripts/ and the fixture under crates/socket-patch-core/tests/).
- Filters at the pipeline points in 9.0:
- disk: root filter in
project_dirs / run_project_dirs
(scan/mod.rs:1268-1320, carrying explicit) and the agent project;
admits_purl next to --package (scan/mod.rs:1490-1511); severity
filter on by-package candidates before select_patches
(discover_selected, scan/mod.rs:553, and the human arm,
mod.rs:2386-2402); retained set computed from the recorded view and
excluded from writers.
- memory: full path policy in
selectHostedScanPaths
(hosted_memory/select.rs), from the caller-supplied policyFiles
text (7.2, two-phase); the same root filter in the session before
max_projects (hosted_memory/mod.rs:377); admits_purl at
hosted_memory/mod.rs:428-432; severity filter before
select_top_ranked.
- Move
test tests fixtures __fixtures__ testdata out of
EXCLUDED_ROOT_SEGMENTS (hosted_memory/roots.rs:56-67) into the
built-in default ignores, and apply them to disk PATH-glob expansion.
enabled: false report-only path; get's policy_bypassed warning;
--global ignores the file; PATHs outside the repo root → exit 2.
- Flags:
--no-socket-yml/SOCKET_NO_SOCKET_YML,
--min-severity/SOCKET_MIN_SEVERITY (SocketYmlArgs).
- napi + hosted-bundle (7.2, A rows);
npm/index.d.ts types.
- JSON
policy block (4.7), human policy line (naming suppressed
critical/high), error output with errorCode, warnings
socket_yml_ignored_value, socket_yml_name_case,
socket_yml_repo_untrusted, patches_disabled, policy_bypassed;
output string hygiene.
Tests:
- Unit (core, table-driven): every row of 4.4 in order; the npm-
ignore
golden fixture (anchoring, bare names, trailing /, !, excluded
parents, case); marker rule (all markers ignored / any included);
defaults + negation; explicit vs discovered; package specs incl.
invalid ones; severity floor incl. unknown and moderate; both-files
equal / different / one invalid; lookup with .git dir, .git file,
none, GIT_CEILING_DIRECTORIES, foreign-owned .git; symlink inside
and outside, directory, FIFO; alias bomb; oversize; BOM, CRLF, UTF-16.
- Parser contract:
tests/cli_parse_scan.rs rows for both flags and env
vars (empty = unset, malformed = exit 2).
- E2E (wiremock,
tests/in_process_scan.rs style): hosted, vendored,
agent and --dry-run with a socket.yml filtering by path, ecosystem,
package and severity; invalid file → exit 1, errorCode, no bytes
changed; --no-socket-yml; narrowing after a patch is applied leaves the
pinned package byte-identical in all three modes (retained); a recorded
merged patch below a new floor is kept, not replaced; --prune universe
unchanged; PATH outside the repo → exit 2.
- Parity:
tests/hosted_memory_parity.rs gains a socket.yml fixture
(single-lockfile roots) where disk and memory filter the same roots and
packages; a memory test where the tree lists socket.yml but its content
is withheld → policyError; a memory test where
ignorePaths: ["!/e2e/tests/"] re-includes a default-ignored root, so
its lockfile is selected, fetched and patched as on disk.
- This repo's own
socket.yml keeps working (its projectIgnorePaths
now also excludes the fixtures from patching).
Docs (A): CLI_CONTRACT.md (new "socket.yml patch policy" section:
grammar, precedence, paths, lookup, validation, commands; flag + env rows;
error codes; policy JSON block; the trust-boundary bullet gains the
"narrow or pace" sentence), README (scan section: "Roll out gradually"
with recipes R1-R4, R6), CHANGELOG [Unreleased] (Added: socket.yml
patch policy; Changed (BREAKING): scan honors projectIgnorePaths,
default test/fixture ignores on discovered roots, invalid socket.yml with
a patches block fails scan).
9.2 Work item B — limit, ordering, reporting
Scope:
crates/socket-patch-core/src/rollout.rs; pub mod rollout; in
crates/socket-patch-core/src/lib.rs; search_result_supersedes in
ranking.rs, and detect_updates / updates[] switched to by-package
supersession; move the detect_updates call (today scan/mod.rs:1912,
on batch data) after discover_selected so it receives the by-package
offers.
- Make
discover_selected (scan/mod.rs:553) the single disk selection
point: route the human agent/vendored arm (mod.rs:2386-2402) through
it, and add the step-7 stage after it (classify its Offers, planning
pass, plan_rollout) yielding {admitted, deferred}, so hosted
(run_redirect_selected, hosted.rs:1196), vendored and agent writers
receive only the rows 9.0 step 8 allows (ALREADY with the recorded
uuid). discover_selected's return type is A's Offers.
- Classification from the merged recorded view (5.1); the planning pass
for eligibility (hosted: grants, purl/url, vlt preflight, symlink
refusals, rewriter planning; vendored: preflight; agent: partition);
fetch-all references; rollout_reference_failed and
rollout_incomplete_lookup; plan_rollout; the remaining budget
carried through run_project_dirs in sorted directory order.
- In-memory engine (7.2, B rows): pin discovery and state-file reads,
collect → plan → apply, options and result fields, npm/index.d.ts,
hosted-bundle fields.
- Flag:
--max-new-patches <N|none>/SOCKET_MAX_NEW_PATCHES
(RolloutArgs); resolve_max_new including the file value from A
(9.3).
- JSON
rollout block (5.5), redirect.skipped[] mirror, human
"Rollout:" line and the Next-steps deferred line (hosted
format_next_steps, hosted.rs:3457, and the agent/vendored
summaries).
Tests:
- Unit (core):
rollout_cmp total order (property test: every
permutation sorts the same); plan_rollout caps only eligible NEW,
counts base purls, one package across roots costs 1, 0 = no NEW, none
= unlimited, ineligible rows hold no slot, incomplete admits nothing
NEW, in-flight first, remaining budget; resolve_max_new precedence
table incl. cap on none; canonical_base_purl twins;
search_result_supersedes rungs.
- E2E (wiremock): hosted, vendored, agent,
--dry-run: 9 candidates with
--max-new-patches 3 apply the 3 most severe; a rerun on the result
applies the next 3; a third run the last 3; a fourth changes nothing;
dry-run output equals the wet run's decisions; upgrades land regardless
of the cap; a withdrawn, a bad_purl and a vlt-withheld top-ranked
patch hold no slot; a failed detail lookup with a cap admits nothing
NEW; two PATH directories share one budget in sorted order; JSON
rollout and redirect.skipped[]; exit 0.
- Parity:
hosted_memory_parity.rs single-root cap fixture: disk and
memory admit and defer the same rows. Two-root fixture: assert memory's
run-wide order and disk's per-directory order separately (they differ by
design, 5.2). A memory rerun with pins (and with a committed
manifest / vendor state) lands the next N.
- Parser contract rows for the flag and env var.
Docs (B): CLI_CONTRACT.md (limit semantics: classification,
eligibility, unit, budget scope, order, convergence, version-bump and
twin notes, starvation and non-committing CI; flag + env rows; rollout
block; rollout_deferred; warnings; jq recipe; "Which patch gets
selected" gains the cross-package order and the by-package supersession
change), README (recipe R5, --max-new-patches), CHANGELOG
[Unreleased] Added (and Changed: updates[] uses by-package data).
9.3 Integration (B, after rebasing on A)
- Pass
policy.max_new_patches() as the file layer of resolve_max_new.
- Resolve the
ScanArgs struct-literal and run_project_dirs conflicts.
- Combined e2e: a socket.yml with
includePaths, minSeverity: high and
maxNewPatches: 2 over a two-root fixture, disk and memory, three runs to
convergence, asserting each engine's own budget scope (5.2);
--no-socket-yml drops the file's cap but keeps a flag cap.
- Switch
Candidate.project to A's repo_relative and consume A's
Offers (before A lands, B uses canonical --cwd as the repo root and
treats the selected offers as the unfiltered list).
- If B is ready before A merges, B ships with the file layer passed as
None and wires it in a follow-up commit on its branch once A lands.
Generated by Claude Code
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
[agent] CI note: test (windows-latest) fails on ff7a30a, in the target -p socket-patch-cli --test covgap_commands_scan_mod.
This PR changes only three Markdown files under docs/design/, so it can't cause a Rust test failure. The base branch is already red: CI run 36352437716 on release/v5-prerelease (8ae7dc3, PR #277) also failed test (windows-latest), along with test (ubuntu-latest), test (macos-latest), coverage and test-release.
I don't know of an existing fix to port. I'll re-run the failed job once, after this CI run finishes.
Generated by Claude Code
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
#283 landed on release/v5-prerelease as 06437d2; please merge origin/release/v5-prerelease again, resolve conflicts, get green, and keep it ready.
Generated by Claude Code
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
[agent] test (windows-latest) fails in -p socket-patch-cli --test covgap_commands_scan_mod, on the first run and on its one rerun. This PR changes only docs.
The same target failed on Windows in base PR #283's own last CI run (job 108911094705), and #283 is now in release/v5-prerelease. That makes this a base-branch failure, not one this PR causes. Ubuntu and macOS pass. No fix exists yet.
Generated by Claude Code
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
[agent] ready to land
The plan is final and CI is green except test (windows-latest), which also fails on the base branch (see the comment above). This PR changes only docs.
Generated by Claude Code
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c434039. Configure here.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Bugbot on #290: the plan had the in-memory engine's path selector
apply only the built-in test/fixture ignores, because it runs before
socket.yml is read. A negation such as `!/e2e/tests/` could then
never bring those trees back in depscan, while it works on disk.
Selection is now two-phase: the caller fetches the root policy
file(s) first and passes their text to selectHostedScanPaths, which
applies the full path policy. A listed policy file that is not passed
fails closed. A new memory test covers the negation case.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
|
[agent] Plan amendment for work item A, at 82f5b00. I edited the plan final comment above in place.
In-memory path selection is now two-phase. depscan fetches the root socket.yml/socket.yaml first and passes the text to selectHostedScanPaths in a new option, policyFiles. The selector then applies the full path policy, not just the built-in defaults, so an ignorePaths negation works in memory the same as on disk. A listed policy file that is not passed fails closed with policyError. See §7.2 (A row), §7.3 item 2, and the §9.1 memory bullet and memory test. Work item B is unaffected.
Generated by Claude Code
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Mikola Lysenko (mikolalysenko)
pushed a commit
that referenced
this pull request
Sep 28, 2026
Brings in the squashed staged-rollout plan (#290), the e2e-tier fix
(#288: Windows path separators in a scan test, CI cancel rules) and
the docs-only design PRs. The plan doc's later edits (two-phase
policy selection for the in-memory engine) merge with this branch's
implementation notes unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
|
[agent] Work item B status: #294 (v5: cap new patches per scan, most critical first) is ready to land.
- Implements: §5, §7.2 (B rows), §9.2 and §9.3. There's a per-run cap on new patches, and eligibility is checked before any budget is spent. Deterministic ordering (severity, advisory count, ecosystem, purl, uuid) means repeated scans converge without churn. Upgrades are uncapped, and there are
rollout JSON and human reports. Disk and memory behave the same.
- Wired to A: A's
patches.maxNewPatches sets the file layer. The combined socket.yml + cap e2e (§9.3) passes on disk and in memory.
- Gap decisions: listed in
docs/design/staged-rollout.md §11 and in the v5: cap new patches per scan, most critical first #294 description.
- Integration: merged with the base at 73c0c4f and with A at 4b71112.
- CI: the only red checks are four vlt
install-proof jobs (vlt 0.0.0-1 and 0.0.0-11). They also fail on the base's own run at 28cebf7.
Generated by Claude Code
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
[agent] Work item A (socket.yml patch config and filtering) is ready to land as #293. It targets release/v5-prerelease.
What it adds
crates/socket-patch-core/src/policy/ holds the frozen §9.0 contract:
- a strict parser for the
patches block, covering enabled, includePaths, ignorePaths, ecosystems, packages, ignorePackages, minSeverity, and maxNewPatches (validated here, enforced by B);
- a gitignore-semantics path matcher, pinned by a golden fixture generated from npm
ignore.
- The policy applies across hosted, vendored, agent and
--dry-run scans, and in the in-memory engine through §7.2's two-phase selection.
- The handshake uses
policySha256, so a session that reads a policy different from what selection saw fails closed.
- The test/fixture directory defaults moved out of the in-memory engine's hard-coded list into the policy. They apply to discovered roots only and can be re-included with a negation.
- Flags only narrow further:
--min-severity / SOCKET_MIN_SEVERITY beats the file's floor.
--no-socket-yml / SOCKET_NO_SOCKET_YML ignores the file.
- A broken or ambiguous file fails before any request or write. The error codes are
socket_yml_invalid and socket_yml_ambiguous.
- Narrowing never removes a patch that is already recorded. Such packages are reported in
policy.retained[].
- Trust boundary: nothing in socket.yml can set endpoints, credentials or modes, or turn off safety checks. Keys like that are rejected as unknown.
Decisions where the plan left a gap: recorded in docs/design/staged-rollout.md §9.4, items 1–7. The items B picks up are:
- the in-memory
retained[] view;
search_result_supersedes for the floor-vs-recorded rule;
- README recipes R1/R5.
CI: green except failures the base branch already has:
- vlt
0.0.0-1 / 0.0.0-11: hosted-rollback tests;
yarn-classic 1.0.2 / 1.6.0 / 1.7.0 / 1.9.4: mode_migration_npm expects an integrity line.
No fix exists yet for either.
Generated by Claude Code
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
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.
|