Skip to content

Local downloading of optimization statistics for the build - #1186

Open
mu-hun wants to merge 115 commits into
masterfrom
local_optimization_config
Open

Local downloading of optimization statistics for the build#1186
mu-hun wants to merge 115 commits into
masterfrom
local_optimization_config

Conversation

@mu-hun

@mu-hun mu-hun commented Apr 3, 2026

Copy link
Copy Markdown
Member

Enables local download and reuse of optimization stats, supporting filter creation based on a pinned stats snapshot.

This feature is managed entirely through build flags in FiltersRegistry.

The workflow

  • yarn download-stats (--download-stats) downloads per-filter stats.json files to temp/optimization/stats/filters/<filterId>/stats.json. Use --include or --skip to scope which filters are downloaded.
  • yarn build:local: If downloaded optimization stats exist, stats are read from there; if any required filter is missing its stats.json, the build fails with a message pointing to yarn download-stats. If stats doesn't exist, stats are fetched live from the remote server instead.

Alex-302 and others added 5 commits March 28, 2026 20:40
Strip volatile metadata lines (Checksum, Diff-Path, TimeUpdated, Version)
from compiled filter files after build. Reduces noise when comparing
outputs between compiler versions.
@mu-hun
mu-hun force-pushed the local_optimization_config branch 2 times, most recently from 6507dd5 to 3bcca2e Compare April 7, 2026 10:01
Comment thread yarn.lock
@mu-hun
mu-hun force-pushed the local_optimization_config branch 2 times, most recently from df6f136 to 424e89f Compare April 8, 2026 15:53
@mu-hun

mu-hun commented Apr 8, 2026

Copy link
Copy Markdown
Member Author

Please specify how to perform the test.

I have just aligned with the flags you created (#1181). In the PR description,

Both --generate-cache and --use-cache flags now include optimization config handling alongside the existing filter source caching.

@mu-hun
mu-hun marked this pull request as ready for review April 8, 2026 16:34
@mu-hun
mu-hun requested a review from Alex-302 April 8, 2026 16:34
@mu-hun
mu-hun force-pushed the local_optimization_config branch from e04f297 to 867ab88 Compare April 27, 2026 08:19
@mu-hun

mu-hun commented Apr 27, 2026

Copy link
Copy Markdown
Member Author

Crash fixed

7691c68. The cache dir is wiped with force: true before generate() runs, so re-running on an existing cache no longer errors.

Alex-302 and others added 6 commits April 28, 2026 00:02
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
@mu-hun

mu-hun commented Aug 26, 2026

Copy link
Copy Markdown
Member Author

If there are no further suggestions or change requests, I'm ready to merge 👀

@mu-hun
mu-hun requested review from maximtop and removed request for maximtop and piquark6046 August 26, 2026 11:56

@maximtop maximtop left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly small stuff inline. The one I'd genuinely chase is the e2e percent.json mock — it doesn't intercept the compiler's fetch, so the new CI workflow hits the live network on every PR. The beta compiler pin and the script placement are already tracked in open threads.


// compile() always fetches percent.json remotely, even under use(). Mock only
// that call so the suite below stays offline; everything else passes through.
vi.mock('child_process', async (importOriginal) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth another look at the offline claim here: the compiler's ESM build fetches percent.json via createRequire(import.meta.url)('child_process').execFileSync('curl', ...) (checked the pinned 3.3.0-beta.1 dist, index.js:1000/1025), and since vitest externalizes @adguard/filters-compiler, this vi.mock('child_process') never intercepts that call — the real curl runs. So every yarn test (both Node legs of the new test.yaml on every PR) curls the live chrome.adtidy.org/optimization_config/percent.json and depends on it listing filterId 1. On a network hiccup the compiler's curl --retry 5 backoff (~31s) also blows past the 30s beforeAll timeout and fails the whole file. Inlining the compiler into vitest's transform pipeline (server.deps.inline), having the compiler accept a local percent.json, or stubbing curl via PATH would each fix it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including #1186 (comment), I'll take this issue as adding an option to load percent.json locally from #1222.

But I want to finalize this PR with no more additional patches, so I'd like to handle that issue after this feature is released. Therefore, I just dropped the "offline" keyword from the PR body and main issue description as follows:

Enables local download and reuse of optimization stats, supporting filter creation based on a pinned stats snapshot.

Comment thread DEVELOPMENT.md Outdated
Comment thread DEVELOPMENT.md
`template.txt` with a single `@include "./filter.txt"` directive, and compiles
from that copy. The original `filters/` directory is never modified.

Optimization stats are picked up automatically: if `temp/optimization/stats`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This says the local stats are "used as-is", but getOptimizableFilterIds() in the pinned compiler always fetches percent.json via curl, even after localOptimizationStatistics.use() — only the per-filter stats.json content comes from disk. So yarn build:local still needs network (offline it hangs through curl retries and dies with a raw curl error, no --download-stats hint), and the snapshot isn't fully pinned since the live percent.json decides which filters get optimized. Either document the remaining network dependency here (and drop "offline" from the PR body), or have the compiler read percent.json from the cache dir under use().

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

answered in #1186 (comment)

Comment thread scripts/build/__tests__/regression-test-against-master.sh
Comment thread AGENTS.md Outdated
Comment thread DEVELOPMENT.md Outdated
Comment thread scripts/build/build.js Outdated
echo "Branch (reference): master @ $MASTER_SHA"
echo "Branch (feature): $CHANGED_BRANCH @ $CHANGED_SHA"
if [ "${BUILD_LOCAL:-false}" = "true" ]; then
BUILD_CMD="generate-cache && yarn build:local --no-patches-prepare --strip-generated-meta"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script uses 2-space indentation and no shebang, while the repo's other shell scripts (scripts/auto_build.sh, the translations scripts) start with #!/bin/bash and use 4-space indentation. Harmless at runtime since DEVELOPMENT.md invokes it via bash, but worth matching when it moves in the child PR.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll update to use 4-space indent in one-level child PR.

Comment thread scripts/build/build-config.ts Outdated
};
}

if (flags.useCache && flags.downloadStats) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The three mutual-exclusion blocks here are identical except for flag names, and this PR adds the second and third. The neighboring incompatibility checks were just deduplicated via buildIncompatibilityError; the same treatment fits (a buildMutualExclusionError(a, b) helper or a small table of exclusive pairs), so a wording tweak isn't edited three times.

});
});

it('--download-stats: downloads stats for all filters, compile skipped', async () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The three --download-stats tests below are line-for-line identical (~17 lines each) — set argv, import build.js, destructure the mocked compiler, vi.waitFor the same download assertion; only the extra flag and expected include/exclude arrays differ. A single it.each keeps the coverage without the copy-paste and would also absorb the repeated mock destructure recurring in nearly every test of this block.

Comment thread .markdownlint.json Outdated
Comment thread DEVELOPMENT.md
mu-hun added 2 commits August 27, 2026 15:25
Document that --download-stats swaps the entire local stats
directory rather than merging per-filter, so scoped downloads
must be paired with an equally scoped build.

I've removed description "--include or --skip are not both at once." in AGENTS.md
and add description rejects --report flag in both files.

Also, "scoped downloads must be paired with an eqaully scoped build
— sholud I mentioned the same for the `--generate-cache` flag?

Commented in
- #1186 (comment)
- #1186 (comment)
- #1186 (comment)
- #1186 (comment)
mu-hun added a commit that referenced this pull request Aug 27, 2026
The top-level buildFilters() call had no .catch, so any rejection surfaced
as an UnhandledPromiseRejection trace where the actionable hint (e.g. "run
--download-stats") is easy to miss. Now matches the arg-validation error
pattern: print the message in red and exit(1).

Commented in #1186 (comment)
The top-level buildFilters() call had no .catch, so any rejection surfaced
as an UnhandledPromiseRejection trace where the actionable hint (e.g. "run
--download-stats") is easy to miss. Now matches the arg-validation error
pattern: print the message in red and exit(1).

Commented in #1186 (comment)

About updated test case:

The missing-stats.json case previously asserted on an unhandledRejection.
Now that buildFilters() catches rejections and exits 1, the test spies
console.error and process.exit, waits for exit(1), and checks the printed
output contains the --download-stats hint plus the original error message.
@mu-hun
mu-hun force-pushed the local_optimization_config branch from b902864 to 5cc9a45 Compare August 27, 2026 11:15
mu-hun added 3 commits August 28, 2026 15:11
'optimization_config' base path name to 'optimization/stats':
  build.js now uses optimizationStatsDir = path.join(tempDir, 'optimization', 'stats'). Mirror that.

Suggested in #1186 (comment)
--use-cache, --generate-cache, and --download-stats are one mutually
exclusive group.

Replace the three near-identical pairwise blocks with
a single table + count check, so the wording lives in one place.

Suggested in #1186 (comment)

@mu-hun mu-hun left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reviewed and applied all of your suggestions.

Comment thread DEVELOPMENT.md
yarn build --download-stats --skip=12,24
# Scoped download replaces the cache with just these filters — pair with a matching scoped build
yarn build --download-stats --include=1,2,3 && yarn build:local --include=1,2,3
yarn build --download-stats --skip=12,24 && yarn build:local --skip=12,24

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scoped downloads must be paired with an equally scoped build

Should I also mentioned above for the --generate-cache flag?

AS-IS

# Cache generation with filter selection
yarn build --generate-cache
yarn build --generate-cache --include=1,2,3
yarn build --generate-cache --skip=12,24
yarn build --generate-cache --report='report.txt'

TO-BE

# Cache generation with filter selection
yarn build --generate-cache
# Scoped download replaces the cache with just these filters — pair with a matching scoped build
yarn build --generate-cache --include=1,2,3 && yarn build:local --include=1,2,3
...


const filtersDir = path.join(tmpDir, 'filters');
optimizationDir = path.join(tmpDir, 'optimization_config');
optimizationStatsBasePath = path.join(tmpDir, 'optimization', 'stats');

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the outdated optimization_config base path name to optimization/stats:

@mu-hun
mu-hun requested a review from maximtop August 28, 2026 06:29
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.

7 participants