| B-01 |
BLOCKING |
Naming |
imageHandler.tsx:37 |
Image component is not prefixed F0 — AGENTS.md requires all public components start with F0 |
Rename to F0Image; rename ImageProvider → F0ImageProvider, useImageContext → useF0ImageContext |
| B-02 |
BLOCKING |
Naming |
Utilities/Image/ folder |
Component folder is not named F0Image/ — must match component name |
Rename folder to F0Image/ |
| B-03 |
BLOCKING |
TypeScript |
imageHandler.tsx:9,30,32 |
All three public types use type instead of interface (ImageContextValue, ImageProps, SrcProps) — AGENTS.md: "prefer interfaces over types for public APIs" |
Convert all three to interface |
| B-04 |
BLOCKING |
Props |
imageHandler.tsx:30 |
className is not blocked on the public Image component — AGENTS.md: "No className on public components" |
Omit className via Omit<ImgHTMLAttributes<…>, "className"> or the privateProps pattern |
| B-05 |
BLOCKING |
React |
imageHandler.tsx:15 |
React.FC<…> used but React namespace is not imported — TypeScript compile error |
Replace with a typed plain function: export function F0ImageProvider({ children, ...value }: …): ReactNode |
| B-06 |
BLOCKING |
forwardRef |
imageHandler.tsx:44 |
displayName is never explicitly set on the forwardRef component — AGENTS.md: "set displayName" |
Add Image.displayName = "F0Image" (post-rename) after the forwardRef call |
| B-07 |
BLOCKING |
Structure |
Utilities/Image/ |
Wrong folder layout: missing __tests__/, __stories__/, implementation file (F0Image.tsx), and types.ts — all required by AGENTS.md |
Create correct folder layout; move implementation out of lib/ |
| B-08 |
BLOCKING |
Testing |
Utilities/Image/index.spec.tsx, lib/imageHandler.spec.tsx |
Both test files use .spec.tsx extension — AGENTS.md: "never .spec.ts" |
Rename both to .test.tsx |
| B-09 |
BLOCKING |
Testing |
Utilities/Image/index.spec.tsx |
Test file at component root, not in __tests__/ subfolder |
Move to F0Image/__tests__/F0Image.test.tsx |
| B-10 |
BLOCKING |
Exports |
components/exports.ts |
Image, ImageProvider, types, and hook are not exported from the public package surface — AGENTS.md: "Components in components/ must be exported in exports.ts" |
Add export * from "./Utilities/F0Image" to exports.ts |
| B-11 |
BLOCKING |
Exports |
Utilities/Image/index.tsx:1 |
index.tsx only re-exports Image; ImageProvider, useImageContext, and all public types are inaccessible from the public API |
Export all public symbols from index.tsx |
| B-12 |
BLOCKING |
Architecture |
src/lib/imageHandler.tsx |
Public component implementation lives in lib/ (internal utilities), not components/ — AGENTS.md: "lib/ is for internal utilities" |
Move implementation to components/Utilities/F0Image/F0Image.tsx; leave a @deprecated re-export shim in lib/ during migration |
| B-13 |
BLOCKING |
Context |
imageHandler.tsx:23–28 |
useImageContext spreads undefined context value ({ ...undefined } → {}) instead of using the ?? fallback pattern documented in AGENTS.md |
Change to return useContext(ImageContext) ?? {} |
| B-14 |
BLOCKING |
Imports |
Utilities/Image/index.tsx:1 |
Deep relative import ../../../lib/imageHandler instead of @/ alias or sibling file |
Once implementation is collocated, use export * from "./F0Image" |
| B-15 |
BLOCKING |
A11y |
imageHandler.tsx:30 |
alt is string | undefined (optional in ImgHTMLAttributes) — TypeScript does not prevent omitting alt, which is a WCAG 1.1.1 (Level A) violation |
Change to alt: string in the public props type (empty string is still allowed for decorative images) |
| B-16 |
BLOCKING |
A11y |
ProductUpdates/index.tsx:249 |
<Image> rendered with no alt attribute in production code — confirmed missing alt on an informative thumbnail image |
Pass alt={title} to this usage; once B-15 is fixed TypeScript will enforce this |
| B-17 |
BLOCKING |
A11y |
imageHandler.tsx:30, index.stories.tsx |
No decorative image pattern (alt="" + optional role="presentation") is defined, documented, or story-demonstrated |
Add discriminated union or documented guidance; add a Decorative story |
| B-18 |
BLOCKING |
A11y |
imageHandler.tsx:32–43 |
SrcProps allows the transformer to return src: undefined (because it is Pick from ImgHTMLAttributes where src is optional), silently breaking the image for AT users |
Tighten SrcProps to { src: string; srcSet?: string; sizes?: string } and add runtime console.warn guard |
| B-19 |
BLOCKING |
Storybook |
index.stories.tsx |
Story file at component root, not in __stories__/ subfolder |
Move to F0Image/__stories__/F0Image.stories.tsx |
| B-20 |
BLOCKING |
Storybook |
index.stories.tsx (missing) |
No Snapshot story with withSnapshot({}) — component is invisible to Chromatic |
Add export const Snapshot: Story = { parameters: withSnapshot({}) } |
| B-21 |
BLOCKING |
Storybook |
index.stories.tsx:8 |
title: "Image" — does not match folder structure and conflicts with other image-related stories |
Change to title: "Utilities/Image" |
| B-22 |
BLOCKING |
Storybook |
index.stories.tsx (missing) |
No story demonstrates ImageProvider / src transform — the component's only distinctive feature |
Add a WithImageProvider story with an inline decorators showing the transform |
| B-23 |
BLOCKING |
Testing |
Utilities/Image/index.spec.tsx:1,8 |
render and screen imported from @testing-library/react — must use zeroRender from @/testing/test-utils |
Replace import |
| B-24 |
BLOCKING |
Testing |
Utilities/Image/index.spec.tsx:4 |
Relative import path "../../../lib/imageHandler" — must use @/lib/imageHandler alias |
Fix import |
| B-25 |
BLOCKING |
Testing |
lib/imageHandler.spec.tsx:1 |
Same render/screen from @testing-library/react violation |
Replace import |
Stability Audit — Utilities/Image
Components audited:
Image(Utilities/Image/),ImageProvider,useImageContext(implemented insrc/lib/imageHandler.tsx)BLOCKING findings
imageHandler.tsx:37Imagecomponent is not prefixedF0— AGENTS.md requires all public components start withF0F0Image; renameImageProvider→F0ImageProvider,useImageContext→useF0ImageContextUtilities/Image/folderF0Image/— must match component nameF0Image/imageHandler.tsx:9,30,32typeinstead ofinterface(ImageContextValue,ImageProps,SrcProps) — AGENTS.md: "prefer interfaces over types for public APIs"interfaceimageHandler.tsx:30classNameis not blocked on the publicImagecomponent — AGENTS.md: "NoclassNameon public components"classNameviaOmit<ImgHTMLAttributes<…>, "className">or theprivatePropspatternimageHandler.tsx:15React.FC<…>used butReactnamespace is not imported — TypeScript compile errorexport function F0ImageProvider({ children, ...value }: …): ReactNodeimageHandler.tsx:44displayNameis never explicitly set on theforwardRefcomponent — AGENTS.md: "setdisplayName"Image.displayName = "F0Image"(post-rename) after theforwardRefcallUtilities/Image/__tests__/,__stories__/, implementation file (F0Image.tsx), andtypes.ts— all required by AGENTS.mdlib/Utilities/Image/index.spec.tsx,lib/imageHandler.spec.tsx.spec.tsxextension — AGENTS.md: "never.spec.ts".test.tsxUtilities/Image/index.spec.tsx__tests__/subfolderF0Image/__tests__/F0Image.test.tsxcomponents/exports.tsImage,ImageProvider, types, and hook are not exported from the public package surface — AGENTS.md: "Components incomponents/must be exported inexports.ts"export * from "./Utilities/F0Image"toexports.tsUtilities/Image/index.tsx:1index.tsxonly re-exportsImage;ImageProvider,useImageContext, and all public types are inaccessible from the public APIindex.tsxsrc/lib/imageHandler.tsxlib/(internal utilities), notcomponents/— AGENTS.md: "lib/is for internal utilities"components/Utilities/F0Image/F0Image.tsx; leave a@deprecatedre-export shim inlib/during migrationimageHandler.tsx:23–28useImageContextspreadsundefinedcontext value ({ ...undefined }→{}) instead of using the??fallback pattern documented in AGENTS.mdreturn useContext(ImageContext) ?? {}Utilities/Image/index.tsx:1../../../lib/imageHandlerinstead of@/alias or sibling fileexport * from "./F0Image"imageHandler.tsx:30altisstring | undefined(optional inImgHTMLAttributes) — TypeScript does not prevent omittingalt, which is a WCAG 1.1.1 (Level A) violationalt: stringin the public props type (empty string is still allowed for decorative images)ProductUpdates/index.tsx:249<Image>rendered with noaltattribute in production code — confirmed missing alt on an informative thumbnail imagealt={title}to this usage; once B-15 is fixed TypeScript will enforce thisimageHandler.tsx:30,index.stories.tsxalt=""+ optionalrole="presentation") is defined, documented, or story-demonstratedDecorativestoryimageHandler.tsx:32–43SrcPropsallows the transformer to returnsrc: undefined(because it isPickfromImgHTMLAttributeswheresrcis optional), silently breaking the image for AT usersSrcPropsto{ src: string; srcSet?: string; sizes?: string }and add runtimeconsole.warnguardindex.stories.tsx__stories__/subfolderF0Image/__stories__/F0Image.stories.tsxindex.stories.tsx(missing)Snapshotstory withwithSnapshot({})— component is invisible to Chromaticexport const Snapshot: Story = { parameters: withSnapshot({}) }index.stories.tsx:8title: "Image"— does not match folder structure and conflicts with other image-related storiestitle: "Utilities/Image"index.stories.tsx(missing)ImageProvider/srctransform — the component's only distinctive featureWithImageProviderstory with an inlinedecoratorsshowing the transformUtilities/Image/index.spec.tsx:1,8renderandscreenimported from@testing-library/react— must usezeroRenderfrom@/testing/test-utilsUtilities/Image/index.spec.tsx:4"../../../lib/imageHandler"— must use@/lib/imageHandleraliaslib/imageHandler.spec.tsx:1render/screenfrom@testing-library/reactviolationSUGGESTION findings
index.stories.tsx:14"no-sidebar"tag is inconsistent with"stable"— unique combination in the entire codebase; causes the component to be hidden from the sidebar"no-sidebar"from tagsindex.stories.tsx(missing)argTypes—ImgHTMLAttributesexposes 40+ HTML attributes, flooding the Controls panelargTypesdescribingsrc,alt,width,height,loading,srcSet,sizesand disabling irrelevant event handlersindex.stories.tsx(missing)srcSet/sizesorloading="lazy"— both are first-class features inSrcPropsWithSrcSetandLazyLoadingstoriesindex.stories.tsx(missing)parameters.docs.description.componentprose on theImageProvidertransform patternindex.stories.tsx:4@factorialco/f0-core/assets/icons/app/heart.svgraw asset path — use@/icons/apptyped import instead@/icons/appimageHandler.tsx:19ImageProviderspreads all remaining props into the context via...value— future new props would be leaked into context without filteringconst { src } = value; <ImageContext.Provider value={{ src }}>imageHandler.tsx:15React.FCis used — AGENTS.md convention is to use typed plain functions insteadexport function F0ImageProvider(…): ReactNodeindex.tsx:1export *— new exports added to implementation must be manually syncedexport * from "./F0Image"imageHandler.tsx:30DataAttributesfrom@/global.typesnot included inImageProps— other F0 components intersect it& DataAttributestoF0ImagePropsimageHandler.tsx:32SrcPropsis too generic — should beF0ImageSrcPropsand live intypes.tsimageHandler.tsx:30console.warnwhen bothwidthandheightare missing (CLS risk)if (!props.width && !props.height) console.warn(…)in developmentindex.stories.tsx(missing)playfunction withcheckA11y— axe regressions will go undetected in CIplayfunction toBasicandDecorativestoriesindex.stories.tsx(missing)loading="lazy"story (best practice guidance for off-screen images)LazyLoadingstoryindex.spec.tsx:7asynckeyword with noawaitexpression — dead weightasyncindex.spec.tsx(whole file)lib/imageHandler.spec.tsx— barrel re-export has no own logic; component-level test adds zero incremental coverage__tests__/F0Image.test.tsx; delete the duplicateimageHandler.tsx:37forwardRefref forwarding is never tested — regression would go undetectedconst ref = createRef<HTMLImageElement>(); render(<F0Image ref={ref} src="x.png" alt="x" />); expect(ref.current?.tagName).toBe("IMG")lib/imageHandler.spec.tsx__tests__/folder —lib/test convention is inconsistent;linkHandler.spec.tsxhas the same issuelib/__tests__/convention and migrate all lib tests togetherReviewer sections
Code Review
Accessibility
Storybook
Test Coverage
Ready-to-run fix prompt