Skip to content

feat(stamphog): bound the whole PR by the most generous ceiling in play - #92116

Merged
trunk-io[bot] merged 10 commits into
masterfrom
feat/stamphog-size-gate-roof
Sep 1, 2026
Merged

feat(stamphog): bound the whole PR by the most generous ceiling in play#92116
trunk-io[bot] merged 10 commits into
masterfrom
feat/stamphog-size-gate-roof

Conversation

@webjunkie

@webjunkie webjunkie commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Problem

Stamphog can auto-review a PR of 1800 substantive lines once #91348 lands. The size gate was calibrated to escalate past ~800.

  • feat(stamphog): make size_gate.max_lines delegable per folder #91348 makes size_gate.max_lines delegable and checks every budget per scope. It removes the whole-PR line total.
  • A PR touching products/desktop/ gets 1000 lines there, plus 800 in the global pool. Every folder that adopts a grant adds another full budget.
  • Scope count is unbounded. Nothing caps how many budgets one PR can hold.
  • The ~800 threshold documented in the agent README came from PR size, not per-folder size. After feat(stamphog): make size_gate.max_lines delegable per folder #91348 no check measures it.
  • Files have the same shape. That part is pre-existing and latent, because only products/visual_review/ grants max_files today.

Changes

Each ceiling now bounds the whole PR, at the most generous ceiling in play for that key.

PR shape on #91348 with this layer
no folder grant 800L 800L
products/desktop/ only 1000L 1000L
products/desktop/ plus global 1800L 1000L
products/desktop/ plus four more granting folders 4800L 1000L
  • A PR author who overruns the roof reads which limit refused it: too large for auto-review (1394L, 49F substantive across the whole PR — roof is 1000L).
  • The roof needs no new key in policy.yml. Every grant is validated at or under the contract ceiling, and the global pool is always a scope.
  • With no folder grant the roof equals the global default. The gate then reduces to the single total it applied before the ceilings became delegable.
  • Per-scope budgets still hold. The headroom a grant unlocks stays spendable only inside the folder that granted it.
  • This tightens the pre-existing files case. A PR with 50 products/visual_review/ files plus more elsewhere now refuses where it passes on master.
  • The policy loader now fails closed when a delegation ceiling sits under its own global default. A repo overlay can replace size_gate while inheriting the overrides contract, and that pairing let the global pool carry the roof past the ceiling.
  • Mechanical: two properties on EffectivePolicy, two comparisons in _check_size, one loader check, and both READMEs.

Nothing in the PostHog app looks different. The only surface a person reads is the stamphog refusal message quoted above.

How did you test this code?

  • test_size_gate_roof_bounds_the_whole_pr covers a PR where every scope fits its own budget but the total does not. No existing test had two scopes that both fit.
  • test_roof_is_the_most_generous_ceiling_in_play covers a roof that ignores the global pool. A folder may grant under the global default, and the roof must not follow it down.
  • _ceiling_under_global_default joins the malformed-policy parametrization. It catches a contract ceiling under its own global default, which no existing case covered.
  • Ran the pr-approval-agent suite and products/stamphog/backend/tests/test_policy_defaults.py locally, plus hogli ci:preflight --strict.
  • Not run: repo-wide mypy, and anything needing the dev stack.

Automatic notifications

  • Publish to changelog?

Docs update

.stamphog/README.md and products/stamphog/packages/pr-approval-agent/README.md are updated here.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Written by Claude Code (Opus 5) at @webjunkie's direction while reviewing #91348. The review flagged the missing whole-PR total, and this layer implements the fix it proposed. Stacking it keeps the delegation work mergeable if a reviewer rejects the roof.

Skills invoked: /posting-pr-reviews, /merging-prs, /stacking-prs, /simplify, /writing-pr-descriptions.

The roof derives from max(scope.ceiling ...) rather than a new policy.yml key. A configured roof is a second number that can drift from the overrides contract. The derived one cannot exceed the contract ceiling.

Codex found the loader gap during review, and Copilot found two doc statements that overstated or trailed off. Those are fixed here. Copilot also flagged the em dash in the refusal messages. Rejected: the three sibling messages in the same function and the whole package use it, so changing two strings would make the gate's output inconsistent with itself.

Considered and rejected: judging the whole PR as one budget at the highest grant on any touched chain. That would let one file in a granting folder raise the ceiling for unrelated code in the same PR. Per-scope budgeting exists to prevent that.

charlesvien and others added 7 commits August 29, 2026 23:31
A folder that granted one size_gate key was given a fresh copy of the other
key's global ceiling, which created a second budget nobody delegated: a
lines-only grant let a PR touch 30 folder files plus 30 global files, and a
files-only grant let it add 800 folder lines plus 800 global lines.

Each ceiling now resolves on its own chain walk. A file counts against the
nearest folder granting that ceiling and against the global pool when the chain
grants it nowhere, so a one-key grant leaves its files in the pool they were
already in for the other key.

Generated-By: PostHog Desktop
Task-Id: dd27894e-233a-469b-ada8-c80d13d67405
Generated-By: PostHog Desktop
Task-Id: dd27894e-233a-469b-ada8-c80d13d67405
The size-gate helpers returned same-typed pairs, which the
tuple-return-prefer-dataclass rule blocks: callers can swap the two scope
tuples, or the two counts, without a type error.

_size_budgets now returns the EffectivePolicy the scopes already live on, and
the per-scope file filter returns the file list so substantive_size stays the
one place that unpacks a count pair.

Generated-By: PostHog Desktop
Task-Id: dd27894e-233a-469b-ada8-c80d13d67405
Per-scope size budgets are checked independently and scope count is unbounded.
A PR touching products/desktop/ plus anything else can reach 1000 substantive
lines in desktop plus 800 in the global pool, and every folder that adopts a
grant adds another full budget on top.

The ~800 threshold documented in the agent README was derived from PR size, not
from per-folder size, so after delegation nothing in the gate measured what that
number describes. Files have the same shape. That part is pre-existing and
latent, because only products/visual_review/ grants max_files today.

Each ceiling now also carries a roof over the whole PR: the most generous
ceiling in play for that key. It needs no new key in policy.yml, since every
grant is already validated at or under the contract ceiling and the global pool
is always a scope. With no grant in play the roof equals the global default, so
the gate reduces to the single global total it applied before the ceilings
became delegable.

Per-scope budgets still hold, so the headroom a grant unlocks stays spendable
only inside the folder that granted it.

This does tighten the pre-existing files case. A PR with 50 visual_review files
plus more elsewhere now refuses where it passes today.

Claude-Session: https://claude.ai/code/session_01R6HeFa3hsShpfQM4gGWTZv
@webjunkie webjunkie self-assigned this Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🤖 CI report

Trunk lane — non-backend lane

This PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.

@webjunkie
webjunkie marked this pull request as ready for review September 1, 2026 07:00
Copilot AI lite review requested due to automatic review settings September 1, 2026 07:00
@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-01T07:16:26.993057Z 1f523ef 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.

@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team September 1, 2026 07:00
Base automatically changed from feat/stamphog-delegable-max-lines to master September 1, 2026 07:04
@trunk-io

trunk-io Bot commented Sep 1, 2026

Copy link
Copy Markdown

😎 Stack merged successfully - details.

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

This PR updates the Stamphog PR size gate so per-scope budgets (global + folder grants) cannot add up to an unbounded whole-PR allowance. It introduces a derived “roof” for both substantive lines and files, defined as the most generous ceiling in play across scopes, and updates tests and docs to match.

Changes:

  • Add whole-PR “roof” limits for substantive lines/files, derived from the max scope ceiling for each key.
  • Update size-gate refusal messaging to report whole-PR roof overruns (in addition to per-scope overruns).
  • Add new policy-resolution and pipeline tests covering roof behavior, plus documentation updates.

Reviewed changes

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

Show a summary per file
File Description
products/stamphog/packages/pr-approval-agent/review_pr.py Enforces PR-wide roofs for lines/files after per-scope checks and adds corresponding refusal messages.
products/stamphog/packages/pr-approval-agent/policy.py Adds line_roof/file_roof derived properties on EffectivePolicy to compute the PR-wide roofs.
products/stamphog/packages/pr-approval-agent/test_policy.py Refactors size-gate setup helper and adds tests validating roof behavior and “most generous ceiling” semantics.
products/stamphog/packages/pr-approval-agent/README.md Documents that per-scope budgets do not sum because a PR-wide roof still applies.
.stamphog/README.md Documents the new roof concept and how it relates to delegation ceilings and global defaults.

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

Comment thread products/stamphog/packages/pr-approval-agent/review_pr.py
Comment thread .stamphog/README.md Outdated
Comment thread products/stamphog/packages/pr-approval-agent/README.md Outdated
…gate-roof

# Conflicts:
#	.stamphog/README.md
#	products/stamphog/packages/pr-approval-agent/README.md
#	products/stamphog/packages/pr-approval-agent/policy.py
#	products/stamphog/packages/pr-approval-agent/review_pr.py
#	products/stamphog/packages/pr-approval-agent/test_policy.py

@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: e0e00baa25

ℹ️ 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 products/stamphog/packages/pr-approval-agent/policy.py
Review feedback on the roof docs. The contract-ceiling sentence read as if
every PR gets that total, when a PR whose files reach no grant keeps the lower
global roof. The agent README bullet ended mid-sentence.

Claude-Session: https://claude.ai/code/session_01R6HeFa3hsShpfQM4gGWTZv
A repo overlay can replace size_gate while inheriting the overrides contract.
That allowed a global max_lines above the contract ceiling, and the roof then
followed the global pool past the ceiling the docs call the upper bound.

The loader now fails closed on that pairing. It is incoherent on its own terms
too: under the global default a ceiling bounds nothing, and delegation could
only ever lower a folder's allowance.

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

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

good approach

@trunk-io
trunk-io Bot merged commit 01af5d2 into master Sep 1, 2026
206 checks passed
@trunk-io
trunk-io Bot deleted the feat/stamphog-size-gate-roof branch September 1, 2026 13:17
@deployment-status-posthog

deployment-status-posthog Bot commented Sep 1, 2026

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-09-01 13:52 UTC Run
prod-us ✅ Deployed 2026-09-01 14:20 UTC Run
prod-eu ✅ Deployed 2026-09-01 14:23 UTC Run

dmarticus added a commit that referenced this pull request Sep 4, 2026
…ay (#92116)

Co-authored-by: Charles Vien <charles.v@posthog.com>
Co-authored-by: Charles Vien <me@charlesvien.com>
dmarticus added a commit that referenced this pull request Sep 4, 2026
…ay (#92116)

Co-authored-by: Charles Vien <charles.v@posthog.com>
Co-authored-by: Charles Vien <me@charlesvien.com>
dmarticus added a commit that referenced this pull request Sep 4, 2026
…ay (#92116)

Co-authored-by: Charles Vien <charles.v@posthog.com>
Co-authored-by: Charles Vien <me@charlesvien.com>
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