← back to Dw Pitch Followup
fix(notes): FileMaker note-save silently no-op'd — write rep-1 bare key + read-back verify
229cd17c1379f4098c2f7e10e20b050d1be55d20 · 2026-07-15 10:56:36 -0700 · Steve
Root cause: repeating-field rep 1 must be written as the BARE field name ("Internal notes"), not "Internal notes(1)" — the Data API accepts the (1) form with success code 0 but silently ignores it, so notes logged as saved but never persisted (verified: a real save was empty on read-back). Also updateRecord reports committed:true after any non-erroring PATCH without confirming the field changed. Fix: write bare key AND read the record back, throwing if the note is not actually present — never report a save we cannot see.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Files touched
Diff
commit 229cd17c1379f4098c2f7e10e20b050d1be55d20
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Jul 15 10:56:36 2026 -0700
fix(notes): FileMaker note-save silently no-op'd — write rep-1 bare key + read-back verify
Root cause: repeating-field rep 1 must be written as the BARE field name ("Internal notes"), not "Internal notes(1)" — the Data API accepts the (1) form with success code 0 but silently ignores it, so notes logged as saved but never persisted (verified: a real save was empty on read-back). Also updateRecord reports committed:true after any non-erroring PATCH without confirming the field changed. Fix: write bare key AND read the record back, throwing if the note is not actually present — never report a save we cannot see.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
lib/fm-notes.js | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/lib/fm-notes.js b/lib/fm-notes.js
index 2402700..da30738 100644
--- a/lib/fm-notes.js
+++ b/lib/fm-notes.js
@@ -104,14 +104,22 @@ export async function addNote(account, note) {
const prevRO = process.env.FM_READONLY; // defensive: never let a stray read-only flag block or linger
delete process.env.FM_READONLY;
try {
- const res = await client.updateRecord(
+ // REP-1 WRITE FIX: a repeating field's rep 1 must be set via the BARE field name. FileMaker's
+ // Data API accepts "Internal notes(1)" with success code 0 but SILENTLY IGNORES it — the write
+ // no-ops while reporting committed:true (this caused notes to log-as-saved but never persist).
+ await client.updateRecord(
'invoice', INVOICE_LAYOUT, cur.invoiceRecordId,
- { 'Internal notes(1)': toFm(next) },
+ { 'Internal notes': toFm(next) },
{ dryRun: false },
);
- if (!res.committed) throw new Error(res.note || 'FileMaker did not commit the note');
+ // VERIFY: updateRecord's committed:true only means "PATCH didn't error", not "field changed".
+ // Read the record back and confirm the note is actually there — never report a save we can't see.
+ const check = await getNotes(account);
+ if (!check || !String(check.notes || '').includes(line)) {
+ throw new Error('FileMaker accepted the write but the note did not persist — NOT saved');
+ }
+ return { ...cur, notes: check.notes, added: line };
} finally {
if (prevRO !== undefined) process.env.FM_READONLY = prevRO;
}
- return { ...cur, notes: next, added: line };
}
← 109d6a3 Make invoice # on the note chip + notes editor clickable — o
·
back to Dw Pitch Followup
·
chore: lint, refactor (dedup repaint per unique email), v0.4 dcb29c4 →