Skip to content

build: name the source-archive ceilings in the context check (SUP2-1094) - #388

Merged
jwfing merged 3 commits into
mainfrom
fix/sup2-1094-build-archive-ceiling
Nov 6, 2026
Merged

jwfing merged 3 commits into
mainfrom
fix/sup2-1094-build-archive-ceiling

Conversation

@jwfing

@jwfing jwfing commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Fixes SUP2-1094. insta build --json said needs-attention with only a "large context" warning at 315.3 MB. The 256 MiB compressed upload cap first showed up at insta deploy, after packing (307.7 MiB > 256.0 MiB).

What changes

The context check in insta build now measures the context against the archive lane's limits (pack.ts ARCHIVE_LIMITS). Build stays offline, so these are labelled as defaults; the server's negotiated figures still win at deploy.

Case Message
over the extracted-size or entry limit, too large for insta deploy <dir>: …
already-compressed files (.gz/.xz/.zip/images/video…) alone, or payload plus tar headers/padding, over the upload limit ships only if it compresses below the cap (extension-based estimate, never a certain verdict)
uncompressed size over the upload limit X MiB uncompressed (Y of it already compressed) — ships only if it compresses below the cap
under the cap unchanged

Uncompressed bytes alone never make the call, because a large text tree can pack small. When a ceiling applies, the next action also covers intentional large assets: recompress with xz/zstd, or fetch the file at start-up. That's the reporter's case: a checkpoint they ship on purpose.

--json gains archiveLimits: {maxArchiveBytes, maxExtractedBytes, maxFiles, source: "default"}.

Verification

  • npm run typecheck passes. test/build.test.ts passes 41/41, including new cases: 315 MB reported case, compressible vs incompressible, extracted/entry limits, custom limits, compressed-file accounting.
  • Ran it on real directories (300 MiB):
    • random checkpoint.gz → too large for insta deploy <dir>: already-compressed files alone are 300.0 MiB, over the 256.0 MiB compressed upload limit
    • zero-filled data.bin → ships only if it compresses below that
  • npm test: test/setup-agent.test.ts fails 12 tests with ApiError: unauthorized. It fails the same way on unmodified main on my machine (local login state), so this PR doesn't cause it.

Docs: skills insta/cli-reference.md updated in a companion PR.

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

The insta build context check now flags contexts that exceed the deploy archive ceilings at build time, instead of surfacing only at insta deploy after packing.

  • Ceilings are measured against what the packer would actually archive (root .dockerignore, else .gitignore fallback), not the docker context, and count tar headers and gzip framing along with the payload.
  • Over the extracted-size or entry limit → certain failure: too large for insta deploy <dir>. Uncompressed size alone never triggers a certain verdict, since compressible trees can pack well below the cap.
  • Already-compressed files (.gz, .xz, .zip, images, video, etc.) alone over the upload cap → warning that it ships only if it compresses below the cap (extension-based estimate; stored files can still shrink), with guidance to recompress intentional large assets with xz/zstd or fetch them at start-up.
  • Uncompressed size over the cap but compressible → similar warning, noting how much is already compressed and any payload that sits near the limit once tar headers count.
  • --json gains archiveLimits with the default ceilings, labelled as such since build runs offline and the server's negotiated figures still win at deploy.

Written for commit dda44f3. Summary will update on new commits.

View guided diff Turn on auto-fix

`insta build` warned only that a large context is slow; the 256 MiB compressed
upload cap surfaced first at `insta deploy`, after packing. The context check
now measures the context against the archive lane's limits (pack.ts
ARCHIVE_LIMITS, still offline, so labelled as defaults):

- certain: over the extracted-size or entry limit, or already-compressed files
  (by extension) alone over the upload limit -> "too large for insta deploy"
- possible: uncompressed size over the upload limit -> ships only if it
  compresses below it; never a verdict from uncompressed bytes alone
- next action covers intentional large assets (recompress with xz/zstd, or
  fetch at start-up) besides .dockerignore

--json gains `archiveLimits` ({maxArchiveBytes, maxExtractedBytes, maxFiles,
source: "default"}).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All reported issues were addressed across 2 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread src/commands/build.ts Resolved
Comment thread src/commands/build.ts Resolved
…nsions as a certain overflow (SUP2-1094)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="test/build.test.ts">

<violation number="1" location="test/build.test.ts:151">
P3: Keep a positive integration assertion here: this test should verify that `contextCheck` surfaces the already-compressed estimate, not only that it avoids calling it definite. Otherwise the archive-risk detail can disappear while the test still passes because the context is generally oversized.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread test/build.test.ts
expect(f.over).toBeUndefined()
expect(f.maybe).toMatch(/already-compressed files alone are 300\.0 MiB.*likely not fit/)
const c = contextCheck({ ...base, totalBytes: 320 * MiB, incompressibleBytes: 300 * MiB }, limits)
expect(c.detail).not.toContain('too large for')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Keep a positive integration assertion here: this test should verify that contextCheck surfaces the already-compressed estimate, not only that it avoids calling it definite. Otherwise the archive-risk detail can disappear while the test still passes because the context is generally oversized.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At test/build.test.ts, line 151:

<comment>Keep a positive integration assertion here: this test should verify that `contextCheck` surfaces the already-compressed estimate, not only that it avoids calling it definite. Otherwise the archive-risk detail can disappear while the test still passes because the context is generally oversized.</comment>

<file context>
@@ -143,9 +143,23 @@ describe('archive ceiling (SUP2-1094)', () => {
+    expect(f.maybe).toMatch(/already-compressed files alone are 300\.0 MiB.*likely not fit/)
     const c = contextCheck({ ...base, totalBytes: 320 * MiB, incompressibleBytes: 300 * MiB }, limits)
-    expect(c.detail).toMatch(/too large for `insta deploy <dir>`: already-compressed files alone are 300\.0 MiB/)
+    expect(c.detail).not.toContain('too large for')
+    expect(c.status).toBe('fail')
+  })
</file context>
Suggested change
expect(c.detail).not.toContain('too large for')
expect(c.detail).toMatch(/already-compressed files alone are 300\.0 MiB.*likely not fit/)

@jwfing jwfing 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.

verdict=request_changes

Reviewed full head commit: 978486979dc5db1d28d94ea8471922aa455f4d2d (base/merge-base d075ab784457fb9681be09a241fc162b3a783a25).
GitHub event: COMMENT. This is a quality verdict only; no APPROVE or REQUEST_CHANGES event is being submitted.

Scope: full PR diff (src/commands/build.ts, test/build.test.ts), build report/rendering, context walking/ignore rules, pack.ts tar construction and limit enforcement, deploy lane discovery/server limits, pinned fflate compressor, surrounding tests and repository conventions. Assessed against the SUP2-1094 requirements supplied in the review request and PR description: offline upload/extracted/entry warnings, default-sourced JSON limits, no certainty from raw size/extensions, intentional-assets advice, and parity with actual packing.

Findings

Critical (2)

  1. src/commands/build.ts:121: Critical — The new overhead estimate still misses actual near-cap archives. pack.ts uses fflate 0.8.3 gzipSync(..., {level: 9}). Its compressor flushes on symbol thresholds (including >24,576 symbols), so incompressible input can incur stored-block framing more frequently than once per 65,535 bytes. The level-0 stored-block interval is not a safe bound for this level-9 output. In a real directory containing one random data.bin of 268,405,456 bytes, archiveOverheadBytes returned 22,559 and the total estimate was 268,428,015, below the 268,435,456 default cap; archiveFit returned {}. Packing that same directory produced 268,460,038 bytes, and default packDirectory rejected it as too large. Thus build still omits the upload ceiling for a context deploy rejects. Use a conservative bound for the actual pinned compressor (over the tar input), or an explicit near-limit uncertainty margin, and add a regression comparing the estimate with actual packing. This is the remaining case of the prior overhead finding, not resolved by counting tar headers alone.
  2. src/commands/build.ts:133 (also entry branch at 130–131): Critical — Archive certainty is computed from the wrong ignore semantics. These limits are checked against contextStats, which calls contextEntries: it deliberately ignores only .dockerignore. However, packDirectory falls back to root and nested .gitignore when .dockerignore is absent. A directory with Dockerfile, .gitignore containing local.bin, and an ignored sparse local.bin of 1 GiB + 1 byte gets “too large for insta deploy <dir> … over the 1024.0 MiB extracted-size limit” from build. Actual default packing succeeds with 2 entries, 47 extracted bytes, and a 159-byte archive. The same mismatch affects the entry cap and upload estimates. The generic Docker/Fly context scan predates this PR, but applying archive-specific certain-failure claims to it is new. Compute archive-limit statistics using the packer's ignore selection; keep any Docker/Fly context diagnostics separate. Cover the no-.dockerignore/.gitignore fallback in a pack-versus-build regression.

Suggestion (1)

  1. src/commands/build.ts:157 and renderReport (lines 294–322): Suggestion — Label the human-readable ceilings as offline defaults. archiveLimits.source = "default" correctly labels JSON, but normal insta build output prints the ceiling and “too large for insta deploy <dir>” with no default/offline or archive-lane qualification. renderReport never prints the JSON metadata, and deploy actually uses the limits returned by discoverLane. Show a short qualifier that these are offline archive defaults and negotiated server limits win, ideally once per report; verify the rendered output as well as JSON. This would preserve the requested default-limit explanation for users who do not pass --json.

Information (0)

Previous feedback and requirement coverage

  • Prior cubic extension/certain-overflow finding is addressed: upload branches return maybe, not over. A real repetitive 300 MiB stored.zip packed successfully to 307,065 bytes and received only the qualified estimate. Large raw payloads likewise do not become certain upload failures.
  • Prior cubic overhead finding is only partially addressed: tar headers/padding/end blocks are included conservatively, but the compressor framing assumption still permits the reproduced near-limit miss above.
  • JSON retains {maxArchiveBytes: 268435456, maxExtractedBytes: 1073741824, maxFiles: 10000, source: "default"}. Intentional-assets guidance includes xz/zstd or fetching from storage at start-up. No network discovery was introduced in build.
  • Existing cubic feedback on the same head was checked before publication; its separate test-assertion suggestion is not repeated here.

Verification actually executed

  • Dependency setup: npm ci --ignore-scripts --no-audit --no-fund.
  • npm run typecheck: passed.
  • npm test -- test/build.test.ts test/pack.test.ts test/pack-ignore.test.ts: 3 files / 172 tests passed.
  • npm test: 107 files passed; 2268 tests passed, 2 skipped.
  • Scratch-directory execution of actual contextStats, contextCheck, buildReport, renderReport, jsonReport, and packDirectory: reproduced ignored-file false certainty and actual near-cap gzip overflow, verified default rejection, and verified repetitive-extension content remains packable. No implementation or tests were edited.

Limits

The repository has no docs/ or docs/superpowers/ (including specs/plans). Read AGENTS.md, CONTRIBUTING.md, and the referenced development guide. The linked Linear issue was inaccessible; its requirements were taken from the supplied review request and PR description. Read the currently published companion CLI reference, but did not verify the claimed companion documentation PR. Linux/Node verification only; no Windows runtime, production resources, or live deploy/upload were used.

Head was rechecked immediately before submission; this verdict applies only to the full SHA above. A later head requires review of its changes.

Comment thread src/commands/build.ts Outdated
// framing (5 bytes per 64 KiB) for data that does not compress. pack.ts compresses the tar, not the
// bare files, so the upload limit applies to totalBytes plus this.
export function archiveOverheadBytes(ctx: ContextStats, payloadBytes = ctx.totalBytes): number {
return ctx.entries * 1023 + 1024 + Math.ceil(payloadBytes / 65535) * 5 + 32

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.

Critical — The new overhead estimate still misses actual near-cap archives. pack.ts uses fflate 0.8.3 gzipSync(..., {level: 9}). Its compressor flushes on symbol thresholds (including >24,576 symbols), so incompressible input can incur stored-block framing more frequently than once per 65,535 bytes. The level-0 stored-block interval is not a safe bound for this level-9 output. In a real directory containing one random data.bin of 268,405,456 bytes, archiveOverheadBytes returned 22,559 and the total estimate was 268,428,015, below the 268,435,456 default cap; archiveFit returned {}. Packing that same directory produced 268,460,038 bytes, and default packDirectory rejected it as too large. Thus build still omits the upload ceiling for a context deploy rejects. Use a conservative bound for the actual pinned compressor (over the tar input), or an explicit near-limit uncertainty margin, and add a regression comparing the estimate with actual packing. This is the remaining case of the prior overhead finding, not resolved by counting tar headers alone.

Comment thread src/commands/build.ts
if (ctx.entries > limits.maxFiles) {
return { over: `${ctx.entries.toLocaleString('en-US')}${ctx.truncated ? '+' : ''} entries (directories count), over the ${limits.maxFiles.toLocaleString('en-US')}-entry archive limit` }
}
if (ctx.totalBytes > limits.maxExtractedBytes) {

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.

Critical — Archive certainty is computed from the wrong ignore semantics. These limits are checked against contextStats, which calls contextEntries: it deliberately ignores only .dockerignore. However, packDirectory falls back to root and nested .gitignore when .dockerignore is absent. A directory with Dockerfile, .gitignore containing local.bin, and an ignored sparse local.bin of 1 GiB + 1 byte gets “too large for insta deploy <dir> … over the 1024.0 MiB extracted-size limit” from build. Actual default packing succeeds with 2 entries, 47 extracted bytes, and a 159-byte archive. The same mismatch affects the entry cap and upload estimates. The generic Docker/Fly context scan predates this PR, but applying archive-specific certain-failure claims to it is new. Compute archive-limit statistics using the packer's ignore selection; keep any Docker/Fly context diagnostics separate. Cover the no-.dockerignore/.gitignore fallback in a pack-versus-build regression.

Comment thread src/commands/build.ts Outdated
: `${size}${tooBig ? ' — large contexts make remote builds slow' : ''}`
const bad = shipsNodeModules || tooBig || ctx.truncated
: `${size}${tooBig && !fit.over && !fit.maybe ? ' — large contexts make remote builds slow' : ''}`
const ceiling = fit.over ? `too large for \`insta deploy <dir>\`: ${fit.over}` : fit.maybe

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.

Suggestion — Label the human-readable ceilings as offline defaults. archiveLimits.source = "default" correctly labels JSON, but normal insta build output prints the ceiling and “too large for insta deploy <dir>” with no default/offline or archive-lane qualification. renderReport never prints the JSON metadata, and deploy actually uses the limits returned by discoverLane. Show a short qualifier that these are offline archive defaults and negotiated server limits win, ideally once per report; verify the rendered output as well as JSON. This would preserve the requested default-limit explanation for users who do not pass --json.

…und gzip framing, label defaults (SUP2-1094)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/commands/build.ts">

<violation number="1" location="src/commands/build.ts:117">
P3: `contextStats` walks every file twice when `.dockerignore` exists, even though both functions use the same archive selection. Reuse the first tally for that case.</violation>
</file>

<file name="src/pack.ts">

<violation number="1" location="src/pack.ts:202">
P2: `archiveEntries` discards the packer’s symlink errors, so `insta build` can report a clean context even though the corresponding deploy always fails. Preserve the link list and surface `linkError` (or expose the condition to the context check).</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread src/pack.ts
export function archiveEntries(absDir: string, cap = Infinity): Found[] {
const entries: Found[] = []
const { ig, files, flavour } = rootIgnore(absDir)
walk(absDir, '', entries, [], ig, files, flavour, cap)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: archiveEntries discards the packer’s symlink errors, so insta build can report a clean context even though the corresponding deploy always fails. Preserve the link list and surface linkError (or expose the condition to the context check).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/pack.ts, line 202:

<comment>`archiveEntries` discards the packer’s symlink errors, so `insta build` can report a clean context even though the corresponding deploy always fails. Preserve the link list and surface `linkError` (or expose the condition to the context check).</comment>

<file context>
@@ -193,6 +193,16 @@ export function contextEntries(absDir: string, cap = Infinity): Found[] {
+export function archiveEntries(absDir: string, cap = Infinity): Found[] {
+  const entries: Found[] = []
+  const { ig, files, flavour } = rootIgnore(absDir)
+  walk(absDir, '', entries, [], ig, files, flavour, cap)
+  return entries
+}
</file context>
Suggested change
walk(absDir, '', entries, [], ig, files, flavour, cap)
const links: { path: string; target: string }[] = []
walk(absDir, '', entries, links, ig, files, flavour, cap)
if (links.length) throw linkError(links)

Comment thread src/commands/build.ts
Comment on lines +117 to 123
const { stats, nodeModulesBytes } = tally(contextEntries(dir, cap + 1), cap)
return {
...stats,
nodeModulesBytes,
hasDockerignore: existsSync(join(dir, '.dockerignore')),
archive: tally(archiveEntries(dir, cap + 1), cap).stats,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: contextStats walks every file twice when .dockerignore exists, even though both functions use the same archive selection. Reuse the first tally for that case.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/commands/build.ts, line 117:

<comment>`contextStats` walks every file twice when `.dockerignore` exists, even though both functions use the same archive selection. Reuse the first tally for that case.</comment>

<file context>
@@ -100,33 +110,39 @@ export function contextStats(dir: string, cap = WALK_CAP): ContextStats {
+}
+
+export function contextStats(dir: string, cap = WALK_CAP): ContextStats {
+  const { stats, nodeModulesBytes } = tally(contextEntries(dir, cap + 1), cap)
   return {
-    totalBytes,
</file context>
Suggested change
const { stats, nodeModulesBytes } = tally(contextEntries(dir, cap + 1), cap)
return {
...stats,
nodeModulesBytes,
hasDockerignore: existsSync(join(dir, '.dockerignore')),
archive: tally(archiveEntries(dir, cap + 1), cap).stats,
}
const hasDockerignore = existsSync(join(dir, '.dockerignore'))
const context = contextEntries(dir, cap + 1)
const { stats, nodeModulesBytes } = tally(context, cap)
return {
...stats,
nodeModulesBytes,
hasDockerignore,
archive: hasDockerignore ? stats : tally(archiveEntries(dir, cap + 1), cap).stats,
}

@jwfing jwfing 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.

verdict=approved

Reviewed full head SHA: dda44f39ea8ac3a52b5f1c4954591c27c5683a0f.
Base/merge-base: d075ab784457fb9681be09a241fc162b3a783a25.
Review round: 2/10.
GitHub event: COMMENT. “approved” is this reviewer's quality judgment only; this review does not grant GitHub approval. Human approval is still required.

Scope and findings

Independently reviewed the complete PR change against SUP2-1094 and rechecked every finding from round 1. Scope includes build statistics/report/rendering/JSON, the new archive walker, packer ignore selection, tar construction, pinned fflate compression, deploy lane/server-limit discovery, and related tests and repository conventions.

  • Critical: 0
  • Suggestion: 0
  • Information: 0

No actionable issues found in this reviewed scope. This does not guarantee the absence of defects.

Resolution of previous findings

  1. Near-limit gzip overhead miss: addressed. Repeated the real-directory case with a single random file of exactly 268,405,456 bytes. Actual packDirectory output was 268,460,040 bytes, over the 268,435,456-byte default cap. The new estimate was 268,676,935 bytes and archiveFit correctly returned maybe, without claiming certain failure.

    Independently checked more than the empirical random-data ratio: the installed, exactly pinned fflate 0.8.3 implementation's gzipSync path calls dflt with a 10-byte gzip header and 8-byte trailer, allocating at most t + 5*(1 + ceil(t/7000)) + 18 bytes for tar input length t; its final slice cannot exceed that buffer. The new ceil(t/1000) + 1024 compression allowance exceeds that allocation overhead for every nonnegative integral t: checked the first 7000-byte period (minimum spare margin 997 bytes), and each following period increases the spare margin by 2 bytes. The tar estimate also conservatively covers each header/padding plus the closing blocks. Thus the current allowance has a source-based upper-bound justification for this pinned implementation, beyond its measured ~0.02% random-data expansion. It is not a general guarantee for future compressors or dependency changes.

  2. Wrong ignore semantics for archive certainty: addressed. archiveEntries shares rootIgnore and walk with packDirectory; contextCheck now evaluates archive ceilings using those archive statistics. Repeated the root .gitignore regression with an excluded sparse 1 GiB + 1-byte file: archive statistics matched the successful pack (2 entries, 47 extracted bytes, 159 compressed bytes), with no “too large for” archive claim. Also verified nested .gitignore fallback and root .dockerignore precedence against actual packing. The existing generic Docker-context size warning remains separate from archive certainty.

  3. Human-readable offline-default qualification: addressed. Ran buildReport followed by actual renderReport, not just a check-detail assertion. The rendered upload warning includes [archive limits are offline defaults — the server's limits win at deploy], and the next action includes xz/zstd and fetching intentional assets at start-up. Verified the qualifier also appears for the extracted-size warning. jsonReport retains all three default ceilings with source: "default".

The earlier cubic extension/certain-failure issue also remains fixed: a real 300 MiB repetitive stored.zip packed successfully to 307,146 bytes and was classified only as maybe. Neither raw size nor extension-matched bytes alone causes a certain upload failure.

Verification actually executed

  • npm run typecheck: passed.
  • npm test: 107 test files passed; 2271 tests passed, 2 skipped.
  • Independent scratch-directory assertions using actual contextStats, archiveEntries, archiveFit, packDirectory, buildReport, renderReport, and jsonReport: all passed.
  • Compared actual packing with the estimate for 6 MiB random, zero-filled, low-alphabet, and mixed random/zero data. All outputs were below the estimate. A limit one byte below each actual archive produced maybe; a limit 1% above the random archive produced no archive warning.
  • Tested actual 10,001-entry and >1 GiB extracted-size directories: both archive diagnostics and the packer's early rejection agreed.
  • Repeated the full-size near-upload-cap regression, root/nested ignore selection, Docker-ignore precedence, rendering/default-limit JSON, and compressible .zip behavior described above.

Verification used Linux/Node and local scratch data; no production resources, live upload/deploy, implementation edits, or merges were used.

Review limits

The repository has no docs/ or docs/superpowers/ directory (including specs/plans). Repository instructions and development guidance were consulted. The linked Linear issue was inaccessible in the preceding round; requirements were taken from the supplied unchanged SUP2-1094 acceptance criteria and PR description. The claimed companion documentation PR was not verified. No Windows runtime was exercised.

Head was checked immediately before submission. This quality judgment applies only to the full SHA above; later commits need their own review.

@Fermionic-Lyu Fermionic-Lyu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, Approved.

@Fermionic-Lyu Fermionic-Lyu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, Approved.

@jwfing
jwfing merged commit 24f72ec into main Nov 6, 2026
3 checks passed
@jwfing jwfing mentioned this pull request Nov 6, 2026
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.

2 participants