After creating a remote workflow, push regenerates the local file from the server's response and overwrites the author's source:
// packages/cli/src/core/services/sync-engine.ts:509-516
const tsCode = await WorkflowTransformerAdapter.convertToTypeScript(newWf, {
format: true,
commentStyle: 'verbose'
});
ensureParentDirectory(filePath);
fs.writeFileSync(filePath, tsCode, 'utf-8');
From that moment the server's normalised view is the source of truth for the file on disk. Any field the author wrote that the server does not return is gone from source, with no diff, no warning and no backup.
Observed
A builder in the harness benchmark reported:
push rewrote the local file and dropped the per-node notes fields I had set in the @node decorators.
What is not the cause
The transformer round-trips notes correctly in both directions, so this is not a serialisation gap:
1. parsed notes : "KEEPME" | notesInFlow: true
2. built n8n JSON : "KEEPME" | notesInFlow: true
3. json -> ast : "KEEPME"
4. regenerated file has the note: true
typescript-parser.ts:194, workflow-builder.ts:109 and ast-to-typescript.ts:360 all handle notes/notesInFlow. The value is lost because it does not come back from the instance, and the overwrite then makes that authoritative.
Why the overwrite itself is the bug
The write-back exists for a good reason — the file needs the new workflow id. But it rewrites the whole file to deliver one field. The blast radius is every field the server normalises, not just notes, and it grows silently whenever n8n changes what it echoes.
Suggested fix
Write back only what the push actually learned (the id, and the sync hash), leaving the author's file otherwise untouched. If a full regeneration is wanted, it should be opt-in (push --rewrite) and should report a diff of what it is about to drop rather than performing it silently.
Minimum viable version: after regenerating, compare the node-level metadata of the authored file against the regenerated one and warn on every key that disappeared.
After creating a remote workflow,
pushregenerates the local file from the server's response and overwrites the author's source:From that moment the server's normalised view is the source of truth for the file on disk. Any field the author wrote that the server does not return is gone from source, with no diff, no warning and no backup.
Observed
A builder in the harness benchmark reported:
What is not the cause
The transformer round-trips
notescorrectly in both directions, so this is not a serialisation gap:typescript-parser.ts:194,workflow-builder.ts:109andast-to-typescript.ts:360all handlenotes/notesInFlow. The value is lost because it does not come back from the instance, and the overwrite then makes that authoritative.Why the overwrite itself is the bug
The write-back exists for a good reason — the file needs the new workflow id. But it rewrites the whole file to deliver one field. The blast radius is every field the server normalises, not just
notes, and it grows silently whenever n8n changes what it echoes.Suggested fix
Write back only what the push actually learned (the id, and the sync hash), leaving the author's file otherwise untouched. If a full regeneration is wanted, it should be opt-in (
push --rewrite) and should report a diff of what it is about to drop rather than performing it silently.Minimum viable version: after regenerating, compare the node-level metadata of the authored file against the regenerated one and warn on every key that disappeared.