fix(input-format): field not editable race condition#5102
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryLow Risk Overview The editor now keeps a ref-cached fallback row and commits updates via Reviewed by Cursor Bugbot for commit 8e92af9. Configure here. |
|
bugbot run |
|
@greptile |
Greptile SummaryThis PR fixes a race condition in the
Confidence Score: 5/5Safe to merge — the changes are tightly scoped to the input-format editor component and its shared factory helper. The fix correctly addresses the root cause: the fallback field ref ensures a stable id across renders, and switching from storeValueRef to fieldsRef ensures updateField always maps against the ids actually shown in the UI. The factory extraction is a straightforward deduplication with no observable behavioral differences. The dead-code removal in store.ts has no callers to break. No files require special attention. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant UI as FieldFormat (render)
participant Ref as fallbackFieldRef / fieldsRef
participant Store as SubBlock Store
Note over UI,Store: Before fix — new block, store empty
UI->>Ref: "fields = [createDefaultField()] → id=abc"
UI->>Store: updateField(abc, name, foo)
Store-->>UI: "storeValue = null/empty"
UI->>UI: "currentFields = [createDefaultField()] → id=xyz (new!)"
UI->>Store: "setStoreValue([{id:xyz, name:foo}])"
Note over UI,Store: id mismatch — input never commits correctly
Note over UI,Store: After fix — new block, store empty
UI->>Ref: "fallbackFieldRef.current ??= createDefaultField() → id=abc (cached)"
UI->>Ref: "fieldsRef.current = [{id:abc}]"
UI->>Store: updateField(abc, name, foo)
Store-->>Ref: "fieldsRef.current = [{id:abc}] (same id)"
UI->>Store: "setStoreValue([{id:abc, name:foo}])"
Note over UI,Store: id stable — input commits correctly
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant UI as FieldFormat (render)
participant Ref as fallbackFieldRef / fieldsRef
participant Store as SubBlock Store
Note over UI,Store: Before fix — new block, store empty
UI->>Ref: "fields = [createDefaultField()] → id=abc"
UI->>Store: updateField(abc, name, foo)
Store-->>UI: "storeValue = null/empty"
UI->>UI: "currentFields = [createDefaultField()] → id=xyz (new!)"
UI->>Store: "setStoreValue([{id:xyz, name:foo}])"
Note over UI,Store: id mismatch — input never commits correctly
Note over UI,Store: After fix — new block, store empty
UI->>Ref: "fallbackFieldRef.current ??= createDefaultField() → id=abc (cached)"
UI->>Ref: "fieldsRef.current = [{id:abc}]"
UI->>Store: updateField(abc, name, foo)
Store-->>Ref: "fieldsRef.current = [{id:abc}] (same id)"
UI->>Store: "setStoreValue([{id:abc, name:foo}])"
Note over UI,Store: id stable — input commits correctly
Reviews (1): Last reviewed commit: "simplify" | Re-trigger Greptile |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 8e92af9. Configure here.
Greptile SummaryThis PR fixes a race condition in
Confidence Score: 5/5Safe to merge — the change is tightly scoped to the input-format editor component and its seeding helpers, with no impact on execution or persistence paths. The fix directly addresses the documented race condition: a cached ref replaces per-render ID generation so the stable No files require special attention. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User
participant FieldFormat
participant fieldsRef
participant SubBlockStore
Note over FieldFormat: Component mounts, storeValue = null
rect rgb(255, 220, 220)
Note over FieldFormat: BEFORE FIX (bug)
FieldFormat->>FieldFormat: "render → createDefaultField() → id='X'"
User->>FieldFormat: type 'a' in name input
FieldFormat->>fieldsRef: updateField('X', 'name', 'a')
Note over fieldsRef: storeValueRef.current = null → createDefaultField() → id='Y' (new!)
fieldsRef->>SubBlockStore: map finds no 'X' in ['Y'] → no update
SubBlockStore-->>FieldFormat: storeValue still null → keystroke lost
end
rect rgb(200, 255, 200)
Note over FieldFormat: AFTER FIX
FieldFormat->>FieldFormat: "render → fallbackFieldRef.current ??= createDefaultInputFormatField() → id='X' (cached)"
User->>FieldFormat: type 'a' in name input
FieldFormat->>fieldsRef: updateField('X', 'name', 'a')
Note over fieldsRef: fieldsRef.current = [fallbackField id='X']
fieldsRef->>SubBlockStore: "map finds 'X' → setStoreValue([{id:'X', name:'a', ...}])"
SubBlockStore-->>FieldFormat: "storeValue = [{id:'X', name:'a'}] → re-render OK"
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User
participant FieldFormat
participant fieldsRef
participant SubBlockStore
Note over FieldFormat: Component mounts, storeValue = null
rect rgb(255, 220, 220)
Note over FieldFormat: BEFORE FIX (bug)
FieldFormat->>FieldFormat: "render → createDefaultField() → id='X'"
User->>FieldFormat: type 'a' in name input
FieldFormat->>fieldsRef: updateField('X', 'name', 'a')
Note over fieldsRef: storeValueRef.current = null → createDefaultField() → id='Y' (new!)
fieldsRef->>SubBlockStore: map finds no 'X' in ['Y'] → no update
SubBlockStore-->>FieldFormat: storeValue still null → keystroke lost
end
rect rgb(200, 255, 200)
Note over FieldFormat: AFTER FIX
FieldFormat->>FieldFormat: "render → fallbackFieldRef.current ??= createDefaultInputFormatField() → id='X' (cached)"
User->>FieldFormat: type 'a' in name input
FieldFormat->>fieldsRef: updateField('X', 'name', 'a')
Note over fieldsRef: fieldsRef.current = [fallbackField id='X']
fieldsRef->>SubBlockStore: "map finds 'X' → setStoreValue([{id:'X', name:'a', ...}])"
SubBlockStore-->>FieldFormat: "storeValue = [{id:'X', name:'a'}] → re-render OK"
end
Reviews (2): Last reviewed commit: "simplify" | Re-trigger Greptile |
Summary
Race condition that prevents input format field from being edited sometimes until the "+" is clicked
Type of Change
Testing
Tested manually
Checklist