Skip to content

[Fleet Execution] Fix hardcoded index in Project.generate projection #316

@jules-fleet

Description

@jules-fleet

Objective

Update the code generator and domain map to support dynamic array searching, fixing the hardcoded index bug in Project.generate() that causes it to fail on subsequent calls when the response structure changes.

Code-Level Diagnosis

Code path: packages/sdk/scripts/ir-schema.ts, packages/sdk/scripts/generate-sdk.ts, and packages/sdk/generated/domain-map.json
Mechanism: The code generator relies on hardcoded indices (e.g., [1]) in ProjectionStep to extract screens from the outputComponents array. If the Stitch backend omits components (like designSystem) on subsequent calls, the index shifts, causing a StitchError.
Root cause: The projection schema and emission logic lack a way to express 'find the first element that matches the rest of the path' instead of 'pick the element at index N'.

Current Implementation

// In packages/sdk/generated/domain-map.json
      "returns": {
        "class": "Screen",
        "projection": [
          {
            "prop": "outputComponents",
            "index": 1
          },
          {
            "prop": "design"
          },
          {
            "prop": "screens",
            "index": 0
          }
        ]
      }

Proposed Implementation

Files to modify: Add findFirst: z.boolean().optional() to ProjectionStep in ir-schema.ts. Add emitFindFirstProjection logic in generate-sdk.ts. Update domain-map.json to replace "index": 1 and "index": 0 with "findFirst": true for generate_screen_from_text and edit_screens.

Integration (Before -> After)

// In packages/sdk/scripts/ir-schema.ts
<<<<<<< SEARCH
  index: z.number().int().min(0).optional(),
  /** Flatten all items via flatMap (replaces [*] glob) */
  each: z.boolean().optional(),
  /** Alternate property name if primary is missing */
  fallback: z.string().optional(),
}).refine(
  data => !(data.index !== undefined && data.each),
  { message: "Cannot use both 'index' and 'each' on the same step" }
);
=======
  index: z.number().int().min(0).optional(),
  /** Flatten all items via flatMap (replaces [*] glob) */
  each: z.boolean().optional(),
  /** Find first matching item applying remaining steps */
  findFirst: z.boolean().optional(),
  /** Alternate property name if primary is missing */
  fallback: z.string().optional(),
}).refine(
  data => {
    let count = 0;
    if (data.index !== undefined) count++;
    if (data.each) count++;
    if (data.findFirst) count++;
    return count <= 1;
  },
  { message: "Cannot use more than one of 'index', 'each', or 'findFirst' on the same step" }
);
>>>>>>> REPLACE

Test Scenarios

  1. Run bun scripts/generate-sdk.ts -> Verify Project.generate now uses (raw?.outputComponents || []).map((a: any) => a?.design?.screens?.[0]).find((x: any) => x).
  2. Run npm run test -> Verify existing generation tests pass.

Target Files

  • packages/sdk/scripts/ir-schema.ts
  • packages/sdk/scripts/generate-sdk.ts
  • packages/sdk/generated/domain-map.json

Boundary Rules

Restrict your modifications exclusively to the files listed in the Target Files section. Ensure your source changes are entirely backward-compatible if unowned tests outside your boundary fail. Retain all existing file names and locations outside your explicitly declared target list.


Fleet Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    fleetFleet-managed issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions