Repository navigation
Conversation
The Fusion starter repo patches each mirrored Chat template with exact search/replace edits. Agent Native changes broke those edits three times in ten days (most recently #6872), and each break surfaced only hours later as a failed starter sync in another repo. - starters/fusion/ now holds the patch (apply.ts, overlay, owned and delete lists), converted from apply.mjs. push-starter-template.yml copies it to the starter's .github/starter-patch/ on every mirror. - Security guards materializes templates/chat, applies the patch, and applies it again to prove idempotence on PRs that touch templates/chat, packages/core, or starters/fusion, so a break fails the PR that causes it and lands its fix in the same change. - ci-change-scope gains a starter_patch check; starters/fusion changes stay targeted instead of forcing a full run.
Visual recap — generation failedRecap authentication failed — the |
The copy-paste CRUD reference listed and mutated every row with no owner check, so an app built from it let any signed-in user read or change another user's notes. The example table is now ownable, reads go through accessFilter, and writes through assertAccess. updatedAt is written as the ISO string its text column expects. uniqueReplace now fails when the original snippet survives next to its replacement instead of treating the file as patched. Every deleted path is in owned.txt so a later patch that stops deleting one restores it. The docs now say the starter ships homePath "/" (from starter#388) and when to replace it.
|
Closing this in favor of a different approach. Instead of moving the starter's find-and-replace patch here and checking it in CI, the Fusion starter becomes a bundled core scaffold template ( 8903704 on this branch addresses the review findings, and that content is the seed for the new template:
Generated by Claude Code |
There was a problem hiding this comment.
Builder reviewed your changes and found 5 potential issues 🟡
Review Details
Incremental Code Review Summary
The updated commit, 8903704eb, addresses four prior findings: CRUD examples now apply ownership/share access controls and bounded pagination, the timestamp update uses the schema's string representation, replacement handling rejects mixed old/new snippets, and deleted paths are added to the restore manifest. I verified these changes in the current patch and resolved those four prior comment threads, plus the auth landing-route thread after the updated starter documentation now explicitly covers replacing / when the signed-in app moves elsewhere.
The architecture remains sound overall: the patch is still a targeted overlay with materialize/apply/reapply checks, and the expanded data example is safer. This is a standard-risk PR. The incremental review found new concerns in the restoration manifest and several previously identified-but-not-posted functional/CI gaps: one config file modified by the patch still is not restored, the advertised thread navigation still points to a deleted route, and the scope check does not cover Toolkit-only changes despite Toolkit imports in the overlay. The patch also pins pnpm below the version required for its package-age exclusion syntax. Additional medium findings cover the navigation-state reader, domain-operation guard, and migration URL selection.
🧪 Browser testing: Skipped — browser-test-planner is unavailable in this environment.
| DEVELOPING.md | ||
| actions/navigate.ts | ||
| actions/view-screen.ts | ||
| agent-native.json |
There was a problem hiding this comment.
🟡 Restore agent-native.config.ts before reapplying the patch
applyReplacements() changes agent-native.config.ts to add onboarding.firstRun, but this manifest entry is agent-native.json; agent-native.config.ts is absent from the restoration list. A later --source-root sync therefore does not restore the pristine config before reapplying, so the patch can retain stale output or fail to match after upstream changes. Add agent-native.config.ts to this append-only manifest.
| `minimumReleaseAgeExclude: | ||
| - "@agent-native/*" |
There was a problem hiding this comment.
🟡 Use a pnpm version that supports wildcard release-age exclusions
This patch adds the @agent-native/* minimumReleaseAgeExclude pattern, while the generated package manager is pinned to pnpm 10.14.0. That release does not support the minimum-release-age exclusion/wildcard syntax being relied on here, so same-day framework packages may still be rejected by Fusion's install policy; pin to a supporting pnpm version or use syntax supported by the pinned version.
| const threadId = | ||
| typeof command?.threadId === "string" ? command.threadId.trim() : ""; | ||
| return threadId ? `/chat/${encodeURIComponent(threadId)}` : "/"; |
There was a problem hiding this comment.
🟡 Do not navigate to the deleted Chat thread route
When a command includes threadId, this still navigates to /chat/<id>, but delete.txt removes app/routes/chat.$threadId.tsx and the starter intentionally ships without Chat. The supported navigate --threadId=... option therefore lands on a guaranteed 404; remove the thread option/branch or provide the route when Chat is enabled.
| readmeChanged || | ||
| starterPatchChanged, | ||
| qa_static: templateChanged, | ||
| starter_patch: chatChanged || coreChanged || starterPatchChanged, |
There was a problem hiding this comment.
🟡 Run the patch compatibility check for Toolkit changes
The generated overlay imports Toolkit APIs such as AppProviders, ErrorBoundary, and HeaderActionsProvider, but this selector enables the compatibility lane only for Chat, core, or patch changes. A Toolkit-only API change can merge without checking those imports against the patched starter; include toolkitChanged in the selector.
| run: async () => { | ||
| const navigation = await readAppState("navigation"); |
There was a problem hiding this comment.
🟡 Read navigation state from the current tab
The generated root uses useAgentRouteState with browserTabId: TAB_ID, which writes navigation under a tab-scoped key, while this action reads the global navigation key. In normal sessions it therefore returns “No application state found” instead of the visible screen; read the current-tab-scoped key written by the UI.
The Fusion starter (builder-agent-native-starter) builds its blank app from our Chat template. On each sync it applies about 30 exact find-and-replace edits to the mirrored template (
.github/starter-patch/apply.mjson itstemplatebranch). Nothing in this repo runs those edits, so a Chat or skill rewrite here breaks them silently. The break shows up hours later as a failed starter sync in another repo. #6872 broke 20 of them today. Before that, BuilderIO/builder-agent-native-starter#409 (9/28) and BuilderIO/builder-agent-native-starter#413 (9/30) were fixes for the same kind of drift.This PR moves the patch here and checks it on the PRs that can break it, so a break fails in the PR that caused it and its fix lands in the same change.
Changes
starters/fusion/holds the patch: the overlay,owned.txt,delete.txt, andapply.ts(converted fromapply.mjs; Node 24 runs it directly through type stripping). The content matches BuilderIO/builder-agent-native-starter#415 byte for byte. That PR re-anchors the patch on Improve generated app scaffolds and skills #6872's rewrite and converts it to TypeScript on the starter side.push-starter-template.ymlcopiesstarters/fusion/to the starter's.github/starter-patch/on every mirror, and also runs whenstarters/fusion/**changes. The starter'ssync.ymlkeeps applying the patch at merge time, afterskills update scaffold, so the patch still runs at the same point in the sync.Security guardsjob gains a step, "Fusion starter patch applies to the Chat template". It materializestemplates/chat, applies the patch, then applies it again and requires a clean tree. It takes about 2 seconds, so it joins an existing job instead of adding one.ci-change-scope.tsgains astarter_patchcheck that turns on fortemplates/chat/,packages/core/, orstarters/fusion/changes. A change only understarters/fusion/selectslint,guardsandstarter_patch, the same treatment as a guard-script change. Without this, it would fall through to a full run..oxlintrc.jsonignoresstarters/**, as it already doespackages/core/src/templates/**. The overlay is app code that only type-resolves inside the starter, and the starter lints and builds it there.Verification
The check catches the real break: the pre-Improve onboarding auth and shared design systems #415 patch from the starter's
templatebranch fails on today's materialized Chat template withexpected snippet not found in .../AGENTS.md, the same error the starter sync hit. The current patch applies cleanly and comes back clean on the second application.The classifier on real
maincommits:starter_patch61543b29(Improve generated app scaffolds and skills #6872)4a6dcd0c(docs only)ed781044(Content fix)Classifier tests:
node --experimental-strip-types --test scripts/ci-change-scope.test.ts scripts/ci-build-workspaces.test.ts scripts/ci-test-lanes.test.tspasses 62/62. The new cases cover the check being on, off, on for astarters/fusion-only change, and on for full or tooling-only runs.Repo checks:
pnpm guardspasses all 85 checks. The new content needed Agent-Native branding, UTM tags on the shipped README links, andcoercion-okreasons on two catches that intentionally treat failure as absent.oxfmt --checkis clean.Typecheck:
apply.tspasses stricttscagainst@types/node.The patched starter builds: on the patched tree,
pnpm install,typecheck,build, andagent-native doctorall pass. Install resolves@agent-native/otel@0.1.0.Rollout
Merge starter#415 first, or at the same time. It switches the starter's
sync.ymltoapply.ts, and the first mirror after this PR then copies over identical content. After that, starter-patch edits belong in this repo. The starter README now says so, and a direct edit there would be overwritten by the next mirror.🤖 Generated with Claude Code
https://claude.ai/code/session_01RUDitSt3FB37KqMKfQgkJj