Skip to content

chore(devex): nudge when a change pushes a file past 1000 lines - #92275

Merged
trunk-io[bot] merged 12 commits into
masterfrom
chore/devex-file-size-nudge
Sep 2, 2026
Merged

chore(devex): nudge when a change pushes a file past 1000 lines#92275
trunk-io[bot] merged 12 commits into
masterfrom
chore/devex-file-size-nudge

Conversation

@webjunkie

@webjunkie webjunkie commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Problem

Nothing tells an author when a change turns a readable file into one that costs an agent a large share of its context window just to open. An agent reads a file, not a function, so file length is what decides the token cost of every later change to it.

PR #91305 shipped the cyclomatic complexity signal and named file and module size as the other thing this repo has never measured. This is that half.

The obvious version does not work. Warning about every oversized file in a diff fires on most commits, because touching a big file is normal, and a warning that common becomes wallpaper. That is the same shape that forced #91305 to drop its error tier.

Changes

  • hogli lint:size warns when the diff itself pushed a file past 1000 lines, and points at /splitting-oversized-modules. Only that case is something the author can act on in the change they are making, so it stays uncommon.
  • Files that were already oversized get one note naming the largest of them, priced in tokens to read. One note, not a list.
  • The check runs as a soft DiffCheck in ci:preflight, so it reaches the author at push time. It never fails a build.
  • Git rename detection is on. Reading the destination path at the merge base returns nothing, so without it a relocated file reads as newly created and every product migration gets nudged for tidying up.
  • Function length is deliberately not checked. Splitting a long function moves the same bytes rather than removing them, and complexity already covers the case that hurts.
  • The .claude/hooks and quill AGENTS.md reminders now actually print. Both were lint-staged tasks, and lint-staged discards stdout and stderr from every task that exits 0, so both have been silent since they landed.
  • AGENTS.md said .claude/hooks/ changes trigger a lint-staged warning. It now names the hook, and says why a warn-only check cannot be a lint-staged task.
  • Mechanical: shellcheck.yml gains a step that lints the two scripts and runs their test. It skips when the test file is absent, so a PR that has not rebased onto this commit is unaffected.

Nothing here changes a UI.

Commit-time warnings, before

flowchart LR
    C{{git commit}} --> H[pre-commit hook body]
    C --> L[lint-staged tasks]
    H --> V[visible to author]
    L --> X[discarded on exit 0]
    classDef phBlue fill:#1d4aff,stroke:#1d4aff,color:#fff;
    classDef phYellow fill:#f9bd2b,stroke:#f9bd2b,color:#000;
    classDef phRed fill:#f54e00,stroke:#f54e00,color:#fff;
    class H,L phBlue
    class C,V phYellow
    class X phRed
Loading

After

flowchart LR
    C{{git commit}} --> H[pre-commit hook body]
    C --> L[lint-staged tasks]
    H --> V[visible to author]
    L --> F[formatters and fixers only]
    P{{git push}} --> PF[ci:preflight soft checks]
    PF --> V
    classDef phBlue fill:#1d4aff,stroke:#1d4aff,color:#fff;
    classDef phYellow fill:#f9bd2b,stroke:#f9bd2b,color:#000;
    class H,L,PF phBlue
    class C,P,V,F phYellow
Loading

How did you test this code?

tools/hogli-commands/hogli_commands/tests/test_size_lint.py builds a real temporary git repo per case, so the merge-base and rename plumbing runs for real rather than through mocks.

Each group names a regression no existing test catches:

  • Boundary cases, parameterized: a file that was already over the line must stay quiet. That is the entire reason the check is framed around crossings, and a naive absolute check passes every other test while failing this one.
  • A renamed file must not read as newly created.
  • Two oversized files must produce one note, not two.
  • The CLI must exit 0 with output on stdout, because that is the contract ci:preflight reads a soft check through.
  • Out-of-scope and generated paths must never be counted.

check-commit-warnings.test.sh covers the two shell scripts. The large-index case is the point: a match early in a long staged list closes the pipe before git finishes writing it, and under pipefail the warning has to survive that.

Manual checks, run locally:

  • bin/hogli lint:size against real oversized files prints the note, and against normal files prints nothing.
  • bin/hogli ci:preflight passes in both modes on this branch. The size check does not trigger here, because every file this PR touches is out of its scope.
  • The devex semgrep rules run clean on the changed module, in the pinned image CI uses.
How the lint-staged behavior was confirmed

A scratch repo with a task that prints to both streams and exits 0. Default run shows [COMPLETED] and no output; --verbose shows both lines. Installed version is lint-staged 15.4.3.

Not run: CI itself, and the crossing path against a real branch, because no file in scope changed here. The unit tests cover that path.

Automatic notifications

  • Publish to changelog?

Docs update

None. The behavior is self-describing at the point it fires.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Built with Claude Code. Skills invoked: /writing-tests, /writing-code-comments, /writing-pr-descriptions, /simplify.

The session started as research into file and function size limits for agents, and two proposals died on the way here. Function-length limits went first: reading the functions a line rule would flag showed they are dispatch tables and literal lists, where splitting adds indirection without removing bytes. Ruff's PLR0915 went second, because most of its findings already trip C901 and it misses the majority of functions over a hundred lines, so it measures statements rather than the thing that costs tokens.

A baseline file was also considered and dropped. Git already holds the previous size of every file, so the check needs no checked-in state to tell a new problem from an old one.

The percentages behind the "fires on most commits" claim came from replaying several hundred squashed PR commits on master and comparing each framing. They are kept out of this description on purpose.

Most of the diff after the first push came from bot review. The recurring defect was namespace confusion in the git plumbing: which base to compare against, which copy of a file to measure, and which rename map applies to which path. Three findings were declined, one of them after building the scenario and confirming git emits no rename records for it.

https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo

An agent reads a file, not a function, so file length is what decides the token
cost of making a change. Function length is a different story and is left alone
here: splitting a long function moves the same bytes around instead of removing
them, and cyclomatic complexity already covers the case that hurts.

Warning about every oversized file would fire on most commits, and a warning
that common turns into wallpaper. This warns only when the diff itself pushed a
file over the line, which is uncommon and is always something the author can act
on in the change they are making. Files that were already oversized get a single
note naming the largest one, priced in tokens, so the reading cost stays visible
without printing a list.

Runs as a soft check in ci:preflight beside the complexity lint, scoped through
changed_files so the two cannot drift, and never fails a build. Rename detection
is on because reading the destination path at the merge base gives nothing, so
without it a relocated file looks newly created and every product migration gets
nudged for tidying up.

Claude-Session: https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo
… hook

lint-staged discards stdout and stderr from every task that exits 0, so a
warn-only task there prints nothing at all. The .claude/hooks reminder and the
quill AGENTS.md reminder have both been silent since they landed, which is a
neat trick for the one telling authors to prefer lint-staged rules over Claude
Code hooks.

The pre-commit hook already runs three warn-only scripts with `|| true` for this
exact reason, and says so in a comment. These two now follow that pattern and
match their own staged paths instead of relying on a lint-staged glob.

Claude-Session: https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo
@webjunkie webjunkie self-assigned this Sep 1, 2026
@trunk-io

trunk-io Bot commented Sep 1, 2026

Copy link
Copy Markdown

😎 Merged directly without going through the merge queue, as the queue was empty and the PR was up to date with the target branch - details.

@webjunkie
webjunkie marked this pull request as ready for review September 1, 2026 09:49
Copilot AI lite review requested due to automatic review settings September 1, 2026 09:49
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T06:32:56.519156Z b86df84 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

🚨 Trunk lane — universal lane

This PR is assigned to the universal lane. It cannot merge in parallel with other PRs, so it can take longer to merge. Ask dev-ex if you think this is wrong.

Bundle size — no change

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 68.18 MiB · no change

No file changed by more than 1000 B.

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

Eager graph — within budget

How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.

Root Eager (shipped) Δ vs base Budget
entry (logged-out pages, app bootstrap)
src/index.tsx
1.44 MiB · 22 files no change ███░░░░░░░ 32.0% of 4.51 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
8.85 MiB · 3,249 files no change █████████░ 91.1% of 9.71 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx

Largest files eagerly shipped from src/index.tsx
Size File
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
6.3 KiB ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js
4.5 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
3.9 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.4 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.3 KiB src/RootErrorBoundary.tsx
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
789 B src/scenes/ChunkLoadErrorBoundary.tsx
762 B src/index.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
307.0 KiB ../node_modules/.pnpm/posthog-js@1.422.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
267.7 KiB ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
263.5 KiB ../node_modules/.pnpm/posthog-js@1.422.5_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.js
256.1 KiB src/taxonomy/core-filter-definitions-by-group.json
154.2 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
126.8 KiB ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js
104.7 KiB src/lib/api.ts
95.2 KiB ../packages/quill/packages/quill/dist/index.js
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
90.6 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js

Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479

Toolbar bundle — eager 2.26 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.26 MiB · 18 files no change ████░░░░░░ 39.6% of 5.72 MiB
Deferred (lazy) 2.11 MiB · 45 files no change n/a — loads on demand
Loader dist/toolbar.js 1.1 KiB no change █░░░░░░░░░ 5.8% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
752.2 KiB dist/toolbar/toolbar-app-WSMUB6BA.css
590.3 KiB dist/toolbar/chunk-chunk-PM4Z562B.js
484.7 KiB dist/toolbar/chunk-chunk-OTPWDCQE.js
134.1 KiB dist/toolbar/chunk-chunk-H2DYTHK5.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
71.3 KiB dist/toolbar/toolbar-app-2WME6WBO.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-UQ3KI6QW.js
21.0 KiB dist/toolbar/chunk-chunk-YKSM6PG7.js
6.8 KiB dist/toolbar/chunk-chunk-DV7IWQNF.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

Dist folder size — no change

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 1459.33 MiB · no change

⚠️ Playwright — 1 failed

🎭 Playwright report · View test results →

1 failed test:

  • Hover chart to see tooltip with data point values (chromium)

These issues are not necessarily caused by your changes.
Annoyed by this section? Help fix flakies and failures and it will go green!

ClickHouse migration SQL — none

No ClickHouse migrations in the latest push.

Copilot AI 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.

Pull request overview

Adds a new devex signal to help keep files from silently growing beyond a “readable for agents” threshold by warning only when a diff crosses 1000 lines, plus wiring it into hogli ci:preflight as a soft check. It also moves two previously-silent lint-staged warnings into the Husky pre-commit hook so they actually print.

Changes:

  • Introduce hogli lint:size (warn-only) that reports threshold crossings and a single “already huge” note with an estimated token cost.
  • Wire the size lint into hogli ci:preflight as a soft DiffCheck so it shows as a warning at push time.
  • Move .claude/hooks and quill AGENTS.md reminder warnings out of lint-staged into .husky/pre-commit via new scripts.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tools/hogli-commands/hogli_commands/size_lint.py Implements the size lint command, scope filtering, rename detection, and reporting/output contract.
tools/hogli-commands/hogli_commands/tests/test_size_lint.py Adds pytest coverage for crossings vs pre-existing oversize, rename detection, “single note” behavior, CLI contract, and scope exclusions.
tools/hogli-commands/hogli_commands/ci_preflight.py Adds a new soft DiffCheck for file size linting based on the shared scope.
hogli.yaml Registers the new lint:size command in the hogli manifest.
package.json Removes the warn-only lint-staged tasks that were previously silent due to lint-staged stdout/stderr behavior.
.husky/pre-commit Runs the new warning scripts directly from Husky so the messages are visible to authors.
.github/scripts/check-quill-agents-md.sh New pre-commit warning script for quill source changes without an AGENTS.md update.
.github/scripts/check-claude-hooks.sh New pre-commit warning script when .claude/hooks/ is touched.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tools/hogli-commands/hogli_commands/size_lint.py
Comment thread tools/hogli-commands/hogli_commands/size_lint.py Outdated
chatgpt-codex-connector[bot]

This comment was marked as outdated.

Three gaps from bot review, all cases where the check and its caller disagreed
about which change they were looking at.

Preflight picks changed files relative to `--against`, but ran `hogli lint:size`
without it, so the child resolved its own base. On a stacked branch that blamed
the current layer for a crossing that happened in the layer below. DiffCheck
gained a `takes_base` flag and preflight now forwards the base it already
computed.

Naming a base is a question about committed history, so the size is now read
from the HEAD blob rather than the working tree, falling back to disk for files
that are not committed yet. Under the pre-push hook the diff carries only
commits, so an uncommitted edit no longer moves the reported number away from
what the push contains.

Rename detection read only the committed range, so a staged `git mv` had no
source to resolve and its destination looked like a new file over the
threshold. The index is now a second rename source. A move that is neither
committed nor staged stays undetectable, because git has no rename to report
until one side is recorded.

Also drops a degraded-run message that promised more than it reported.

Claude-Session: https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo
chatgpt-codex-connector[bot]

This comment was marked as outdated.

@trunk-io

trunk-io Bot commented Sep 1, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

The previous commit tied "which copy of the file to read" to "was a base
named", which was wrong. Preflight forwards the base on every run, so an
advisory run started reading the HEAD blob as well, and a file grown past the
threshold in the working tree reported nothing.

Those are two questions, so they are now two flags. `--against` says which base
to compare against. `--committed` says to measure the committed file. Preflight
passes the base always and `--committed` only under `--strict`, matching the
scope it already picks for changed files: a push carries only commits, while an
advisory run keeps the working tree in scope and has to measure it.

Claude-Session: https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo
chatgpt-codex-connector[bot]

This comment was marked as outdated.

…ook doc

Preflight defaulted the forwarded base to origin/master, but change detection
falls back from origin/master to local master. In a clone without the remote
ref the two disagreed, the child could not resolve a merge base, and the check
silently reported nothing. The base is now forwarded only when it was given
explicitly, so the child repeats the same fallback.

AGENTS.md still told contributors that .claude/hooks changes trigger a
lint-staged warning, which stopped being true when that warning moved into the
pre-commit hook. It now names the right mechanism, keeps settings.json with
lint-staged where it belongs, and says why a warn-only check cannot be a
lint-staged task.

Claude-Session: https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo
chatgpt-codex-connector[bot]

This comment was marked as outdated.

Both warn-only scripts piped the staged file list straight into `grep -q`. With
a long list, grep exits at the first match, git gets SIGPIPE, and under pipefail
the whole pipeline reads as failed, so the warning never printed. A test written
against the old scripts reproduces it. They now capture the list into a variable
and match with a herestring, so there is no pipeline left to fail.

shellcheck.yml gains a step that lints both scripts and runs the new test. It
skips when the test file is absent, so an open PR that has not rebased onto this
commit does not fail there before its own checks run.

`lint:size` now resolves an explicit `--against` itself. Passing files bypasses
change detection, which is what normally rejects a bad ref, so a typo used to
read as "no base available" and quietly turn crossing detection off.

Claude-Session: https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo
chatgpt-codex-connector[bot]

This comment was marked as outdated.

A file renamed in a commit and again in the index produces two separate rename
records, so a single lookup landed on the intermediate name. That name does not
exist at the merge base, so the file read as new and the move was blamed for a
crossing it did not cause. Rename resolution now walks the chain back to the
base path, with a guard so a cycle cannot loop.

Validating that `--against` resolves was too weak: a ref can resolve and still
share no history, which leaves nothing to compare against and turned crossing
detection off without saying so. The check is now the merge base itself, so an
unrelated commit fails the same way a typo does.

Claude-Session: https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo
chatgpt-codex-connector[bot]

This comment was marked as outdated.

`--committed` scoped the measurement but not the file selection, so running the
command directly still picked up staged and untracked work. Those paths have no
blob at the revision being measured, so they fell back to disk and reported
content the caller had asked not to see. Discovery now drops the working tree in
committed mode, and a path with no blob counts as zero instead of falling back.

Claude-Session: https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo
chatgpt-codex-connector[bot]

This comment was marked as outdated.

…ed map

Unioning the index and committed rename maps flattened two namespaces into one.
A pathname freed by one rename and taken by another connected two unrelated
files, so a large file could be compared against a small file's baseline and
report a crossing that never happened.

The maps are kept apart and applied in order: index path to its name at HEAD,
then HEAD path to its name at the merge base. Neither is consulted for the
other's namespace, which also drops the chain walk and its cycle guard.

Claude-Session: https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 480ab4462d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tools/hogli-commands/hogli_commands/size_lint.py Outdated
semgrep's tuple-return-prefer-dataclass caught this: the two maps share a type,
so `staged, committed = _rename_maps(base)` could be swapped at the call site
and nothing would notice. Swapping them silently resolves paths through the
wrong namespace, which is the bug the two maps exist to avoid.

They are now fields on a frozen RenameMaps, and the resolution moves onto it as
a method, so the hop order lives with the data it applies to.

Claude-Session: https://claude.ai/code/session_01LEZFeFHxVkeCbYNnxaWXKo
@webjunkie webjunkie added the stamphog Request AI approval (no full review) label Sep 1, 2026

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

Not approved yet — waiting on the conditions below.

Re-add the stamphog label to request another review once you have addressed this.

Gates denied this as T2-never for touching CI/infra tooling (workflows, husky hooks); despite the author being on the owning devex team, changes to CI pipeline behavior warrant explicit human sign-off rather than automated approval.

  • 👍 on the PR from chatgpt-codex-connector[bot].
  • Modifies .github/workflows/shellcheck.yml and .husky/pre-commit, which is CI/infra-tooling territory that the deny-list flags for mandatory human review regardless of size.
  • Gate tier classified this as T2-never (cross-cutting, 668 lines/11 files), explicitly excluded from automated approval.
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list matches: infra_cicd
size 338L, 8F substantive, 668L/11F incl. docs/generated/snapshots — within ceiling
tier classified as T2-never: T2-never (668L, 11F, cross-cutting, chore)
stamphog 2.0.0b4 .stamphog/policy.yml @ 03a257c · reviewed head 03a257c

@stamphog stamphog Bot removed the stamphog Request AI approval (no full review) label Sep 1, 2026
@webjunkie
webjunkie requested a review from pauldambra September 1, 2026 11:43
@@ -0,0 +1,244 @@
"""File-size nudge, scoped to changed files.

An agent reads a file, never a function, so file length is what decides how many

@gantoine gantoine Sep 1, 2026

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.

An agent reads a file, never a function

so unnecessary lol

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b86df841f1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if rev is not None:
result = _git("show", f"{rev}:{path}")
return 0 if result.returncode != 0 else len(result.stdout.splitlines())
return len((REPO_ROOT / path).read_text(errors="replace").splitlines())

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 Badge Inspect staged contents before reporting no crossing

When a file has more than 1,000 lines staged but is subsequently edited back below the threshold in the worktree, ordinary lint:size and non-strict preflight select the path because the index changed but always count the on-disk copy here. The command therefore reports no crossing even though committing without restaging records the oversized index blob; inspect the index as well as the worktree so either pending version can trigger the advisory.

Useful? React with 👍 / 👎.

Comment on lines +152 to +153
result = _git("show", f"{rev}:{path}")
return 0 if result.returncode != 0 else len(result.stdout.splitlines())

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 Badge Batch blob reads for large committed diffs

When a refactor changes hundreds of in-scope files, strict preflight spawns a separate git show HEAD:<path> process here for every path before it can discard files below the threshold, and oversized files incur another subprocess for their base content. Running this exact pattern over 500 tracked files locally took about nine seconds, adding linear latency to every pre-push check for large diffs; use a single git cat-file --batch process or another batched blob reader.

Useful? React with 👍 / 👎.

@trunk-io
trunk-io Bot merged commit e97a7c4 into master Sep 2, 2026
230 checks passed
@trunk-io
trunk-io Bot deleted the chore/devex-file-size-nudge branch September 2, 2026 06:35
@deployment-status-posthog

deployment-status-posthog Bot commented Sep 2, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-09-02 06:53 UTC Run
prod-us ✅ Deployed 2026-09-02 07:03 UTC Run
prod-eu ✅ Deployed 2026-09-02 07:05 UTC Run

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.

4 participants