Repository navigation
feat(cli): check-review inspect attaches the inspector's report to each framed finding - #6409
Conversation
The --skip-contrast-in-motion flag and HYPERFRAMES_CHECK_SKIP_CONTRAST_IN_MOTION env give way to a check-review capability in HF_TOOL_CONTEXT, so only a harness turns it on. The skill text and manifest go back to main.
…ng time With HF_TOOL_CONTEXT check-review.findingFrames, every error/warning finding in layout or contrast with a real bbox gets frameTime (the middle sample of its longest held run, by the heldMs gap rule) and frame (the absolute path of an unannotated full frame shared by every finding at that time). One seek and screenshot per distinct time, capped at 60 times with errors first, into the run's snapshot folder; not listed in snapshots, history or events. Without the capability, output is unchanged.
…ch framed finding
With findingFrames on, the finding-frames page is served with the
inspector's GSAP hooks. After each frame is captured, every finding framed
at that time is inspected by its data-hf-id, else its selector, and the
inspector's own report is attached as the finding's inspect field. A failed
inspection becomes that finding's { error } and never fails the check.
Without the capability nothing changes.
Drops the unused @types/mime-types devDependency that the dependency audit
flags once packages/cli/package.json is touched.
…to feat/check-review-inspect
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 1 important · 1 nit · head a003c36
Capability gating, the seek → screenshot → inspect order, finalizeDocument reading the HTML the server actually sends, the abort checks after prepare, ready and each inspect, and the bundled imports all check out. The one finding is a target-identity gap for contrast findings that fall back to selector; it is inline.
Scope and verification
- Read the full non-test diff, plus
prepareLiveInspectionininspector/src/live.ts, the fingerprint exclusions insources.ts, and the runtime target query incore/src/runtime/inspection.ts. - Ran a fresh adversarial sub-agent pass.
- Ran locally on this head:
- root
bun run build: passes; tsc --noEmiton the CLI: passes;bun run lintandoxfmt --check: pass;- knip: no new issues compared with the base;
- the 5 focused test files: 221 passed. The Chromium tests could not run because Chrome will not launch in this sandbox.
- root
- Bundling: the
live-*.jschunk imports onlyacornandpostcss(both declared CLI dependencies) and sits besidedist/inspection.js. I copieddistinto a directory that had only those two packages installed, andprepareLiveInspectionloaded and read the runtime. - CI:
ci.ymlonly triggers on PRs tomain, soTest (cli)has not run on this head. It will run after the PR is retargeted and in the merge queue. Every workflow that did run on this head is green.
The base branch was changed.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
|
Windows render failure (run 40294744314, commit d06422e): this PR caused it, it is not a flake. In the "Build render prerequisites" step, |
Edit accuracy: accurate 271 (base branch 271), smooth 149 of thoseThe gate passes. Quarantined, measured but not gated (0) |
There was a problem hiding this comment.
Verdict: APPROVE · 0 open, 0 new · 6ad5162 → ba4e334 (now based on main)
Integration check
- The CLI and docs diff against main is patch-identical to the approved
6ad5162. The only other difference is thepackage.jsonversion that main bumped. windows-render.yml: inspector now builds before CLI. No other selective CLI build skips it.compositionViewport.ts: callingparseHTMLdirectly matches what the polyfilledDOMParserreturned for fragments, full documents and<template>.- Locally: tsc passes and 265 focused tests pass. On this head, CI, CodeQL and Windows render all succeeded.
What
A third
check-reviewfield inHF_TOOL_CONTEXT:inspect(boolean, defaultfalse).When
inspectandfindingFramesare both on, the session that takes the finding frames also runs the component inspector (@hyperframes/inspector) on each framed finding while its frame is on screen. The inspector's report is added to that finding, in the inspector's own format, as a newinspectfield.findingFramesoff:inspectdoes nothing.Why
A framed finding says what is wrong and shows the frame, but not where it comes from in the source. To fix it, an agent has to find the element's markup, the CSS that matches it and the GSAP calls that move it. The inspector already answers that from the live page. Running it in the frames session costs almost nothing, so the review gets the source context without another command.
Related work
Based on
main. #6401 (findingFrames) merged into main as12ae82aa8ab5cef317dc28a6bfbf6913dc188ca4at 2026-10-26 08:45:29 UTC; #6400 is also merged. Landed main was integrated with signed merged06422ef24ae8ef0fe19a7b983ac8529c17554e2. GitHub automatically retargeted this child to main when the parent landed; the diff is only inspect and its focused repairs.How
check-review.inspectis parsed intoolContext.tsthe same way as the other two fields, and read through the samecheckReview()helper incommands/check.ts. The option is set only when the field istrue.{ hfId }when the finding hasdataAttributes["data-hf-id"], else{ selector }(findingFrameRequestsincheckFindingFrames.ts). Withinspectoff, the requests are exactly as before.prepareFindingInspector(new,checkFindingInspect.ts) bundles the project withscriptProvenanceandonRead, and calls the inspector's embedding API,prepareLiveInspectionfrom@hyperframes/inspector/live. That API puts the GSAP hooks first in<head>. The frames session serves that HTML instead of the plain check page. Once the page is ready, the inspector is given the HTML the server actually answers (finalizeDocument). That HTML is read throughserver.answerwhen the sandbox refusedlisten(), else fetched.{ targets: [target], descendants: false }under the inspector's default byte budget. The live API refusestime(live_query_does_not_seek), because the caller seeks. Check has already seeked the page toframeTime, so the report is taken at that time. The report has novisualState; the finding's ownframeTimealready gives the time. Nothing is added to the report: no bbox at frame, no progress, no ancestor walk.ambiguous_selectorerror rather than attaching mixed source snippets; the ambiguity count includes candidates omitted by the inspector byte budget. One failed inspection makes that findinginspect: { "error": "<message>" }, and the other findings keep going. If preparation fails, the frames are still captured, and every targeted finding gets the{ error }. Neither ever fails the check.framesphase, the same way each frame does. Inspection runs inside the framesdeadline.run, so a timeout or stop during inspection is handled like a frames timeout: a runtime failure, and no frame or inspect fields.@hyperframes/inspectoris a workspace devDependency and bundled into the CLI (noExternal), like core and producer. The CLI is published withnpm publish, which would not rewrite aworkspace:*runtime dependency. The inspector reads its page runtime from beside its own module, sobuild-copy.mjscopies the requiredinspector/dist/inspection.jstocli/dist/inspection.js; a missing runtime fails the build. The module is imported dynamically, so it loads only when something is inspected.captureFindingFramesnow returns{ written, inspected }instead ofstring[].@types/mime-typesdevDependency is dropped. The dependency audit flags it oncepackages/cli/package.jsonchanges.Example
inspectvalue (trimmed), from acontainer_overflowfinding on#cz-w1 > span:nth-of-type(1)(data-hf-id="hf-1s9k",frameTime17.527):{ "generation": "79914b17-…", "sourceVersion": "05e707db…", "reused": true, "results": [ { "target": 0, "status": "found", "candidates": [ { "ref": "hfi:79914b17-…:25", "tag": "span", "id": "", "hfId": "hf-1s9k", "classes": ["cz-wi"], "composition": "cta", "withinId": "cz-w1" } ], "animations": 4, "coTargets": [], "unmappedAnimations": 0, "scopeTruncated": false } ], "snippets": [ { "id": "compositions/cta.html:49-49", "kind": ["matched CSS candidate"], "code": " .cz-wi { display: block; font: 800 158px/190px \"Inter\", sans-serif; … white-space: nowrap; }\n", "uniqueInFile": true }, { "id": "compositions/cta.html:215-215", "kind": ["html opening tag"], "code": " <div data-hf-id=\"hf-jpgt\" id=\"cz-line\"><div … id=\"cz-w1\" class=\"cz-w\"><span data-hf-id=\"hf-1s9k\" class=\"cz-wi\">Roll</span></div>…\n", "uniqueInFile": true }, { "id": "compositions/cta.html:255-258", "kind": ["animation creation", "animation source dependency"], "code": "function steps(target, times, props) {\n tl.set(target, pick(props, 0), 0);\n …\n}\n", "uniqueInFile": true }, { "id": "compositions/cta.html:468-468", "kind": ["animation caller"], "code": "steps('#cz-w1 .cz-wi', [5.25, 5.333, 5.417, 5.5], { yPercent: [110, 70, 30, 0] });\n", "uniqueInFile": true }, "… 6 more: composition roots and host, animation source dependencies" ], "omitted": [], "omittedCount": 0, "nextOffset": null, "recordLimitReached": false, "hooked": true, "debugAvailable": true, "elapsedMs": 9 }Test plan
toolContext.test.ts:inspectparses as a boolean, defaults tofalse, and is off for a non-truevalue.commands/check.test.ts:inspectonly from the capability;data-hf-idis present, else the selector;{ error }while the others keep theirs and the check does not fail;inspectalone, orfindingFramesalone, no targets are asked for and noinspectfield is added (the inspect-alone report is byte-identical to the plain one).checkBrowser.test.ts:checkFindingInspect.test.ts:{ error };{ error }.checkFindingInspect.chromium.test.ts(runs whenPUPPETEER_EXECUTABLE_PATHis set, likecheckBrowser.chromium.test.ts): a real project with real GSAP, on a real page through the real static server. By hfId and by selector, it returnsfoundwith 1 animation and snippets of kindhtml opening tag,animation creationandmatched CSS candidate; a missing selector returnsmissing.vitest runoncheck.test.ts,toolContext.test.ts,checkBrowser.test.ts,checkFindingInspect.test.ts,checkFindingInspect.chromium.test.ts,checkBrowser.chromium.test.ts,bundleWithLocalizedFonts.test.ts: 228 passed. The non-Chromium ones also pass withpackages/inspector/distremoved, as in theTest (cli)job.tsc --noEmitinpackages/clipasses, and so dooxlintandoxfmt --checkon the touched files, the pre-commit fallow audit, andbun install --frozen-lockfile.Wall clock of
check --jsonwithfindingFrameson, on four real projects,inspectoff and on. Three interleaved runs each, median, built CLI, isolatedHYPERFRAMES_HISTORY_ROOT:Coverage: 35 of 35 framed findings got an
inspectreport with statusfound, with no{ error }. All 33 on bench_m1 were targeted by hfId: 26 contrast, 7 layout.Byte-identical check against the base branch build (
5e14d8bd9), on instagram_reel and bench_m1. These configurations gave the same output except the per-run UUIDs in the report and snapshot paths:HF_TOOL_CONTEXT;findingFramesonly;inspectonly.docs/developers/harness-tool-context.mdx,check-reviewsection, with theinspectfield and the finding'sinspectfield.Independent followthrough validation (
a003c3681)bin,distandpackage.jsonoutside the checkout: top-level--helpand--versionwork with no dependencies.check --helpneeds the declaredhonodependency. With only declared runtime dependency links and no workspace package links, the built CLI checked a local GSAP overflow fixture in plain, inspect-only, frames-only and frames+inspect modes. Both framed findings returned nativefoundreports with markup/CSS/animation snippets; novisualState. Plain/inspect-only differed only in per-run saved IDs/paths. Copiedinspection.jsmatches the inspector build.Review repairs (
6ad5162a1){ error }form for multi-candidate selector reports; unique targets retain the native report. Unit coverage includes candidates omitted by the byte budget.inspection.jstemporarily absent, the previous script exited 0 and the repaired script exited 1. The artifact was restored and build-copy/full CLI build passed.Main integration (
d06422ef2)Windows prerequisite repair (
0e17b6bdd)inspection.jscopy failed. Added inspector immediately before CLI in the Windows render build list.Render on windows-latestjob also passed. The final diff adds this workflow prerequisite to the 18 application/docs/test/build files above.Server parser repair (
ba4e33413)DOMParser. The helper now directly uses the existing LinkeDOM server parser, matching neighboring HTML helpers and avoiding dependence on an ambient browser parser. No alert suppression or filter was added.Not covered
animationscounts only GSAP.inspectis only on findings that got a frame:errorandwarningfindings inlayoutandcontrastwith a real bbox, at most 60 distinct times.omitted/nextOffset, which check does not follow.