Skip to content

Fix plugin cache policy handling, add producer-derived TTLs, declare generated grammar as a build output - #1068

Merged
theoephraim merged 2 commits into
mainfrom
plugin-cache-fixes
Sep 4, 2026
Merged

Fix plugin cache policy handling, add producer-derived TTLs, declare generated grammar as a build output#1068
theoephraim merged 2 commits into
mainfrom
plugin-cache-fixes

Conversation

@theoephraim

Copy link
Copy Markdown
Member

Three independent fixes, split out of #1044 so they can land without waiting on the AWS MFA feature. None of them are AWS-specific.

Plugin caches ignored the @cache policy

Plugins install during finishInit, before the @cache root decorator is applied in finishLoad. A cache accessor bound to whatever store existed at install time therefore never saw the policy, so under @cache=memory or @cache=disabled every plugin's cacheTtl fell through to a no-op store. That affects all 11 plugins that cache, not just one.

The accessor now looks up the backing store per call, and the final store is re-propagated to plugins once the policy resolves.

Covered by a new test using a fixture plugin that resolves through plugin.cache: two items sharing a key must produce one value. Without the fix the producer runs twice.

getOrSet can derive its TTL from the produced value

getOrSet took its TTL up front, but for anything whose lifetime the source decides (an STS session, an OAuth token, a lease) that is only known once the producer has run. Callers had to guess a lower bound and correct it afterwards, leaving a window where the entry outlived what it described.

The ttl argument now also accepts a callback receiving the produced value, called once and only when the producer actually produced. Returning zero or less skips the write. All existing callers pass a literal and are unaffected.

Note the guarantee is scoped: cross-process sharing covers persisted results only. A skipped or failed write leaves later processes to run the producer themselves, so a caller guarding single-use work needs a positive TTL. The docstring says so.

Generated parser grammar was not a declared build output

packages/env-spec-parser/src/grammar.js is produced by peggy and gitignored, but the build task only declared dist/**. On a cache hit turbo restored dist/ without it, so a fresh checkout that hit the cache had no grammar and anything importing the parser from source failed with ERR_MODULE_NOT_FOUND. This surfaced whenever a downstream test task cache-missed while the parser build cache-hit.

Also adds grammar.peggy to the build inputs. It sits at the package root, so the shared src/** glob never covered it and editing the grammar would not have invalidated the cache.

The eslint jsonc glob now matches package-level turbo.json files, not just the root one, so they can carry comments the way the root config does.

…s from produced values

Three independent fixes, split out of the aws MFA work so they can land on
their own.

Plugins install during finishInit, before the @cache root decorator is
applied, so a cache accessor bound to whatever store existed at install
time silently ignored the policy - every plugin cacheTtl fell through to a
no-op store under @cache=memory or @cache=disabled. The accessor now reads
the store per call and the final store is re-propagated after the policy
resolves.

getOrSet needed a TTL up front, but for anything whose lifetime the source
decides - an STS session, an OAuth token, a lease - that is only known once
the producer has run. The ttl argument now also accepts a callback given
the produced value, called once and only when the producer produced.
Returning zero or less skips the write, and that skip does not share across
processes, which the docs now say plainly. Existing callers pass a literal
and are unaffected.

The parser's generated src/grammar.js was not a declared build output, so a
turbo cache hit restored dist/ without it and anything importing the parser
from source failed to resolve. grammar.peggy is now an input too, since the
shared src/** glob never covered it.
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

bumpy-frog

The changes in this PR will be included in the next version bump.

minor Minor releases

  • @varlock/native-helper-darwin 1.18.0 → 1.19.0
  • @varlock/native-helper-linux-arm64 1.18.0 → 1.19.0
  • @varlock/native-helper-linux-x64 1.18.0 → 1.19.0
  • @varlock/native-helper-win32-x64 1.18.0 → 1.19.0
  • varlock 1.18.0 → 1.19.0

Bump files in this PR

Click here if you want to add another bump file to this PR


This comment is maintained by bumpy.

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle size

⚠️ grows the bundle by 8.1 KB (+0.2%)

Metric main This PR Δ
Total dist 4479.1 KB 4487.2 KB +8.1 KB (+0.2%)
JS 1702.2 KB 1704.0 KB +1.8 KB (+0.1%)
Sourcemaps 2667.5 KB 2672.1 KB +4.6 KB (+0.2%)
Type defs 109.3 KB 111.0 KB +1.6 KB (+1.5%)
Other 0.0 KB 0.0 KB

dist/ only; native binaries are versioned separately and not counted here.

@pullfrog pullfrog Bot 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.

Important

The parser build cache still omits an environment input that changes the generated grammar, so Turbo can restore the wrong build variant.

Reviewed changes in 405dc1fa, covering plugin cache-store propagation, producer-derived TTL handling across every store, tests, and parser build-cache declarations.

  • Plugin cache policy: Accessors now resolve their backing store lazily, and EnvGraph propagates the store selected by the final @cache policy.
  • Producer-derived TTLs: getOrSet accepts value-based TTL callbacks, normalizes plugin duration strings, skips non-positive writes, and retains producer coalescing behavior.
  • Build outputs: The parser task now tracks grammar.peggy and restores generated src/grammar.js, with nested Turbo configs covered by JSONC linting.

⚠️ Parser build cache ignores trace mode

peggy.config.cjs uses the documented PEGGY_TRACE variable to change src/grammar.js, but the package build task does not include that variable in its environment inputs. Turbo therefore treats traced and untraced builds as interchangeable and can restore the wrong generated parser.

Technical details
# Include the grammar trace mode in the build hash

## Affected sites
- `packages/env-spec-parser/turbo.json:5` - the build task has no `env` entry
- `packages/env-spec-parser/peggy.config.cjs:5` - `process.env.PEGGY_TRACE` changes Peggy's `trace` option

## Required outcome
- Builds with `PEGGY_TRACE` enabled and disabled must have different Turbo cache keys.

## Suggested approach
- Add `"env": ["PEGGY_TRACE"]` to the package build task.

## Verification
- `turbo run build --filter=@env-spec/parser --dry=json` reports hash `e3ec243272b9b092` both with `PEGGY_TRACE=1` and with it unset.
- Direct generation produced different grammar hashes: `b7b456fb...` with tracing and `fbf21eeb...` without tracing.

@pkg-pr-new

pkg-pr-new Bot commented Sep 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

@env-spec/parser

npm i https://pkg.pr.new/dmno-dev/varlock/@env-spec/parser@1068

varlock

npm i https://pkg.pr.new/dmno-dev/varlock@1068

@varlock/native-helper-darwin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/native-helper-darwin@1068

@varlock/native-helper-linux-arm64

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/native-helper-linux-arm64@1068

@varlock/native-helper-linux-x64

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/native-helper-linux-x64@1068

@varlock/native-helper-win32-x64

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/native-helper-win32-x64@1068

@varlock/aws-sigv4-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/aws-sigv4-plugin@1068

commit: 1609aa7

peggy.config.cjs turns on tracing from PEGGY_TRACE, which changes the
generated grammar, but the build task did not declare it. That was harmless
while the grammar was regenerated by executing the task; declaring
src/grammar.js as a restorable output made it a hazard, since a traced and
an untraced build shared a cache key and either could be restored over the
other.

Verified: the task hash was identical with and without the variable and now
differs, and the two grammars really are different files.
@theoephraim

Copy link
Copy Markdown
Member Author

Confirmed and fixed in 1609aa7 by adding "env": ["PEGGY_TRACE"] to the parser build task.

Verified both directions rather than taking the report on faith: the task hash was byte-identical with and without the variable (34fe01c2095872cd either way) and now differs (f90d5b40... vs 71c6bfa8...), and the two generated grammars really are different files (c14f0ca3... untraced vs 1badfc3f... traced).

Worth noting this hazard was introduced by this PR: while src/grammar.js was regenerated by executing the task, a missing env input was harmless. Declaring it a restorable output is what made a traced and an untraced build interchangeable in the cache.

@pullfrog pullfrog Bot 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.

✅ No new issues found.

Reviewed changes since the prior Pullfrog review, focusing on the parser build-cache correction in 1609aa7c.

  • Declared trace-mode input: Added PEGGY_TRACE to the parser build task's environment inputs, so traced and untraced generated grammars no longer share a Turbo cache key.
  • Verified effective hashing: Confirmed Turbo resolves the environment declaration and produces distinct build hashes with PEGGY_TRACE unset and enabled.

Pullfrog  | View workflow run | Using azure/gpt-5.6-sol𝕏

@theoephraim
theoephraim merged commit bcee022 into main Sep 4, 2026
28 checks passed
theoephraim added a commit that referenced this pull request Sep 4, 2026
Rebuilt on current main with the non-AWS changes removed - the @cache
policy fix, the getOrSet TTL callback, and the parser grammar build output
now live in #1068. The duplicate varlock changeset went with them.

DEPENDS ON #1068. The session cache passes getOrSet a TTL callback, which
that PR adds, so this does not typecheck until #1068 is in main:

  plugin.ts: Argument of type '(session: StoredSession) => number' is not
  assignable to parameter of type 'string | number'

That is the only outstanding error. Rebase on main once #1068 lands.

Parked pending a real-world test - see #1047 for the known open gap in
cross-process coordination on the failure path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant