feat(workflow-executor): serialize recordId as pipe string at front/orchestrator boundaries#1594
Conversation
|
Coverage Impact This PR will not change total coverage. Modified Files with Diff Coverage (5)
🛟 Help
|
…rchestrator boundaries Composite primary keys require multiple ID segments. The frontend cannot handle JSON arrays for IDs, so recordId arrays are serialized to a pipe-separated string (e.g. ['id1', 'id2'] ↔ 'id1|id2') at the three communication boundaries: - Orchestrator → Executor: deserialize selectedRecordId string in the run mapper - Executor → Front: serialize recordId arrays in GET /runs/:runId response - Front → Executor: deserialize selectedRecordId pipe string in POST trigger body Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ports Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ing selectedRecordId input incomingPendingData.selectedRecordId now arrives as a pipe string (e.g. '42') from the front, parsed by the Zod schema to an array. Update test inputs and recordId assertions accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
778bbfd to
7d9cbf4
Compare
| export function serializeRecordId(recordId: Array<string | number>): string { | ||
| return recordId.map(String).join('|'); | ||
| } | ||
|
|
||
| export function deserializeRecordId(value: string): Array<string | number> { | ||
| return value.split('|'); | ||
| } |
There was a problem hiding this comment.
🟡 Medium adapters/record-id-serializer.ts:1
serializeRecordId(["foo|bar", "baz"]) returns "foo|bar|baz", and deserializeRecordId("foo|bar|baz") returns ["foo", "bar", "baz"] — the original array structure is lost when any element contains |. Consider using an escaping scheme or structured format like JSON to preserve element boundaries.
-export function serializeRecordId(recordId: Array<string | number>): string {
- return recordId.map(String).join('|');
-}
+export function serializeRecordId(recordId: Array<string | number>): string {
+ return JSON.stringify(recordId);
+}
export function deserializeRecordId(value: string): Array<string | number> {
- return value.split('|');
+ return JSON.parse(value);
}🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file packages/workflow-executor/src/adapters/record-id-serializer.ts around lines 1-7:
`serializeRecordId(["foo|bar", "baz"])` returns `"foo|bar|baz"`, and `deserializeRecordId("foo|bar|baz")` returns `["foo", "bar", "baz"]` — the original array structure is lost when any element contains `|`. Consider using an escaping scheme or structured format like JSON to preserve element boundaries.
Evidence trail:
packages/workflow-executor/src/adapters/record-id-serializer.ts (lines 1-7, REVIEWED_COMMIT) - the serialize/deserialize functions with no escaping or validation. packages/agent-client/src/record-id.ts (lines 19-25, REVIEWED_COMMIT) - the same codebase's other version that explicitly throws on `|` in elements. packages/agent-client/test/record-id.test.ts (line 37, REVIEWED_COMMIT) - test proving the guard: `expect(() => serializeRecordId(['1|abc', 2])).toThrow(...)`. packages/workflow-executor/src/http/pending-data-validators.ts (line 38, REVIEWED_COMMIT) - `deserializeRecordId` used on user-supplied input via Zod transform.

Summary
serializeRecordId/deserializeRecordIdutility insrc/adapters/record-id-serializer.tsrun-to-available-step-mapper.ts: splits pipe-separatedselectedRecordIdfrom the orchestrator into a proper array ('id1|id2'→['id1', 'id2'])executor-http-server.tsviasrc/http/step-serializer.ts: convertsrecordIdarrays to pipe strings inGET /runs/:runIdresponses (['id1', 'id2']→'id1|id2')pending-data-validators.ts: acceptsselectedRecordIdas a pipe string from POST trigger body and transforms to arrayTest plan
record-id-serializer.test.ts— unit tests for the two utility functionsrun-to-available-step-mapper.test.ts— new test for composite key'pk1|pk2'→['pk1', 'pk2']executor-http-server.test.ts— serialization tests for update-record and load-related-record stepspending-data-validators.test.ts— deserialization tests for pipe-stringselectedRecordId788 tests passing.
fixes PRD-214
🤖 Generated with Claude Code
Note
Serialize
recordIdas pipe-separated string at workflow executor HTTP boundariesserializeRecordIdanddeserializeRecordIdto convert betweenstring[]record ID arrays and pipe-delimited strings (e.g."a|b|c")./runs/:runIdresponse now serializesrecordIdarrays to pipe strings viaserializeStepForWireforread-record,update-record,trigger-action, andload-related-recordstep types./runs/:runId/triggerendpoint now acceptsselectedRecordIdas a pipe-separated string instead of an array, deserializing it internally vialoadRelatedRecordPatchSchema.run-to-available-step-mappernow deserializesrun.selectedRecordIdfrom a pipe string into an array when constructingbaseRecordRef.recordId./runs/:runIdand POST trigger endpoints must now send and expectrecordIdas a pipe-delimited string rather than an array.📊 Macroscope summarized 7d9cbf4. 5 files reviewed, 2 issues evaluated, 0 issues filtered, 1 comment posted
🗂️ Filtered Issues