Repository navigation
chore(tooling): post fewer screenshots and lint a deferred mounted-flag reset - #1399
Merged
Merged
Conversation
A python3 or node command that runs a script file no longer counts its arguments as a git write. Inline code, interpreter options, shells, wrappers and a bare git or gh argument still block.
1280 light by default; a 390 or dark frame only where layout or theme visibly differs; no frames that differ only in text; about 12 or fewer per PR. #1395 posted 28.
A useEffect cleanup can run a task after the commit that removes the screen, so a continuation in between still reads the flag as set (#1395). The rule points to useLayoutEffect. Dialog.tsx:321 clears the open-dialog count the same way; it gets an inline disable with its reason, and no product change here.
A return inside a helper defined in the effect is not the cleanup. Round 1 review, P3.
…data-only Round 1 review, P1: npm-cli.js exec -c and pdb.py -c run their argument, so an interpreter-wide exemption let a git write through. The script must now be a regular file whose first five lines carry 'git-guard: data-only-args'; a missing, unreadable or unmarked script blocks as before.
Round 1 review, P2: de-duplicate within the before set and within the after set, never across the pair AGENTS.md requires.
Without them the marker lookup alone blocked python3 -c and node -e, so the option rule had no test.
… symlink Round 2 review, P1: Python's open follows a symlink before .., while Node drops link/.. first, so the guard could read a marked file while Node ran an unmarked runner. The exemption now needs a script path with no .. whose realpath equals its normalized path, and reads the marker through it.
Three review rounds each found a bypass (runner scripts, symlink plus .., swap-then-run). The maintainer chose to drop the guard change; tools/agent-guard/ is back at 1aa3f51.
Ten in-memory effects linted with the real config, run by CI's Lint step. Dropping the effect-ownership check turns nestedFactory and immediateFactory red.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
These are two fixes from the retro on the TOTP slice (#1277). UI PRs posted more screenshots than anyone reads: #1395 posted 28. And the Back-button race that #1395 fixed had no check to stop it coming back.
What changes
1. The verify skill asks for fewer frames.
tools/verify/SKILL.mdasked for 1280x800 and 390x844 in both light and dark. Now a PR posts one frame per distinct state at 1280 light. It adds a 390 or dark frame only where the layout or theme visibly differs. Within the before frames, and separately within the after frames, it skips frames that differ only in text. A changed existing screen always keeps its before and after pair, as AGENTS.md requires, even when only its text changed. The target is about 12 frames or fewer. The 1:1, viewport-only and rebuilt-at-head rules stay.capture.shstill captures all four frames so they can be compared, and the skill now says to post only the frames the rule keeps.2. A lint for a flag cleared in a
useEffectcleanup. In #1395,useDialogSessionclearedmounted.currentin auseEffectcleanup. React can run that cleanup a task after the commit that removes the screen, so a step-up grant that landed in between still sent its write. Ano-restricted-syntaxselector inweb/lint/eslint.config.jsnow flagsx.current = falseinside a function that auseEffectreturns. That covers areturn () => …that belongs to the effect callback (a conditional return included, a return inside a helper defined in the effect excluded) and the() => () => …form. The message points touseLayoutEffect. It applies to all ofweb/src, and AGENTS.md's Enforced rules table has a new row for it.It found one site on main:
web/src/components/Dialog.tsx:321, the mount-once cleanup that pays back the open-dialog count. It gets an inlineeslint-disable-next-linewith its reason, asuseLatestLoad.ts:36does for the #1190 rule.reportUnusedDisableDirectivesfails lint once that line stops violating. The frozen-suppressions file cannot hold this entry:check-suppressions.mjs --basekeys by rule id, andno-restricted-syntaxalready applied to that file. Candidate for a later look: async code readsenteredthroughanyDialogOpen(), so the same one-task delay could apply. No race has been shown, and this PR does not change product code.Dropped
The retro also asked the agent git guard to stop refusing harmless commands whose quoted arguments mention a git write. This branch tried a data-only exemption for scripts and then dropped it. Three review rounds each found a bypass: command runners that ship with the toolchain (npm
exec -c,pdb -c), a symlink plus..that made the guard read a different file than Node ran, and a step that swaps the script before running it.tools/agent-guard/is unchanged from main. The false blocks stay, and decision logging keeps its two-step workaround.Proof
Each mutation broke the new code, and a committed check then ran against it. Every row went red.
useDialogSession.tsreverted touseEffectnpm run lintuseDialogSession.ts 64:20with the new messageDialog.tsxnpm run lintDialog.tsx 321:7web/lint/cleanup-selector.test.mjsnestedFactoryandimmediateFactoryfailweb/lint/cleanup-selector.test.mjsholds the selector's cases. It lints ten in-memory effects with the real config and compares each against an expected count. It expects a diagnostic for a block return, a conditional return, the concise form, a function expression andReact.useEffect. It expects none for a timer callback, a layout effect, or a helper defined or invoked inside the effect. CI's Lint step runs it withnode --test. It is not part ofnpm run lint, sonpm run lint -- --prune-suppressionsstill passes its arguments to ESLint.Runs at the head:
npm run lint,npm run typecheck,check-suppressions.mjs --baseand the selector test pass. The guard's own tests (git_guard_test.py,git_hooks_test.py,pi_extension_test.mjs) pass on the restored guard. The guards that walk every tracked file (the two image-pin tests,TenancyDocsFreshnessTests,FileSizeLimitTests) pass with the new test file tracked.Review guide
web/lint/eslint.config.js: the two selectors andownReturn. The second config block repeats them because itsno-restricted-syntaxreplaces the first block's for routes and components.web/lint/cleanup-selector.test.mjsand one line in.github/workflows/ci.yml's Lint step that runs it.web/src/components/Dialog.tsx: one comment line, the inline disable.tools/verify/SKILL.md: rule 5 is new. The old rule 5 is now rule 6.AGENTS.md: one Enforced rules row.