Skip to content

chore(deps): update dependency fallow to v3.34.0 - #955

Open
renovate[bot] wants to merge 1 commit into
masterfrom
renovate/fallow-3.x-lockfile
Open

renovate[bot] wants to merge 1 commit into
masterfrom
renovate/fallow-3.x-lockfile

Conversation

@renovate

@renovate renovate Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
fallow (source) 3.33.1 → 3.34.0 age confidence

Release Notes

fallow-rs/fallow (fallow)

v3.34.0

Compare Source

Added
  • fallow mutation measures how well the tests detect code changes. The
    command makes small changes (mutants) in the changed code and runs the
    tests of the project against each one. A mutant that no test fails
    on survives. The report gives the mutation score over the tested mutants,
    the survivors by file with their covering tests, and the share of mutants
    that a test reaches.

    • --plan selects and ranks the mutants and runs no code.
      fallow mutation inspect <mutant_id> shows one mutant against the current
      file and runs no code. It reads the report that the last run saved in the
      Fallow cache, or the file that --report names. From a subdirectory, it
      finds the report of a run at the project root. A changed file gives a
      stale status.
    • The default scope is the changed code against the base ref, as for
      audit. --all and file paths widen or narrow it.
    • A survived or timed-out mutant runs once more in a new companion, so
      host load alone does not make a mutant count as detected. The retry of
      a timeout waits twice as long. A changed detection result is flaky
      and leaves the score.
      retried: true on a mutant marks a status from both runs.
    • --setup-timeout sets how long each runner process can take to start,
      finish its dry run or reload (default 2m).
    • A run refuses a dirty git worktree unless --allow-dirty is set. Mutants
      near file system, process, network or database calls are pruned unless
      --allow-side-effects is set. Fallow does not write to project files, and
      the report lists any path that the tests changed. -o <file> writes the
      report after the run, and the worktree check leaves that file out.
    • The exit code is 0 by default. --min-score or mutation.minScore makes a
      lower score exit with 1. --verdicts <file> marks equivalent mutants,
      which leave the score.
    • The coverage counts the mutants that the run did not execute because of
      --max-mutants. The dry run decides their coverage: a pending mutant that
      no test reaches in the dry run is no_coverage. A capped run therefore
      reports the coverage of the full run.
    • A type test (*.test-d.ts, *.spec-d.ts, or a TypeScript file below
      test-d/) is not a test file of the plan. No runner executes it, so it
      no longer gives a false baseline failure or decides the runner.
    • A covering test that fails in the dry run of a restarted companion is a
      baseline failure. The mutant runs with its other covering tests and is a
      runtime error only when no covering test is left. A survivor of such a
      run survives: the check of the test count uses the tests of the run,
      so it no longer gives a runtime error such as 466 of 467 requested tests ran.
    • The dry-run timeout of a restarted companion grows with the first
      dry-run time and the worker count. It is at least the runner timeout. A
      loaded host no longer turns the mutants of a restarted companion into
      runtime errors.
    • Each no_coverage mutant has a test_reach object with the class of the
      audit test reach: mocked-only, none, none-file, transitive or
      direct. A mutant in an exported declaration gets the class of that
      export and its name. For mocked-only, the object lists the tests and
      the mocked modules. The human no-coverage lines count the mutants of
      each file by class, and the plan prints one line with these counts.
    • A run reuses the killed and survived results of an earlier run from the
      Fallow cache. The key covers the mutant, its covering tests, the content
      of the covering test files and the files that they import, the runner
      setup files (also the Bun preload files), the lockfile, the runner
      config and the files that it imports, the configs that the root
      tsconfig.json extends, and the runner. A change to one of them runs the
      mutant again. Dynamic imports that the module graph does not resolve, and
      files that a test reads, are not in the key. Each cache entry and the
      cache object of the report record this limit. A reused result has
      cached: true. --no-cache runs each mutant.
    • Each run writes the instrumented files to a run directory in the Fallow
      cache. A staging directory and a rename install it, so a concurrent run
      on the same plan never reads a partial file. A run reuses a directory
      with the expected content, and removes old run directories beyond the 5
      most recently used ones.
    • The new mutation config section sets the runner, the operators, the
      minimum score and the concurrency.
    • --typecheck or mutation.typecheck type-checks each survivor through
      the --type-aware companion after the tests. A survivor that adds a type
      error to its file gets the status compile_error and leaves the score.
      The check reads only the mutated file and never writes a project file.
      Without a companion, the run exits with 2 before the tests start.
      The checker cannot read a Vue, Svelte or Astro component, so a survivor
      in a component stays survived with the skip reason
      unsupported-file. (#​3471)
    • fallow health --mutation-report <file> reads a saved run report and
      adds the mutation score of each complexity finding next to its CRAP
      score, as mutation on the finding. A function whose file changed since
      the run is stale and gets no score. The score never changes CRAP or
      the health score. A plan or an invalid file exits with 2.
    • Vue, Svelte and Astro components get mutants in their script blocks: the
      Vue <script> and <script setup> blocks, the Svelte instance and module
      scripts, and the Astro frontmatter. Svelte module files (.svelte.js,
      .svelte.ts) get mutants too. The text outside the script blocks stays
      the same, so the framework plugin of the project compiles the mutated
      component.
    • Code that the framework compiler moves out of its block gives no mutant:
      the arguments and destructure defaults of defineProps and the other
      Vue compiler macros, an expression that holds a Svelte rune call, and an exported declaration in
      the Astro frontmatter. The arguments of a rune still get mutants.
    • The plan prunes the mutants in the default export of a tool config file,
      such as vite.config.ts or .eslintrc.js, with the reason
      framework-config. No test loads these files, so their mutants were
      no_coverage and lowered the coverage. A module.exports = ... config
      counts as the default export. Only a file whose name marks a config
      file counts, so codegen-helpers.ts or app/routes.ts keeps its
      mutants. A mutant inside a function of the config,
      for example an inline Vite plugin, stays in the plan. (#​3483)
    • The regex-literal operator changes one token of a regular expression
      literal. It removes a ^ or $ anchor, negates a character class, or
      gives \d, \w or \s the opposite case.
    • The runner is Vitest 4 or 5, node:test of Node.js 22.18 or later, or
      bun test of Bun 1.3 or later. mutation.runner selects one
      (vitest, node-test or bun-test). The default auto detects it
      from the vitest dependency, the test module that the test files
      import, a Bun file at the root, or a node --test script. node:test
      and bun test run each test file in its own process. (#​3407)
      Neither runtime can load a Vue, Svelte or Astro component, so with
      these runners the plan leaves component files out with the skip reason
      runner-cannot-load, and their mutants do not lower the coverage.
      The human output prints one Skipped files: line. (#​3470)
    • The node:test runner gives each test process the module loading flags
      of the node --test command in the project scripts:
      --experimental-transform-types, the strip-types flags, --import,
      --require, --experimental-loader and --conditions. A project
      whose test script uses --experimental-transform-types for a
      TypeScript enum now runs with no NODE_OPTIONS. The baseline failure
      of a test file that does not load now starts with the error line, for
      example SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: ..., not
      with a stack line. (#​3487)
    • A borp script is a node:test run. The files of its -p /
      --pattern glob, or of its positional arguments, are test entry
      points. Without a file and a pattern, the default borp glob
      **/*.test.{js,mjs,cjs,ts,mts,cts} applies. auto selects node-test
      for a project with a borp script. Before, the plan of such a project
      had no test file, and each mutant was no_coverage. Fallow does not
      read .borp.yaml, so a bare borp command gets the default glob. (#​3482)
  • fallow audit can skip sub-analyses. fallow audit now takes
    --only and --skip with the values and rules of bare fallow --only /
    --skip: dead-code, architecture, dupes and health. The new config
    keys audit.deadCode, audit.health and audit.dupes set the default
    selection. --skip removes from it, and --only replaces it. A skipped
    sub-analysis is skipped on the head and on the base snapshot, so it leaves
    the verdict, summary and attribution. A warn-only gate for complexity and
    duplication is now fallow audit --skip dead-code with the complexity rules
    at warn.

    • The JSON report omits the block of a skipped sub-analysis and sets
      summary.dead_code_skipped, complexity_skipped or
      duplication_skipped. The human output and the GitHub step summary show
      the row as skipped.
    • architecture narrows the dead-code findings to, or away from, cycles,
      boundary violations and policy violations. Styling findings come from the
      health sub-analysis.
    • A baseline flag for a skipped sub-analysis exits 2. A configured baseline
      for it is ignored. --max-crap, --coverage, --coverage-root and
      --runtime-coverage print a note when the health sub-analysis is skipped.
    • A selection that leaves no sub-analysis exits 2. The bare
      fallow --skip dead-code,dupes,health now exits 2 too, instead of
      printing an empty report.
    • A partial selection does not write the Impact record, as for the bare run.
    • The review brief (--brief, fallow review) keeps every sub-analysis.
    • The GitHub Action only / skip inputs and the GitLab FALLOW_ONLY /
      FALLOW_SKIP variables now apply to audit too. The MCP audit tool
      takes only and skip, and the programmatic run_audit reads the three
      config keys.
    • The GitHub step summary of audit now has the Styling row in both of
      its renderers.

    Thanks @​cr101 for the request. (#​3381)

  • The review brief reports test reach for changed exports. fallow audit --brief and fallow review add a test_reach section. For each value
    export that the diff changes, it states how tests reach it:

    • direct: a test file references the export.
    • transitive: tests reach it only through other modules.
    • mocked-only: only tests that mock a module on the import path reference
      it, so the real code does not run in a test.
    • none or none-file: no test references it, or no test loads the file.
    • framework: a framework configuration export with a literal value, such
      as the Next.js dynamic option.

    The JSON lists at most 25 exports that need attention, with the mocking
    tests and the mocked module of a mocked-only export. The human brief shows
    the counts and the first three rows. A project without test files gets one
    no-tests line. The section is advisory and never changes the exit code.

  • Built-in plugins for nine more tools. Before, fallow did not know these
    tools. Thus it reported their config files, entry files and packages as
    unused. Now each plugin activates on its package or config file:

    • mise reads mise.toml, .mise.toml, .config/mise/ and conf.d
      configs. Task run commands credit the packages and local scripts that
      they run. A bare command gets credit only when the config puts
      node_modules/.bin on PATH.
    • railway reads each service() in .railway/railway.ts. The build,
      start and pre-deploy commands credit the packages and files that they run.
    • flue makes the app, database, Cloudflare and agent modules of a Flue
      project entry points. Values in flue.config.* replace the default
      locations.
    • textlint reads .textlintrc in each JSON, YAML and JS form, the
      textlint key in package.json, and a textlint --config file. Each
      enabled rule, filter and plugin credits its package, by short name or by
      full name. A local rule path stays reachable.
    • jasmine reads spec/support/jasmine.* and makes the spec_files and
      helpers test entry points. The requires and loader modules get
      credit.
    • rstest reads rstest.config.*. It follows include, exclude,
      setupFiles, globalSetup, resolve.alias and projects. It credits
      the test environment, browser mode and coverage provider packages.
    • serverless-framework and osls read serverless.yml and
      serverless.ts. A root serverless.* config also activates
      serverless-framework, because the CLI is often installed globally.
      Each function handler becomes an entry point. Each
      package in plugins gets credit, and ${file(...)} references to YAML
      and JSON files resolve. The sls binary credits both packages.
    • typescript-content-mapper runs the exec script of
      package.json#typescript.contentMapper as an entry point.
  • fallow migrate recognizes more plugin sections and config keys. A
    plugin section for expo-router, varlock, turbo or one of the new
    plugins above now gets the "auto-detected" message, not the "unknown key"
    warning.
    The root keys cycles, ignoreGlobalBinaries, preprocessor,
    preprocessorOptions and asyncCompilers now get a specific message with
    the closest fallow alternative.

  • Effect dead-code findings. Projects that declare effect get three new
    rules, each at warn by default:

    • unused-effect-layer reports a layer that only unused layers compose.
      A layer with zero references stays an unused-export or an
      unused-class-member.
    • unused-tagged-error reports a Data.TaggedError or
      Schema.TaggedError class that types or catchTag handlers reference,
      but that no code constructs, fails with, or decodes.
    • unproduced-catch-tag reports a catchTag handler for a project tag
      that no code produces, when no unused-tagged-error finding covers it.

    Any value reference to an error class counts as a producer, so errors that
    an API or RPC schema decodes are not reported. Tags that no project class
    declares, and Effect built-in tags, are never reported.

  • Prop-drilling findings can enforce CI gates. Set rules.prop-drilling to
    error to enforce chains, or warn for advisory findings, including under
    --fail-on-issues. Source-hop overrides and suppressions control each chain.
    Baselines, audit attribution and changed-hop scopes support incremental
    adoption, and CI reports show the source location. The rule stays off by
    default, and editor diagnostics stay hints. Thanks
    @​miky-mfw for the request.
    (Closes #​3327)

  • fallow audit reports risky changes as rules. Five new rules compare the
    base and head text of each changed file. weakened-tests reports a new skip
    or focus marker, removed test cases, fewer assertions, or a less strict
    coverage threshold. added-suppression reports a new lint, type-check,
    coverage or Fallow suppression comment. test-only-branch reports a new
    process.env.NODE_ENV === 'test' style check in source code. A Vitest
    in-source test block (if (import.meta.vitest)) is test code and is not
    reported.
    diverged-clone-sibling reports an edit to one copy of duplicated code when
    the other copies did not change. added-dependency reports a new
    package.json dependency. These two rules are off by default. The other
    three rules are warn by default. Set a rule to error to fail the audit,
    or suppress one finding with // fallow-ignore-next-line <rule>. The
    findings are in the new diff_risk JSON section, in SARIF, in CodeClimate,
    in GitHub annotations, in the GitHub job summary and in the MCP audit
    tool. Compact output adds one record for each finding and markdown output
    adds a table. The human status line, the issue count of the GitHub Action
    and the GitLab template, and the VS Code audit status bar count the findings
    too. added-dependency has no suppression comment, because package.json
    cannot hold one: set the rule to off for the path in an overrides entry.

  • fallow health now reports hidden change coupling and change
    dispersion.
    A hidden pair is two files that change together in most
    commits while no import or re-export chain connects them. An agent that
    follows imports does not find the second file. The new change_coupling
    section lists these pairs with the Code Maat defaults: 5 commits per file,
    5 shared commits, a coupling degree of at least 30%, and commits with more
    than 30 analyzed files skipped. health.changeCoupling changes the
    thresholds. Each hotspot also gets median_files_per_commit and
    median_lines_per_commit. Without --since, these values read 12 months
    of history. A strong pair adds the hidden_coupling factor to the
    refactoring targets of its files. A file that no other target rule claims
    becomes a resolve_hidden_coupling refactoring target, so existing targets
    keep their category. This new category value moves schema_version to 12
    for health, 13 for audit, 14 for the combined report and 13 for the audit
    brief. fallow audit --brief shows an advisory co_change_gap fact when
    a diff changes one file of a hidden pair and not the other. The health
    score does not change. The churn cache moves to version 8 and is rebuilt
    once. The fallow-churn/v1 import accepts an optional commit field.

  • Traces now tell you which consumers a name search does not find. A
    grep -w for an export name does not find every consumer: a default import
    under another name, a barrel alias, or a whole-namespace use hides it. Each
    direct_references[] entry of fallow dead-code --trace FILE:NAME now has
    line, search_visibility (found, renamed, missed), reason, and
    search_as. search_as is the name to search for instead. A barrel that
    only forwards the export is found with reason pass-through and never
    counts as a gap, because it needs no edit when the export changes. A class
    member trace has the same fields on owner_direct_references[], checked
    against the owner export name. Each --impact-closure coordination gap
    has search_visibility, reason, and search_as. The MCP trace_export
    and impact_closure tools return them too. fallow audit --brief adds
    impact_closure.search_gap. It lists the missed and renamed consumers
    of each export whose declaration the diff changes, with at most 10
    consumers per export and a total. A trace reads the consumer sources of the
    traced export only. The audit brief reads the consumer sources of the
    exports in the changed files.

  • Search gaps name their symbol and read SFC declarations. An
    --impact-closure coordination gap now has search_symbol. It names the
    entry of consumed_symbols that search_visibility, reason, and
    search_as describe. The human output names the symbol when the consumer
    uses more than one symbol. The MCP impact_closure tool returns the field
    too. For a changed .vue, .svelte, .astro, or .mdx file, the audit
    brief now reads the declaration range from the script block, so a change
    inside a function body gives an impact_closure.search_gap entry.
    (#​3371,
    #​3372)

  • Alchemy projects no longer report their stacks and deployed Workers as
    unused.
    A new built-in alchemy plugin activates on the alchemy
    dependency. Each alchemy.run.{ts,mts,cts,js,mjs,cjs} file is an entry
    point, so the Worker modules that a stack imports stay reachable. The file
    that a resource names in main stays reachable from the file that declares
    it. Fallow reads new URL("./x.ts", import.meta.url),
    ${import.meta.dirname}/x.ts, path.join(import.meta.dirname, ...), a
    string next to such a rootDir, and a string in a stack file. When main
    names its own file, the default export and the exported Durable Object,
    Workflow and Container classes count as used. The CLI loads
    @effect/platform-node and @effect/platform-bun at runtime, so these
    packages are credited. The extraction cache version changes, so the first
    run after the upgrade parses each file again.

  • OpenTelemetry SDK callbacks are no longer reported as unused class
    members.
    A new built-in opentelemetry plugin activates on any
    @opentelemetry/* dependency. The SDK calls the methods of a class that
    implements Sampler, SpanProcessor, SpanExporter,
    PushMetricExporter, LogRecordProcessor, LogRecordExporter,
    ContextManager, TextMapPropagator, TextMapGetter or TextMapSetter.
    The plugin credits only the methods of that interface. A class that extends
    MetricReader gets credit for onInitialized, onForceFlush and
    onShutdown. Other members of the class stay reportable.

Changed
  • A single * in entry and dynamicallyLoaded globs no longer matches /.
    The pattern src/plugins/*/index.js also matched nested files such as
    src/plugins/alpha/components/button/index.js. Each nested match became an
    entry point, so fallow did not report it as an unused file. A single * now
    stays within one path segment and only ** crosses directories, as in
    picomatch. If your config used a
    single * to match nested files, change it to **. Thanks
    @​jleifeld for the report.
    (Closes #​3490)

  • A single * now stays within one path segment in every config path
    glob.
    If your config uses a single * to match nested files, change it
    to **. For example, change src/generated/* to src/generated/**, and
    *.test.ts to **/*.test.ts. For each pattern that now matches fewer
    files, fallow prints a warning on stderr. The warning names the config
    field, the pattern, the count of files that only the old rule matched, and
    the rewrite. --quiet hides the warning, and the JSON output does not
    change. The entry and dynamicallyLoaded fields already use this rule.
    It now also applies to ignorePatterns, ignoreFindings,
    overrides[].files, ignoreExports[].file,
    ignoreCatalogReferences[].consumer, duplicates.ignore,
    similarCode.ignore, health.ignore, health.thresholdOverrides[].files,
    the boundaries zone and coverage globs, the rule-pack file globs, and the
    framework[] fields usedExports[].pattern, manifestEntries[].manifests
    and detection.pattern. Only ** crosses directories, as in picomatch.
    Before this change, ignorePatterns: ["src/generated/*"] also ignored the
    files in the subfolders of src/generated, and "files": ["*.test.ts"] in
    overrides matched test files at any depth. A narrower glob can show new
    findings. A line that you copy from .gitignore can match fewer files in
    ignorePatterns. Fallow matches the glob against each file path, not
    against each directory. Thus src/generated/* in .gitignore ignores the
    subfolders of src/generated, but in ignorePatterns it does not. Globs
    that match package names or import specifiers, such as
    ignoreDependencies and ignoreUnresolvedImports, do not change.

  • Runs with a restored cache are faster. A fresh checkout moves the
    timestamps of every source file, so each run of a CI job that restores its
    cache rewrote every cache entry. A cache entry whose content did not change
    now gets only its new timestamps. On a large monorepo, such a run is about a
    fifth faster. The dead-code run also frees its parsed modules on a helper
    thread, so the report starts sooner.

  • Barrels that export * many packages no longer slow the graph down.
    Each import through such a barrel was checked against every package that
    the barrel re-exports. Now it is checked only against the packages that
    export its name, so the cost grows with the number of imports, not with
    imports times packages. Findings do not change.

  • One oxc version in the build. oxc_coverage_instrument moves to
    0.14, which uses oxc 0.152 like the rest of Fallow. The parser, AST and
    semantic crates no longer compile twice. cargo deny now fails when two
    versions of the core oxc crates enter the dependency graph.

  • The MCP audit tool has a fallow://tools/audit guide. The guide
    names the five diff-risk rules and holds the styling, coverage, baseline,
    grouping, runtime-coverage and FALLOW_DIFF_FILE detail. The audit tool
    description is now a short summary that points to the guide. (#​3369)

  • Workspace dependency declaration guidance is clearer. Root imports of npm
    workspace packages need a dependency declaration; npm links resolve imports
    without declaring them. Guidance covers private/tooling ancestor exceptions,
    self-references and explicit opt-outs. The declaration policy is unchanged.
    Thanks @​VariableVince for the question.
    (Closes #​3325)

  • Existing prop-drilling: "error" settings now enforce CI. Change the rule
    to warn to retain advisory analysis after upgrading. Archived JSON reports
    with effective_severity: "error" also render as errors; changing the current
    configuration does not rewrite those reports.

  • Complexity findings name more callback bodies. A function without a
    declared name now takes a name from the code around it, where it got
    <anonymous> or <arrow> before:

    • Effect.fn("Users.create")(function* ...) gives Users.create.
    • A function after a string-literal argument gives the call, for example
      Command.make("setup"), group.handle("github") or it("renders").
    • A generator that a named function returns, for example
      const load = () => Effect.gen(function* ...), gives load.

    Names that fallow gave before do not change, and scores do not change.
    Coverage matching and runtime function identities still use the placeholder.
    A renamed finding gets a new CodeClimate fingerprint one time. An identity
    baseline (--baseline-mode identity) gives the unused allowance of an
    <anonymous> or <arrow> bucket to new names in the same file, so a saved
    baseline stays valid. Re-save the baseline to record the new names. A file
    move no longer moves an <arrow> bucket, the same as an <anonymous>
    bucket.

  • Storybook, Vitest, Rstest, Jasmine and Playwright globs now accept every
    extglob group.
    One shared rewrite now reads the groups @(..), ?(..),
    +(..), *(..) and !(..) for these plugins and for import.meta.glob.
    Before, each plugin had its own rewrite with its own gaps. The changes per
    plugin are:

    • Storybook: before, only @(..) matched. A stories glob such as
      ../src/**/!(*.dev).stories.@(js|ts) matched no file. Now every group
      matches, and !(*.dev) excludes the files that match *.dev.
    • Playwright: before, a testMatch glob with a group made every script
      below testDir an entry point. Now only the files that the glob matches
      are entry points. The match still ignores case.
    • Vitest, Rstest and Jasmine: !(..) and *(..) now match. A Vitest plain
      (a|b) group still matches one of its alternatives.
    • Vitest: before, a test.include glob with any group made no file an
      entry point, so Fallow reported every test file as unused. Now the
      test.include globs of the config and of each project use the shared
      rewrite.
  • A +(..) group in an include glob now matches one or more repetitions.
    The glob matcher cannot repeat a group, so +(ts|js) becomes {ts,js}*.
    This can make a few more files entry points, for example a.test.jsx for
    *.test.+(ts|js). A +(..) group at the end of a glob also matches a
    longer extension, so *.test.+(ts|js) also matches a.test.tsx.
    Before, Vitest, Rstest and Jasmine matched the group
    once only, which missed names that repeat the group. An exclude glob still
    matches a +(..) group once only, so an exclude never removes a file that
    the tool keeps.

Fixed
  • The MCP routes now apply the same safety rules.

    • Code Mode now refuses an incomplete type-aware run that requires
      complete evidence (--type-aware-require complete, or
      typeAware.require: complete in the config). A direct tool call already
      returned an error for this run, but Code Mode returned the partial result
      as a success.
    • A typed-route tool result over 16 MiB now gets the same refusal as a CLI
      result over the cap: isError: true and code
      FALLOW_MCP_SUBPROCESS_OUTPUT_LIMIT, with context: "typed".
    • A Code Mode subprocess now reads stdin from the null device, as a direct
      tool call does. Before, it shared the MCP server's own stdin.
    • A cloud repository that is only dots (. or ..) is now refused. The
      value becomes one URL path segment, so .. addressed a different route.
      fallow coverage analyze --cloud, the cloud read commands and the cloud
      MCP tools refuse it, with the rule that already applies to commit SHAs.
  • Two Fallow processes can save the cache at the same time. The
    extraction cache and the graph cache wrote through one fixed temp file
    (cache.bin.tmp, graph-cache.bin.tmp). An editor server and a CLI run, or
    a pre-commit hook beside an editor, that shared .fallow/ wrote into the
    same file. A save could then fail, or the cache could hold bytes from two
    runs and be rebuilt from cold on the next run. Each save now writes its own
    temp file and renames it into place.

  • Cache eviction keeps the files that every run reads. At the size cap
    (cache.maxSizeMb), the extraction cache evicted the entries that it had
    parsed longest ago. A file that never changes was parsed once and was then
    the first entry to go, so the next run parsed it again. Eviction now removes
    first the entries that recent runs did not discover, for example test
    files after --production runs.

  • fallow audit --brief no longer reports every export as new public
    API after a run without --brief.
    Only a brief run computes the
    public exports of the base, but both runs shared one cached base
    snapshot. A brief run after a plain run on the same base read an empty
    base set, so public_api_added listed every export of the changed public
    files. The cache key now includes --brief, and the cache version moves
    to 13, so old snapshots are not used.

  • The audit base-snapshot cache no longer grows without a limit. Each
    new base commit or changed-file set wrote one more snapshot file of up to
    16 MiB below <cache>/cache/audit-base-v*/, and nothing removed them.
    Now each save removes the files that are older than audit.cacheMaxAgeDays
    (counted from the last use) and keeps only the newest 32 files.
    fallow audit-cache prune reports and removes these files too, as entries
    with pass: "snapshot". A file over the cap has the reason
    over-capacity.

  • An edit to package.json, deno.json or tsconfig.json now rebuilds
    the cached module graph.
    The graph cache compared source files only. A
    change to a package.json imports map, a workspace package name, a Deno
    import map, or a tsconfig.json that the resolver finds next to a source
    file (with its extends and references chain) did not change the cache
    key. The next run then used the old import targets and could report a live
    file as unused. Now the cache key includes the content of these files, the
    workspace names and roots, and the framework static directory mounts. The
    graph cache version changes, so the first run after an upgrade rebuilds
    the graph.

  • The worktree check of fallow mutation sees more stray writes. Before,
    the check left out the whole cache directory, so a cache.dir of . or
    src hid each write of the tests. Now it leaves out only
    <cache>/mutation and the output files. A run refuses a cache directory
    that is the project root or a directory above it, or that holds a planned
    file, with FALLOW_MUTATION_UNSAFE_CACHE_DIR and exit code 2. The check
    also compares the ignored files that git lists at the start, such as
    .env, so a write to one of them is a worktree-changed error. The docs
    now say that side-effect pruning covers only a function whose own body
    calls a sink.

  • Mutation companions no longer outlive Fallow. A companion that loses
    its stdin during a request now kills its process group and exits. Before,
    it waited for the request, and its test workers kept running after Fallow
    ended. Fallow now also ends the companions on SIGHUP, SIGQUIT and a panic.
    When Fallow starts with SIGHUP ignored, as under nohup, a hangup still
    does not end the run.

  • A direct MCP tool call now stops when the client cancels it or when it
    times out.

    • A client notifications/cancelled now reaches the work of the call.
      Before, the server kept the analysis running until it finished or until
      the response deadline.
    • A subprocess call stops its complete process tree at once.
    • A typed call sets the cancellation flag of the analysis, on a cancel and
      on a timeout. The analysis then stops at its next stage boundary. Before,
      a timed-out typed call continued to run to the end.
    • The client gets no response for a cancelled call, as the MCP
      specification requires. A timeout still returns a structured error:
      FALLOW_MCP_SUBPROCESS_TIMEOUT or FALLOW_MCP_API_TIMEOUT.
    • Code Mode and the direct tools now share one count of in-process calls
      that still run after their caller stopped. While that count is full, a
      Code Mode host call uses the subprocess.
  • A code_execute call now stops when the client cancels it. Before, a
    cancel did not reach Code Mode, and only timeout_ms ended the snippet.

    • The snippet stops, and a host call that starts after the cancel runs
      nothing.
    • A subprocess host call stops its complete process tree at once.
    • An in-process host call sets the cancellation flag of the analysis, as on
      a timeout.
  • The typed and CLI routes of an MCP tool now read the same settings.

    • production: false now gives --no-production on the CLI route. Before,
      only the typed route turned production mode off, and the CLI route used
      the config value.
    • feature_flags on the CLI route now ignores an empty root, config or
      workspace, as the typed route does.
  • Health recommendations use valid config keys. fallow recommend and
    the taste-choice catalog use health.maxCyclomatic, health.maxCognitive
    and health.maxCrap, matching the config reader.

  • GitHub audits keep blocking findings visible. Summary sections sort
    errors before warnings and prioritize introduced findings under new-only
    before truncation. Rule severity is separate from the complexity band.
    Styling details appear in summaries and annotations; missing historical
    attribution remains unknown.

  • Saved reports retain failure and rule identity. Failed-run envelopes
    are rejected with their original message, code, help and failure exit
    code. Legacy SARIF and CodeClimate keep canonical rule IDs, and CodeClimate
    distinguishes styling values and subkinds on the same line without
    changing other fingerprints. A styling finding rendered from a saved or
    legacy report gets a new SARIF rule ID and CodeClimate fingerprint one
    time, so code scanning and the merge request widget show it as new once.

  • Named exports returned through higher-order import loaders stay in use.
    Unknown wrappers preserve the imported module's exports instead of assuming
    that only default is read. Default-only credit requires a proven component
    loader import with no local shadowing. The extraction and graph caches rebuild
    so cached results use the corrected import facts.

  • An electron-vite renderer without an input keeps its files.
    electron-vite builds src/renderer/index.html when the renderer section
    of electron.vite.config.* declares no build.rollupOptions.input. Fallow
    did not use this default entry, so it reported every renderer file as
    unused. Now the default HTML entry and the files that it loads are
    reachable.

  • The review brief labels an edited export modified. The test_reach
    section labelled an export new when every line of its declaration was an
    added line. A one-line edit replaces the line, so an edited one-line export
    read as new. Now an export is new only when the file did not export the
    name at the base of the diff: a new export, a renamed export, or an export
    of a new file. An edited, rewritten or moved declaration is modified.
    The JSON test_reach object also adds e2e_runner: true when the project
    uses Playwright or Cypress. The human brief already said that these tests
    do not import files.

  • A namespace that holds only types is now a type export. TypeScript
    emits no JavaScript for a namespace whose body has only interfaces, type
    aliases, declare declarations, import type aliases and nested
    namespaces of the same kind. Before, Fallow treated such a namespace as a
    value export when it had no declare or export type. Examples are
    export namespace JSX { export interface Element {} } and the same shape
    with module or a dotted name such as A.B.C. Now:

    • An unused one reports as unused-type, not as unused-export. The SARIF
      rule id, the CodeClimate check name and fingerprint, the LSP diagnostic
      and the MCP and audit output change with it.
    • It is no longer an untested export in health --coverage-gaps, and it
      leaves the test_reach section of the review brief.
    • An existing fallow-ignore-next-line unused-export comment on such a
      namespace no longer matches. The finding then reports as unused-type
      and the comment as a stale suppression. Change the comment to
      unused-type.
    • Baselines that list such a namespace as an unused export can change.

    A body with any other statement, exported or not, stays a value. A
    const enum and a non-type import X = A.B alias also keep the namespace
    a value. A namespace that merges with a function, class, enum or variable
    of the same name stays a value too, so a value import of the merged name
    keeps crediting it. The extraction and graph caches are versioned again, so
    a warm cache does not keep the old classification.

  • A dynamic import() whose value escapes no longer reports the target
    exports as unused.
    An import() without a binding credited no export,
    also when its value left the expression. Examples are
    return import('./x') in a nested block, register(import('./x')),
    [import('./x')] and p.then(cb) after const p = import('./x'). Such
    an import() now credits every export of the target module. Only an
    import() whose value is discarded still loads the module without a
    credit. Examples are import('./x');, await import('./x');,
    import('./x').catch(onError); and import('./x').then(() => start()). A local loader function now also recognizes a
    return import('./x') inside switch, if, try and loop blocks. Thus
    const m = await load(name); m.createAdapter() credits createAdapter
    only. The extraction and graph cache versions are bumped, so the first run
    after the update re-parses every file.

  • The MCP trace_export tool runs the CLI when type-aware analysis is
    on.
    With typeAware.enabled in config or FALLOW_TYPE_AWARE set,
    fallow dead-code --trace adds semantic evidence to the trace, and with
    typeAware.require: complete it exits non-zero when that evidence is
    incomplete. The typed route of trace_export and the Code Mode
    traceExport route ignored these settings and returned the syntactic
    trace only. They now run the CLI in this case. fallow_api::run_trace_export
    returns the error code FALLOW_TYPE_AWARE_CONFIG_UNSUPPORTED when type-aware
    analysis is on, also for type_aware.enabled: Some(true). Set
    Some(false) to get the syntactic trace. When typeAware.require: complete comes from the config, an incomplete semantic trace or symbol
    impact is now an MCP error, as the CLI exit 1 says. Before, only the
    type_aware_require parameter made it an error.

  • Search gaps no longer count files that only forward an export. A file
    that imports an export and only exports it again needs no edit when the
    export changes. Examples are import { a } from './x'; export { a } and
    import { a as c } from './x'; export { c }. Such a file is now found
    with reason pass-through in --trace references, in --impact-closure
    coordination gaps and in the audit brief impact_closure.search_gap, the
    same as a pure barrel. A file that also uses the binding stays a normal
    consumer. A file that forwards the binding with export default b or
    export = b also stays a consumer, because its importers are not listed
    under the original export. A namespace import with member access (ns.a) stays found,
    and a whole-object use (Object.keys(ns), a spread, ns as a value) stays
    missed.

  • Coverage gaps and the CRAP estimate count only value references from
    tests.
    Before, a test reference that uses a value export only as a type
    counted as test reach. This covers an import type, and also a plain
    import that the test uses only in type positions (for example
    typeof fn). Now fallow health --coverage-gaps reports such an export
    under untested_exports. The static CRAP estimate for that function uses
    40% coverage (test-reachable file), not 85% (directly tested export). The
    static test signal of runtime coverage changes the same way. File-level
    reach does not change. A test with only type references to a module still
    makes that file test-reachable.

  • The coverage-gap note names mocked exports. fallow health --coverage-gaps now says "only tests that mock this module reference it"
    when the only test references to an untested export go through a closed
    factory mock. Before, the note said that no test-reachable module references
    the export.

  • The MCP audit tool and fallow_api::run_audit read the audit config
    section.
    The typed route ignored audit.gate, audit.css and
    audit.cssDeep. A project with "gate": "all" got the new-only verdict
    from the MCP tool, and the CLI gave all. The typed route now uses these
    keys when the tool parameter is not set, the same as fallow audit. The
    typed route cannot apply audit.deadCodeBaseline, audit.healthBaseline
    or audit.dupesBaseline. When the config sets one of them, the MCP tool
    now runs the CLI, which applies the baseline. fallow_api::run_audit
    returns the error code FALLOW_AUDIT_BASELINE_UNSUPPORTED for these keys.
    It does not ignore them.

  • type_aware: false keeps a run syntactic on every programmatic surface.
    The MCP analyze, check_health, audit and inspect_target tools
    ignored type_aware: false: when the config turned type-aware analysis
    on, the run was type-aware. The tools now pass --no-type-aware to the CLI
    and keep the typed route syntactic, as --no-type-aware does. In
    fallow_api, TypeAwareOptions.enabled is now an Option<bool>.
    Some(false) runs syntactic without the
    FALLOW_TYPE_AWARE_CONFIG_UNSUPPORTED error, also when
    FALLOW_TYPE_AWARE or the config turns type-aware analysis on. In the
    Node bindings, typeAware: { enabled: false } does the same. Before, it
    was the same as an unset option. An explicit choice now also reaches
    detection, as the CLI flags do: a syntactic run credits the framework
    class members that the type-aware config holds back for verification, and
    a type-aware run turns the opt-in private-type-leaks rule on unless the
    config sets it. Before, fallow_api and the Node bindings reported no
    private-type leaks for a type-aware run where fallow dead-code --type-aware reported them.

  • The MCP tools run type-aware analysis when the config turns it on.
    fallow runs type-aware analysis when typeAware.enabled is true, and
    fallow audit also when audit.typeAware is true. The typed route of the
    MCP analyze, check_changed, check_health and audit tools and of the
    Code Mode combined route ignored these keys and the FALLOW_TYPE_AWARE
    variable. It returned syntactic results where the CLI returned type-aware
    results. These routes now run the CLI when one of these settings turns on
    type-aware analysis. fallow_api::run_dead_code,
    run_circular_dependencies, run_boundary_violations, run_audit,
    run_combined and run_health now return the error code
    FALLOW_TYPE_AWARE_CONFIG_UNSUPPORTED in this case. They do not return
    syntactic results. The Node bindings return the same error. To run
    type-aware analysis through the API, set typeAware.enabled in the call
    options. To keep a call syntactic, set FALLOW_TYPE_AWARE=0.

  • Clone families have one order on every surface. fallow audit,
    fallow dupes --changed-since and fallow dupes --baseline now order
    clone_families[] by file set. fallow dupes, the MCP tools and
    fallow_api already used this order. Before, these three commands ordered
    the families by duplicated lines. The suggestions[] of a family now follow
    the order of its groups[] on every surface. Two mirrored_directories[]
    entries with the same total_lines are now ordered by directory pair. The
    family set and the values do not change.

  • The review brief and the audit report the same weakened guardrails.
    The weakening section of fallow audit --brief and fallow review now
    reads its test, threshold and suppression signals from the diff_risk
    findings of the same run. Before, a second detector could report a moved
    test as removed, a lower maxCrap as a lowered threshold, or a
    suppression token in a Markdown file as an added suppression. The JSON keys
    do not change. The evidence text now follows the diff-risk evidence, for
    example test cases: 2 -> 1. (#​3368)

  • weakened-tests reads JavaScript-family test files only. A test file
    in another language, such as a Rust integration test under tests/, can
    hold it.skip or it( text in a string. The rule no longer reports a skip
    marker or removed tests from such a file, and such a file no longer changes
    the test-case totals of the change.

  • The GitLab template counts styling findings like the GitHub Action.
    Under gate: all, the issue count now includes every styling finding.
    Under gate: new-only, it includes the introduced styling findings. Before,
    FALLOW_FAIL_ON_ISSUES did not see them. (#​3370)

  • A test run with a directory or without file arguments now credits its
    test files.
    A script or a CI run line such as bun test src/,
    deno test, deno test tests or node --test test/ made no file a test
    entry point. So the code that these tests import got coverage tier none
    in fallow health and fallow audit CRAP scores. Now a directory
    argument gives the default test file patterns of the runner inside that
    directory. A bun test or deno test run with no file argument gives the
    default patterns of the working directory. Fallow tells a directory from a
    file by its syntax: the argument ends with /, or its last segment has no
    extension and no glob character. Other files in the directory do not
    become entry points, except below a directory named test, where
    node --test runs every source file. The node --test <dir> form follows
    Node 20. Node 21 and later report an error for a directory argument. A Bun
    name filter such as bun test parser adds no pattern. The test files that
    these runs find, and the files that they import, are no longer reported as
    unused files in fallow dead-code.

  • The config schema now describes warn correctly. The descriptions of
    Severity and of the rules that default to warn said that warn does not
    fail CI. A warn finding does not change the CLI exit code unless
    --fail-on-issues is set. The dead-code count gate of the GitHub Action
    counts warn findings, because fail-on-issues defaults to true and the
    gate reads total_issues.

  • The diff-risk rules of fallow audit report less noise. A check over
    merged pull requests of five public projects found these causes, and the
    rules now handle them:

    • weakened-tests does not report removed tests or assertions when the
      lost test lines name code that the same change removed, such as a deleted
      function, error code or fixture directory. The tests went with that code.
      A name of a deleted file that a changed file still holds, a name that a
      deleted file only imports, a directory that still exists, and a reserved
      word such as import do not count.
    • weakened-tests reports an assertion drop only when assertions are at
      least half of the code lines that the test file lost. A test rewrite that
      moves setup checks into a shared helper does not report.
    • added-suppression does not report files below a fixture or generated
      directory, such as a vendored fixture/generated/schema.ts with a
      // @ts-nocheck header.
    • test-only-branch does not report a check that only keeps console
      output quiet in tests, or a check that picks a .env.test file.
    • diverged-clone-sibling does not report an edit to a story copy
      (*.stories.*, *.story.*), the same as a test copy.
    • diverged-clone-sibling is now off by default. Most of its findings
      were copies that differ on purpose, for example an input and an output
      type, a legacy copy, or one component that gets a new feature. Set the
      rule to warn or error to review every diverged copy.
      (Closes #​3367)
  • A static member read through a namespace is no longer an unused class
    member.
    Code such as Layer.provide(Discord.ApiClient.layer) did not count
    as a use of ApiClient.layer. Now a read of Ns.Class.member credits the
    member when Ns is a namespace import or a named import of
    export * as Ns from. Re-export barrels between the namespace and the class
    are followed. A local binding that shadows the namespace does not credit the
    member.

  • Members that a package or the runtime calls are no longer unused class
    members.
    Two cases are now credited:

    • An override member of a class whose base comes from a package or is a
      global constructor, for example override onStop() on a subclass of
      Container from @cloudflare/containers, or override get message() on
      a Schema.TaggedError or Data.TaggedError class from Effect.
    • message, stack, cause and toString on a subclass of a native
      Error, also without override. The runtime reads them to print an
      error. Before, only name got this credit.

    An override gets no new credit when the base is a project class, a mixin
    call that takes a class (extends Mixin(LocalBase)), an unresolved import,
    or a local class with the name of a global.

  • Files that node --test, bun test or deno test runs are now test
    entry points.
    A package.json script or a CI run line such as
    node --test scripts/*.test.mjs made these files entry points with the
    support role only. So the code that they import got coverage tier none in
    fallow health and fallow audit CRAP scores. Now the file and glob
    arguments of these runners have the test role, and the imported code gets
    the static coverage estimate. With no file arguments, the files that match
    the default node --test patterns are test entry points too. bun test in
    a script named test works the same way. A flag value is not a test file:
    a reporter, a loader, a global setup module and a
    --test-coverage-include glob keep no test role. A setup file such as
    --import ./setup.mjs runs in the test process, so it is test code too.
    A --test-coverage-include or --test-coverage-exclude glob also no
    longer makes the files that it matches entry points.

  • The config JSON Schema now accepts extends as a single string. The
    loader already accepted "extends": "./base.json" and the array form. The
    schema allowed only the array, so editors flagged a valid config. The
    schema now allows both forms.
    Thanks @​Smrtnyk for the report.
    (Closes #​3351)

  • CSS health now credits a keyframe name in an animation shorthand that
    contains var().
    A var() or env() in the value made the CSS parser keep
    the declaration as raw tokens, so animation: pulse var(--duration) ease did
    not count as a use of @keyframes pulse. Now each literal name in the
    shorthand and in animation-name counts, also in a comma-separated list. A
    var() in the name position stays unresolved. Thanks
    @​Smrtnyk for the report.
    (Closes #​3349)

  • CSS health now recognizes the classes of Vue <Transition> and
    <TransitionGroup>.
    A literal name="fade" credits fade-enter-from,
    fade-enter-active, fade-enter-to, fade-leave-from, fade-leave-active
    and fade-leave-to. A <TransitionGroup> also credits fade-move. A tag
    without name credits the same classes with the v prefix. Literal custom
    class props such as enter-active-class also count. A bound :name credits
    no generated class, because the name is not known before run time. Scoped
    styles get the credit only from the same component. Global styles get it
    from any Vue component. Thanks @​Smrtnyk for the
    report. (Closes #​3350)

  • unused-store-member no longer reports live Pinia setup-store members in
    two cases.
    A helper can read a member through a parameter typed
    ReturnType<typeof useCounterStore>, or through a type alias of that form that the same file declares before
    the helper.
    Fallow now credits that read to the store, also when the i

[!IMPORTANT]
✂ PR body was truncated to here.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@coderabbitai

coderabbitai Bot commented Oct 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 80e4ccba-fb73-4f1b-9b27-9e151dd744df

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedfallow@​3.33.1 ⏵ 3.34.0100 +110010096100

View full report

@pkg-pr-new

pkg-pr-new Bot commented Oct 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/node-modules/urllib@955

commit: 712e1e2

@codecov

codecov Bot commented Oct 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.77%. Comparing base (e37325d) to head (712e1e2).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #955   +/-   ##
=======================================
  Coverage   94.77%   94.77%           
=======================================
  Files          10       10           
  Lines         746      746           
  Branches      235      235           
=======================================
  Hits          707      707           
  Misses         36       36           
  Partials        3        3           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

0 participants