Commit da5f3d6
authored
* directive: image-guard pipeline (#87)
Replaces v3.2.1's static CACHE_FIX_IMAGE_MAX_DIM with a conditional
three-pass pipeline matching Anthropic's documented rules:
Pass 1 — conditional dim cap (count >20 → 2000px, else 8000px)
Pass 2 — request-size guard (Buffer.byteLength after mutations,
default 30MB budget vs 32MB API ceiling)
Pass 3 — optional Lanczos resize via lazy-loaded sharp peer-dep,
opt-in via CACHE_FIX_IMAGE_PRESERVE_DETAIL=1, preserves
original media type (no transcoding in v1)
Plus hard image-count cap (100 for 200K-window models incl.
claude-3-7-sonnet-, 600 for others; unknown model → safer 100).
Activation: prefix-diff pattern (enabled: true + runtime env-gate),
matching overage-warning and upstream-change-detection. v3.2.1 legacy
KEEP_LAST and MAX_DIM gates remain functional for back-compat.
Includes the two Codex design-stage reviews (REQUEST CHANGES → APPROVED
with notes) so the audit trail is in-tree.
Ref #87
* docs: add PR 88 codex directive review
* directive: address Codex's two blockers on PR #88 review
1. Pin Pass 3's trigger and target unambiguously.
Old wording let Pass 3 read either as "resize when Pass 1 would have
stripped" (target = rejection cap) or as "quality resize whenever
above native cap" (target = native cap). These produce different
behavior for the case Codex called out: a 5000×5000 image in a
5-image request with PRESERVE_DETAIL=1.
Resolved: passes are independent. Execution order is now explicitly
Pass 0 → Pass 3 → Pass 1 → Pass 2 → count cap. Pass 3 (when enabled)
targets the native cap (2576 for claude-opus-4-7, else 1568) for
ANY image above it, regardless of Pass 1's outcome. Pass 1 strips
only — never resizes. Pass 3 resizes only — never strips. Added
test 16 specifically for the above-native, below-rejection gap.
2. Drop the dead 600-cap branch.
Old spec: 100 for 200K-window models, 600 for "other models."
Classifier collapsed every current CC-pipeline model to 100, so
nothing took the 600 branch — CACHE_FIX_IMAGE_COUNT_MAX_OTHER was
unreachable spec surface.
Resolved: single CACHE_FIX_IMAGE_COUNT_MAX env var, default 100.
Users who genuinely need 600 (older Claude 1/2/Instant models) can
set it explicitly. Dropped the 200K prefix list, dropped the
model_classification_unknown_count telemetry counter. Pass 3 keeps
a one-line claude-opus-4-7 prefix check for native cap selection.
Also addressed Codex's two non-blocking notes:
- Removed the unfounded "server's default Lanczos" claim (server-side
algorithm is not documented; the directive only establishes that
it's blind from the client's perspective).
- Tightened the package.json rationale to focus on "no install
requirement" rather than "prevents npm warnings."
Ref #87
* Add Codex rereview for PR 88 directive
* feat: implement image-guard pipeline (#87) per directive
v3.3.0 image-guard pipeline. Replaces v3.2.1's static MAX_DIM with a
conditional pipeline that mirrors Anthropic's actual rules:
- Pass 0 (back-compat): KEEP_LAST tool_result strip
- Pass 3 (opt-in via PRESERVE_DETAIL=1): Lanczos resize via sharp,
preserves aspect ratio and media type, native cap 2576px Opus 4.7
or 1568px otherwise
- Pass 1: conditional rejection-cap strip (2000px when count > 20,
8000px otherwise; MAX_DIM overrides)
- Pass 2: request-size guard (default 30 MB budget, 2 MB headroom
from Anthropic's 32 MB ceiling)
- Hard image-count cap (default 100)
Execution order: Pass 0 → Pass 3 → Pass 1 → Pass 2 → count cap.
Each pass is independent — Pass 1 never resizes; Pass 3 never strips.
Activation:
- Pipeline gated by CACHE_FIX_IMAGE_GUARD=1 (top-level)
- Pass 3 additionally gated by CACHE_FIX_IMAGE_PRESERVE_DETAIL=1
- Legacy KEEP_LAST and MAX_DIM continue to work standalone for v3.2.1
users — no breaking changes
- Extension activation pattern: enabled:true in extensions.json,
runtime env-var gates inside (matches overage-warning shape)
`sharp` is declared only in peerDependenciesMeta as optional. The
proxy never imports it at module load; runtime `await import("sharp")`
in Pass 3 handles MODULE_NOT_FOUND cleanly. Without sharp, Pass 3
sets library_missing telemetry and skips; Pass 1 + Pass 2 still run.
Telemetry: ctx.meta.imageGuardStats carries the full counter set
(counts + bytes + estimated tokens + library_missing flag). One stderr
line per processed request when the pipeline did anything observable.
New files:
- proxy/image-resize.mjs — lazy sharp wrapper
- test/proxy-image-guard.test.mjs — 42 tests covering directive's
test plan (activation, every Pass, count cap, every precedence
matrix row, telemetry shape, sharp-unavailable + sharp-throws
fallbacks). Sharp tests use injected fake — no real install needed.
Modified:
- proxy/extensions/image-strip.mjs — extended; legacy paths unchanged
- proxy/extensions.json — register image-strip at order 150
- package.json — version 3.3.0; sharp peerDependenciesMeta optional
- README.md — pipeline section + precedence matrix + tunables table
- docs/extension-impact-guide.md — extension #9 image-strip section
Tests: 595/595 pass (42 new + 553 existing). All v3.2.1 legacy paths
unchanged; back-compat regression coverage explicit.
* Add Codex implementation review for PR 88
* fix: address Codex implementation review blockers (#88)
Codex review found 2 blockers + 1 telemetry-drift note. All addressed:
1. README precedence matrix is now verbatim from the directive. Ten rows
restored to the directive's exact wording instead of paraphrased
shorthand. The matrix shipped in README.md must match
docs/directives/proxy-image-guard-pipeline.md verbatim per the
directive's reviewer checklist.
2. Pass 1-only mutations now emit the [image-guard] stderr summary.
Added images_stripped_pass1 counter to imageGuardStats, increment it
in runPass1RejectionCapStrip on each strip, and include it in the
onRequest didSomething check + summary line. Reproducer from Codex's
review (single 9000x9000 PNG, IMAGE_GUARD=1, sonnet model) now emits
"[image-guard] stripped=1 ..." correctly.
3. (Note, not blocker) request_bytes_after now recomputed after the
count-cap pass. Without this, count-cap-only requests reported
pre-trim byte totals — telemetry drift, not enforcement drift, but
misleading on T20/T21-style requests. runImageCountCap re-measures
the body after evictions and updates request_bytes_after /
request_bytes_headroom.
New tests:
- T34a: Pass 1-only stripping emits stderr summary
- T34b: count-cap-only request reports updated request_bytes_after
Tests: 597/597 pass (2 new + 595 existing).
* Add Codex rereview artifact for PR 88 implementation
Reconstructs vsits-codex-review-agent's rereview verdict from its PR
comment because the bot's push to feature/image-guard-pipeline was
blocked with 403 (recurring permission gap on this App's installation).
The verdict text matches the bot's PR comment dated 2026-04-30T13:32:01Z
verbatim. The bot's local commit was 775666f; that commit could not be
pushed, so committing here as AI Team Lead.
See PR #88 comment thread for the original verdict author signature.
---------
Co-authored-by: vsits-proxy-builder[bot] <279815601+vsits-proxy-builder[bot]@users.noreply.github.com>
1 parent cba8d36 commit da5f3d6
14 files changed
Lines changed: 2328 additions & 41 deletions
File tree
- docs
- code-reviews
- directives
- proxy
- extensions
- test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
334 | 334 | | |
335 | 335 | | |
336 | 336 | | |
337 | | - | |
| 337 | + | |
338 | 338 | | |
339 | 339 | | |
340 | 340 | | |
| |||
355 | 355 | | |
356 | 356 | | |
357 | 357 | | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
358 | 412 | | |
359 | 413 | | |
360 | 414 | | |
| |||
Lines changed: 28 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
Lines changed: 34 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
Lines changed: 33 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
0 commit comments