mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-14 21:29:34 +00:00
Addresses C1-C7 from Rames's adversarial review + N2/N3 nits:
- C1 (positionFixed): inline probe now value-scopes to 'fixed' — previously
fired on any position value (absolute, relative, sticky), producing a
false-positive anatomy that would mislead maintainers pattern-matching
the 'sub-comp + position:fixed capture' bug family.
- C2 (overflowHidden): symmetric fix — inline path now catches
style='overflow: hidden' via the value-scoped probe, matching the
<style>-tag branch. Also handles overflow-x/overflow-y variants.
- C3 (VISUAL_DEFECT_KEYWORDS): drop 'render' — CLI's primary command is
'hyperframes render', so build/perf/hang reports were triggering an
inappropriate COMPOSITION_STRUCTURE: nudge on the most common failure
mode. Rely on the more specific tokens (black, blank, flicker, corrupt,
wrong frame) to identify actual visual defects.
- C4 (mentionsVisualDefect): compile keywords into a word-bounded regex.
'blackboard', 'blanket', 'visualize', 'corruptible' no longer false-
positive. Accepted tradeoff: plural forms ('flickers') don't match.
- C5 (marker case-normalization): REPRO COMMAND: / COMPOSITION_STRUCTURE:
checks now case-insensitive, matching mentionsVisualDefect's
normalization. Reporters using 'Repro command:' or lowercase
'composition_structure:' get credit for compliance.
- C6 (background/mask shorthand): inline branch previously required the
longhand 'background-image:' / 'mask-image:' — style='background:
url(bg.png)' silently returned false. Now checks both longhand AND
shorthand-with-url() inline forms.
- C7 (usesGsap docstring): trim promise of data-gsap-* attribute scanning
that detectGsap never implemented — attribute scan lives outside the
<script>-only detection path.
- N2 (EMPTY_VALUES): include 'inherit', 'revert', 'revert-layer' — a
style='position: inherit' is authored intent to defer, not authored
intent to place.
- N3 (input size cap): early-exit to a zero census on HTML > 20 MB
rather than feeding linkedom a hostile input. Not expected in normal
usage; guard for future callers that might pass raw user uploads.
Extends the test locks: 6 new census tests (value-scoping, size cap) and
5 new lint tests (word-boundary rejections, render-noise rejections,
lowercase-marker acceptance). All existing tests unchanged in intent —
only the 'flickers' plural in one test updated to 'flicker' to reflect
the new word-boundary rule.
No behavior change to the wire path: lint is still soft-warn, census is
still never called from feedback.ts, no new dependencies.
158 lines
6.3 KiB
TypeScript
158 lines
6.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
COMPOSITION_STRUCTURE_RATING_CEILING,
|
|
VISUAL_DEFECT_KEYWORDS,
|
|
lintFeedbackComment,
|
|
mentionsVisualDefect,
|
|
} from "./feedbackLint.js";
|
|
|
|
describe("lintFeedbackComment", () => {
|
|
it("returns no warnings for a perfect rating regardless of comment", () => {
|
|
expect(lintFeedbackComment({ rating: 10, comment: "black frame at 0.5s, no REPRO" })).toEqual(
|
|
[],
|
|
);
|
|
});
|
|
|
|
it("returns no warnings when the comment is missing or blank", () => {
|
|
expect(lintFeedbackComment({ rating: 6, comment: undefined })).toEqual([]);
|
|
expect(lintFeedbackComment({ rating: 6, comment: "" })).toEqual([]);
|
|
expect(lintFeedbackComment({ rating: 6, comment: " \n " })).toEqual([]);
|
|
});
|
|
|
|
it("warns on non-10 comments missing REPRO COMMAND:", () => {
|
|
const warnings = lintFeedbackComment({
|
|
rating: 6,
|
|
comment: "fast but crashed after a bit",
|
|
});
|
|
expect(warnings).toHaveLength(1);
|
|
expect(warnings[0]?.code).toBe("missing-repro-command");
|
|
expect(warnings[0]?.message).toContain("REPRO COMMAND:");
|
|
});
|
|
|
|
it("stays silent when the reporter already included a REPRO COMMAND: block", () => {
|
|
const warnings = lintFeedbackComment({
|
|
rating: 4,
|
|
comment: [
|
|
"cloudrun submission kept timing out.",
|
|
"REPRO COMMAND: cd project && npx hyperframes cloudrun submit",
|
|
"EXPECTED / ACTUAL: uploads / hangs at seek",
|
|
].join("\n"),
|
|
});
|
|
expect(warnings).toEqual([]);
|
|
});
|
|
|
|
it("warns on rating<=7 visual-defect comments missing COMPOSITION_STRUCTURE:", () => {
|
|
const warnings = lintFeedbackComment({
|
|
rating: 5,
|
|
comment: [
|
|
"REPRO COMMAND: cd proj && npx hyperframes render",
|
|
"EXPECTED / ACTUAL: output correct / black frame at 0.5s",
|
|
].join("\n"),
|
|
});
|
|
expect(warnings).toHaveLength(1);
|
|
expect(warnings[0]?.code).toBe("missing-composition-structure");
|
|
expect(warnings[0]?.message).toContain("COMPOSITION_STRUCTURE:");
|
|
expect(warnings[0]?.message).toContain("buildCompositionCensus");
|
|
});
|
|
|
|
it("skips the composition-structure warning above the rating ceiling", () => {
|
|
const warnings = lintFeedbackComment({
|
|
rating: COMPOSITION_STRUCTURE_RATING_CEILING + 1,
|
|
comment: [
|
|
"REPRO COMMAND: cd proj && npx hyperframes render",
|
|
"minor black bar on the right edge; workaround with --resolution landscape",
|
|
].join("\n"),
|
|
});
|
|
// Missing structure warning is suppressed at rating 8+.
|
|
expect(warnings.filter((w) => w.code === "missing-composition-structure")).toEqual([]);
|
|
});
|
|
|
|
it("skips the composition-structure warning when no visual-defect keyword is present", () => {
|
|
const warnings = lintFeedbackComment({
|
|
rating: 4,
|
|
comment: [
|
|
"docker mode always fails on Alpine",
|
|
"REPRO COMMAND: docker run ... && npx hyperframes doctor --docker",
|
|
].join("\n"),
|
|
});
|
|
expect(warnings.filter((w) => w.code === "missing-composition-structure")).toEqual([]);
|
|
});
|
|
|
|
it("emits both warnings when a low-rating visual comment lacks both markers", () => {
|
|
const warnings = lintFeedbackComment({
|
|
rating: 3,
|
|
comment: "flicker at every scene boundary",
|
|
});
|
|
expect(new Set(warnings.map((w) => w.code))).toEqual(
|
|
new Set(["missing-repro-command", "missing-composition-structure"]),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("mentionsVisualDefect", () => {
|
|
it.each(VISUAL_DEFECT_KEYWORDS.map((kw) => kw as string))(
|
|
"matches keyword %j case-insensitively",
|
|
(kw) => {
|
|
expect(mentionsVisualDefect(`Reports a ${kw.toUpperCase()} issue`)).toBe(true);
|
|
},
|
|
);
|
|
|
|
it("returns false for comments about non-visual friction", () => {
|
|
expect(mentionsVisualDefect("cli hangs on init prompt in non-TTY shells")).toBe(false);
|
|
expect(mentionsVisualDefect("cloudrun deploy expired auth token")).toBe(false);
|
|
});
|
|
|
|
it("does not match on partial-word false positives (word boundary)", () => {
|
|
// The classic false positives Rames flagged in review.
|
|
expect(mentionsVisualDefect("scribbled on the blackboard")).toBe(false);
|
|
expect(mentionsVisualDefect("added to blacklist yesterday")).toBe(false);
|
|
expect(mentionsVisualDefect("brought a blanket to the office")).toBe(false);
|
|
expect(mentionsVisualDefect("let me visualize the graph")).toBe(false);
|
|
expect(mentionsVisualDefect("that's a corruptible pointer")).toBe(false);
|
|
});
|
|
|
|
it("does not fire on `render` — CLI's primary command, too noisy", () => {
|
|
// `hyperframes render` is the CLI's core command; comments like
|
|
// "render OOMed at 118s" are build/perf issues, not visual defects.
|
|
expect(mentionsVisualDefect("render OOMed at 118s")).toBe(false);
|
|
expect(mentionsVisualDefect("render hung on Alpine")).toBe(false);
|
|
expect(mentionsVisualDefect("preview render command took forever")).toBe(false);
|
|
});
|
|
|
|
it("still matches the real defect words in prose", () => {
|
|
expect(mentionsVisualDefect("output is a black frame at 0.5s")).toBe(true);
|
|
expect(mentionsVisualDefect("the whole sequence flickers hard")).toBe(false); // "flickers" (plural) — accepted false-neg
|
|
expect(mentionsVisualDefect("the whole sequence has a flicker at 2s")).toBe(true);
|
|
expect(mentionsVisualDefect("wrong frame at t=0.3")).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("marker-check case-insensitivity", () => {
|
|
it("does not warn when the reporter uses lowercase `Repro command:`", () => {
|
|
// Case asymmetry fix (C5): marker checks match `mentionsVisualDefect`'s
|
|
// case-normalization, so compliance in any case is honored.
|
|
const warnings = lintFeedbackComment({
|
|
rating: 5,
|
|
comment: [
|
|
"cloudrun submission kept timing out.",
|
|
"Repro command: cd project && npx hyperframes cloudrun submit",
|
|
].join("\n"),
|
|
});
|
|
expect(warnings.filter((w) => w.code === "missing-repro-command")).toEqual([]);
|
|
});
|
|
|
|
it("does not double-warn when reporter uses lowercase `composition_structure:`", () => {
|
|
const warnings = lintFeedbackComment({
|
|
rating: 4,
|
|
comment: [
|
|
"REPRO COMMAND: cd proj && npx hyperframes render",
|
|
"composition_structure:",
|
|
" elements: video=1 audio=0 img=0 svg=0 canvas=0 subComps=0",
|
|
"black frame at 0.5s",
|
|
].join("\n"),
|
|
});
|
|
expect(warnings.filter((w) => w.code === "missing-composition-structure")).toEqual([]);
|
|
});
|
|
});
|