Skip to content

defaults guard: a shared helper name is no tunable source (6182 -> 449); an unchecked BLOCK still counts - #33161

Merged
lawrencecchen merged 8 commits into
feat-cmux-nextfrom
fix/defaults-guard-tunable-helpers
Nov 3, 2026
Merged

lawrencecchen merged 8 commits into
feat-cmux-nextfrom
fix/defaults-guard-tunable-helpers

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #33111. This branch contains the two commits of #33111. After #33111 lands, the diff here is only the last two commits.

1. A shared name is not a call of a Tunable helper. toggle, make and points are Tunable helpers. The old guard selected any declaration with a token of that name. For example, registry.bind("toggleSidebar") { ...model.toggle() } in AppActions.bindApp was selected, and the dependency walk then pulled in every handler's static func bind. Thus almost every app PR "changed a default". #32983 (OnboardingHandlers.swift:bind) and #32979 (NewTabPage.swift:paletteActions through HistoryHandlers.bind's closure make) were flagged only because of this.

Now a helper call counts only in two forms:

  • Type.helper, where Type is declared in the helper's file
  • a bare helper, in a file that declares one of the types of the helper's file (the same type or an extension of it)

x.helper and .helper are other members. The dependency walk is not changed.

Fingerprints on feat-cmux-next 38369c1: 6182 before, 449 after. No entry is added. All real helper callers stay, for example ChromeTunables.swift:space1, TabTunables.swift:compactTabWidth, MetricTunables.swift:sidebarWidth and every DropOverlayTunables entry. The bot-owned snapshot schemas/defaults/cmux-next.json is regenerated by base autofix; this PR does not edit it.

Results on the real diffs (defaults_guard.py check --base <merge base> --head <pr head>):

PR old guard this guard
#32983 tunable-source.CmuxNextApp/Handlers/OnboardingHandlers.swift:bind no default change
#32979 NewTabPage+Open.swift:fillPaletteActions, NewTabPage.swift:paletteActions no default change

2. Review findings from #33111

  • If the write-access lookup for a receipt author fails, that author now counts for a BLOCK, never for a SHIP. Thus an unchecked receipt can only keep the guard red. Before, the receipt was dropped, so an unchecked BLOCK lost to an owner's earlier SHIP.
  • If a lookup fails at the earlier head of a carried SHIP, the guard now names it in the error, as it does at the head. Before, it gave only a warning.

Regression command: python3 tests/test_defaults_guard.py

  • Test commit 9094a65: 4 failures.
    • test_a_member_that_only_shares_a_helpers_name_is_not_a_tunable_source reproduces the bindApp/bind/make shapes.
    • test_an_unchecked_block_after_an_owners_ship_keeps_the_guard_red
    • test_an_unchecked_receipt_one_base_merge_back_is_named_in_the_error
    • test_a_receipt_whose_lookup_failed_is_named_in_the_error, for its new wording.
  • Head: 72 tests OK.
  • Real default changes are still caught:
    • The existing fixtures (helper, helper body, cross-file Factory.number, symbol, external symbol, dynamic, backticked) still fail without a review.
    • The new test_a_helper_called_from_an_extension_or_by_its_type_is_still_a_tunable_source covers an extension caller and a Type.helper caller in another module.
    • The name-collision test also checks that a real helper default change is still caught.

Observed / Not run

Observed:

  • The fingerprint counts before and after on the feat tree.
  • Both PR diffs, run through the old and the new guard.
  • The test red and green results above.
  • scripts/cmux-next/prepush-gate.py is clean.

Not run: a live pull_request_target run. The guard runs from the PR base, so this change is first used by PRs whose base contains it.

Changelog

none


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


Summary by cubic

Fixes the defaults guard matching any token that shares a Tunable helper's name (toggle, make, points) as a helper call, which flagged nearly every app PR as changing a default; a helper now counts only for calls that can actually reach it, including Self.helper, typealiases of Tunable, and subclass or protocol-inherited helpers. This drops the fingerprint count on feat-cmux-next from 6182 to 449, and #32983 and #32979 no longer report default changes. Also makes an unchecked receipt whose author's write-access lookup fails count for a BLOCK only, so it can keep the guard red but never green.

  • A call owner's receipt is trusted without the write-access REST lookup, which was exhausting the shared API quota (Chief: import browser cookies from Chrome on request #32983).
  • Failed lookups are now named in the error, including at the earlier head of a carried SHIP, whose author's SHIP no longer counts but whose BLOCK does.
  • Calls through a generic parameter (e.g., T.points) are still not matched.

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

View guided diff Turn on auto-fix

…is spent (failing, #32983)

A private org member reads as CONTRIBUTOR to the workflow's token. The
guard then asks the REST API for their write access. On #32983 that call
got "API rate limit exceeded for installation", so the guard trusted
nobody and stayed red on a valid SHIP from lawrencecchen, a call owner.

Red on the base: python3 tests/test_defaults_guard.py fails
test_a_call_owners_receipt_ships_with_the_rest_quota_spent and
test_a_receipt_whose_lookup_failed_is_named_in_the_error.
…okup (#32983)

A private org member reads as CONTRIBUTOR to the workflow's token, so the
guard asked the REST API for each receipt author's write access. That call
spends the installation's REST quota, which other jobs share. On #32983 the
quota was spent ("API rate limit exceeded for installation"), the lookup
trusted nobody, and the guard stayed red on lawrencecchen's valid SHIP; the
merge service left the PR out as "defaults guard red".

The call owners come from the trusted base's .github/defaults-call-owners.json,
the same file that lets them approve a default outright, so their receipts
now need no lookup. Any other member is still looked up; when that lookup
fails for a reason other than 404, the error now names the receipt that
was not counted and says to re-run when the quota resets.

python3 tests/test_defaults_guard.py: red on the base (2 failures:
test_a_call_owners_receipt_ships_with_the_rest_quota_spent,
test_a_receipt_whose_lookup_failed_is_named_in_the_error), green on this
commit (67 tests OK).
…nchecked BLOCK still counts (failing)

#32983 and #32979 were flagged only because `toggle` and `make` are Tunable
helpers: any token with that name selected its declaration, and through
AppActions.bindApp every handler's `bind` (6182 tunable-source entries).

Two findings from the review of #33111: a BLOCK whose author's lookup failed
was dropped, so an owner's earlier SHIP passed; and a failed lookup at the
earlier head of a carried SHIP gave only a warning.

python3 tests/test_defaults_guard.py on this commit: 4 failures
(test_a_member_that_only_shares_a_helpers_name_is_not_a_tunable_source,
test_an_unchecked_block_after_an_owners_ship_keeps_the_guard_red,
test_an_unchecked_receipt_one_base_merge_back_is_named_in_the_error, and
test_a_receipt_whose_lookup_failed_is_named_in_the_error for its new wording).
…it; an unchecked BLOCK still counts

A Tunable helper (points, make, toggle) selected every declaration that had
a token of that name, so `registry.bind { model.toggle() }` in
AppActions.bindApp, and through it every handler's `bind`, was a
tunable-source default. That is 6182 fingerprints on feat-cmux-next. Now a
helper counts only as `Type.helper` where the helper's file declares Type, or
as a bare `helper` in a file that declares one of the helper file's types
(the same type or an extension of it). `x.helper` and `.helper` are other
members. The dependency walk does not change. On feat-cmux-next
(38369c1) the count goes from 6182 to 449, and no fingerprint is added.
On the diffs of #32983 and #32979 the old guard reports 1 and 2
tunable-source changes, and this one reports none.

Two findings from the review of #33111: a user whose write-access lookup
failed now counts for a BLOCK (never for a SHIP), so an unchecked receipt can
only keep the guard red. A failed lookup at the earlier head of a carried
SHIP is now named in the error too.

python3 tests/test_defaults_guard.py: 4 failures on the test commit, 72 tests
OK on this one. The real-default fixtures (helper, helper body, cross-file
Factory.number, symbol, external symbol, dynamic) still fail without a review.
@lawrencecchen lawrencecchen added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 3, 2026
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 65e1e63: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr33161 -f ref=fix/defaults-guard-tunable-helpers -f platform=macos -f backend_mode=local

web and size checks: green

Default changes

This pull request changes 1 default at ef334672c952 (what everyone gets without configuring anything):

  • guard.scripts/ci/defaults_guard.py: (none) -> "edited"

Signed off on this commit by review (independent-subagent, correctness first), carried from 65e1e63e464f across base merges.

Merge receipt: merged as eb55f4e11175 with these defaults changed, signed off by review (independent-subagent, correctness first), carried from 65e1e63e464f across base merges.

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

Shipped in:

@blacksmith-sh

blacksmith-sh Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Found 1 test failure on Blacksmith runners:

Failure

Test View Logs
build_only must be a conjunctive exclusion on the helper, signing, and publication jobs
, and must not gate the unsigned app build/
build_only must be a conjunctive exclusion on the helper, signing, and publication jobs
, and must not gate the unsigned app build
View Logs

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

…calls stay tunable sources (failing)

The review of #33161 found forms that reach a Tunable or its helper with
no Tunable token and no Type.helper of a type in the helper's file:
Self.points(...), a typealias of Tunable (TD.number, `: TD = .number`), a
subclass calling an inherited helper (bare or Sub.helper), and a type
calling a helper of a protocol extension it conforms to.

On this commit all 6 subtests fail. On the guard before #33161, the 4
Self, subclass and protocol subtests pass and the 2 typealias subtests
fail: that guard missed a typealias too.
…alls reach a Tunable helper

The review of #33161 found Tunable forms the exact helper match missed.
Self.points(...) was skipped because Self is no declared type, and the
guard before #33161 caught it only by the shared-name match. Now:
- Self.helper resolves like a bare helper: the caller's own types.
- A caller's types also include the superclasses and protocols its types
  name, so a subclass reaches its base's helper and a conforming type a
  protocol extension's helper. Only the caller side takes inheritance, so a
  helper file that conforms to Sendable does not reach every Sendable type.
- A typealias of a Tunable, or an alias of such an alias, counts as a
  Tunable token (TD.number, `: TD = .number`). The guard before #33161
  missed this too.
- `class func` / `class var` no longer read as types named func / var.

feat-cmux-next tree: still 449 fingerprints, the same set, all of them in
the old 6182. #32983 and #32979 still report no tunable-source change.
python3 tests/test_defaults_guard.py: 6 subtests red on the test commit,
73 tests OK here. Not resolved: a helper reached through a generic
parameter (T.points).
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Review (independent-subagent, correctness first): SHIP at 3a0a2e2

@lawrencecchen lawrencecchen added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Nov 3, 2026
…s-guard-tunable-helpers

# Conflicts:
#	scripts/ci/defaults_guard.py
#	tests/test_defaults_guard.py
@lawrencecchen lawrencecchen removed the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Nov 3, 2026
@lawrencecchen lawrencecchen added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Nov 3, 2026
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Review (independent-subagent, correctness first): SHIP at 65e1e63

@lawrencecchen lawrencecchen added ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds and removed ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds labels Nov 3, 2026
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 3, 2026 07:44 Inactive
@cmux-bot cmux-bot Bot removed the stack-blocker label Nov 3, 2026
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 3, 2026 07:46 Inactive
@lawrencecchen
lawrencecchen merged commit eb55f4e into feat-cmux-next Nov 3, 2026
179 of 191 checks passed
@lawrencecchen
lawrencecchen deleted the fix/defaults-guard-tunable-helpers branch November 3, 2026 08:04
lawrencecchen added a commit that referenced this pull request Nov 3, 2026
…oes not see (#33321)

#33161 matches a Tunable helper by the call that can reach it. Its review
found five forms that this match misses and the old name match caught.
No helper in the tree is called in these ways today. The lead decided to
leave them and to write them down where the match is.

Co-authored-by: cmux-bot[bot] <348531757+cmux-bot[bot]@users.noreply.github.com>
austinywang added a commit that referenced this pull request Nov 4, 2026
Conflicts kept both sides: Package.swift deps (ChiefMemory and Icons),
Chief BUILTIN skills (10 entries), PageFactory routes (registry and the
new panels route), AppsClient state (changedFiles and eventListeners),
manifest fixture tests, and production wrangler vars with the app
registry left unbound.

defaults_guard.py takes base's type-aware helper matching (#33161),
which supersedes this branch's name-only fix; the three tests that
asserted the old conservative name matching are dropped.

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

This branch was previously deployed

1 inactive deployment
ci-routing-agent — ef334672 Deployed Nov 3, 2026 by cmux-bot[bot] via wait for same-key tree publisher #104700
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant