Skip to content

fix: detect app rename via auto-injected stable id#1118

Open
toiroakr wants to merge 6 commits intomainfrom
fix/rename-app
Open

fix: detect app rename via auto-injected stable id#1118
toiroakr wants to merge 6 commits intomainfrom
fix/rename-app

Conversation

@toiroakr
Copy link
Copy Markdown
Contributor

@toiroakr toiroakr commented May 1, 2026

Summary

  • Inject a stable id: "app-<uuid>" into defineConfig({...}) on first apply/generate and check it into tailor.config.ts.
  • Stamp every managed resource with an sdk-app-id metadata label, alongside the existing sdk-name / sdk-version labels.
  • Determine ownership by the stable id (with name fallback for legacy resources). Renaming the app or any resource now cleanly deletes the old resources and creates the new ones in a single apply.
  • Wrapper configs that re-export defineConfig from another file are skipped on the wrapper; the SDK injects into the file that actually contains the call.

Closes tailor-inc/platform-planning#1070.

How the rename detection works

  • isOwnedByApp(labels, appName, appId) — strict id-precedence: if remote carries sdk-app-id, only an id match counts; otherwise fall back to sdk-name. This prevents an unrelated app that happens to share the same name from being treated as ours.
  • For singular resources (the application itself), application.ts fetches metadata for every existing application in the workspace and detects "renamed-away" apps by id match — they are scheduled for deletion before the new app is created.
  • For list-based resources (TailorDB, Resolver, Auth, IdP, Static Website, Workflow, Executor, Function, Secret Manager), each module's plan loop now uses isOwnedByApp for both conflict checks and orphan deletion.

Test plan

  • Unit tests for isOwnedByApp / hasMatchingSdkVersion (9 cases).
  • Unit tests for ensureConfigId (8 cases: injection, idempotency, wrapper detection, malformed id, multiple defineConfig calls).
  • application.test.ts — 4 new rename scenarios (rename detected by id, same-id same-name no-op, unrelated apps untouched, forRemoval also deletes id-matched renamed apps).
  • e2e/apply.test.ts — uses a shared per-describe id so multi-config tests model a stable app across rewrites.
  • pnpm test — 152 files / 2209 tests passing.
  • pnpm exec turbo run check — 43/43 success.

🤖 Generated with Claude Code

Inject a stable `id: "app-<uuid>"` field into `defineConfig({...})` on
first apply/generate run, and stamp every managed resource with an
`sdk-app-id` metadata label. Ownership is now determined by the stable
id rather than the app name, so renaming the app (or its resources)
cleanly removes the old resources before creating the new ones.

Closes tailor-inc/platform-planning#1070

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@toiroakr toiroakr requested a review from remiposo as a code owner May 1, 2026 15:12
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 1, 2026

🦋 Changeset detected

Latest commit: ac60416

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@tailor-platform/sdk Minor
@tailor-platform/create-sdk Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

⚡ pkg.pr.new

@tailor-platform/sdk

pnpm add https://pkg.pr.new/@tailor-platform/sdk@ac60416
pnpm dlx https://pkg.pr.new/@tailor-platform/sdk@ac60416 --help

@tailor-platform/create-sdk

pnpm add https://pkg.pr.new/@tailor-platform/create-sdk@ac60416
pnpm dlx https://pkg.pr.new/@tailor-platform/create-sdk@ac60416 my-app

commit: ac60416

@claude
Copy link
Copy Markdown

claude Bot commented May 1, 2026

📖 Docs Consistency Check

⚠️ Documentation Gap Found

File Issue Suggested Fix
packages/sdk/docs/cli/application.md The apply and generate commands modify tailor.config.ts on first run by injecting an id field, but this behavior is not documented in the CLI reference Add a note under both apply and generate command sections mentioning the config file modification

Details

What the implementation does:

  • On first apply or generate run, the SDK automatically injects an id: "app-<uuid>" field into the defineConfig({...}) call in tailor.config.ts
  • This is implemented in packages/sdk/src/cli/shared/config-id-injector.ts
  • This is called from both packages/sdk/src/cli/commands/apply/apply.ts and packages/sdk/src/cli/commands/generate/service.ts

What the documentation says:

  • packages/sdk/docs/configuration.md (lines 22, 32): Properly documents that "On first apply (or generate), the SDK injects an id: "app-<uuid>" field into your defineConfig({...}) call"
  • packages/sdk/src/types/app-config.ts (lines 43-47): Proper JSDoc explaining the auto-managed id field
  • example/tailor.config.ts (line 93): Shows the injected id field in practice
  • packages/sdk/docs/cli/application.md: Neither the apply nor generate command documentation mentions this file modification behavior

Why this matters:

  • Users should be aware that running these commands will modify their config file on first run
  • This is similar to how package managers document that they modify lock files
  • The CLI docs already include manual sections for important behavioral details (e.g., "Migration Handling" and "Schema Check" under apply)
  • Users should know to commit this change to version control

Recommended Actions

Add a note to both the apply and generate command sections in packages/sdk/docs/cli/application.md (similar to the existing "Migration Handling" and "Schema Check" sections under apply):

For generate command (after line 90):

**Config File Modification:**

On first run, `generate` automatically injects a stable `id: "app-<uuid>"` field into your `defineConfig({...})` call in `tailor.config.ts`. This identifier is used to track your application across renames. The generated id should be committed to version control. See [Configuration](../configuration.md#application-settings) for details.

For apply command (after line 135, alongside "Migration Handling" and "Schema Check"):

**Config File Modification:**

On first run, `apply` automatically injects a stable `id: "app-<uuid>"` field into your `defineConfig({...})` call in `tailor.config.ts`. This identifier is used to track your application across renames. The generated id should be committed to version control. See [Configuration](../configuration.md#application-settings) for details.

Note: Since application.md contains <!-- politty:... --> markers for auto-generated content, these notes should be added in the manual sections (outside the markers), similar to how "Migration Handling" is documented.


@github-actions

This comment has been minimized.

Move id auto-injection from `generate` (read-only) to `apply` only —
running `generate` against starter templates was mutating their
`tailor.config.ts`, breaking the cross-platform "Generate consistency"
CI check. Also validate any user-provided id against the metadata
label regex (`^[a-z][a-z0-9_-]{0,62}$`) so that an invalid id fails
loudly instead of producing an unusable label downstream.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

This comment has been minimized.

Add `AppConfigSchema` in `parser/app-config/schema.ts` and run it
inside `loadConfig()` so that an invalid config — most importantly an
`id` that does not match the metadata label regex
`^[a-z][a-z0-9_-]{0,62}$` — fails loudly before the SDK starts wiring
resources. Builder-bearing fields (`auth`, `idp`, `db`, ...) are
accepted as opaque values; their shapes are still validated by their
own factory functions and parser-level schemas.

Follows the existing "rich configure type / minimal parser shape"
pattern: `AppConfigParsed` is generated by zinfer from the new schema,
and `expectTypeOf<AppConfig>().toExtend<AppConfigParsed>()` enforces
that the hand-written `AppConfig` interface stays a structural
super-type of the validated shape.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

This comment has been minimized.

toiroakr and others added 3 commits May 7, 2026 22:13
It is only consumed by `apply` now, so colocate it with the other
apply-only modules instead of leaving it in `cli/shared/`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move the `app-` prefix out of the user-facing `id` value: configs now
hold a plain UUID, and the SDK adds the label-compatible `app-` prefix
when stamping `sdk-app-id` and stripping/comparing it in ownership
checks. This keeps the user-facing format clean (just a UUID) while
still satisfying the platform metadata label-value regex internally.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Drop the `app-` prefix from the e2e test's sharedTestAppId so the
injected `id` field passes the new UUID-only validation in
ensureConfigId(). The metadata-side `app-` prefix is now added at the
boundary (label.ts), so configs only need a plain UUID.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

Code Metrics Report (packages/sdk)

main (fa0de36) #1118 (7b2aca6) +/-
Coverage 60.7% 60.9% +0.2%
Code to Test Ratio 1:0.4 1:0.4 +0.0
Details
  |                    | main (fa0de36) | #1118 (7b2aca6) |  +/-  |
  |--------------------|----------------|-----------------|-------|
+ | Coverage           |          60.7% |           60.9% | +0.2% |
  |   Files            |            357 |             359 |    +2 |
  |   Lines            |          12120 |           12246 |  +126 |
+ |   Covered          |           7359 |            7470 |  +111 |
+ | Code to Test Ratio |          1:0.4 |           1:0.4 |  +0.0 |
  |   Code             |          79761 |           80514 |  +753 |
+ |   Test             |          32753 |           33098 |  +345 |

Code coverage of files in pull request scope (65.3% → 66.2%)

Files Coverage +/- Status
packages/sdk/src/cli/commands/apply/test_fixtures/tailor.config.ts 100.0% 0.0% modified
packages/sdk/src/cli/commands/apply/application.ts 80.7% +4.5% modified
packages/sdk/src/cli/commands/apply/apply.ts 82.3% +0.4% modified
packages/sdk/src/cli/commands/apply/auth-connection.ts 30.4% -0.9% modified
packages/sdk/src/cli/commands/apply/auth.ts 68.1% +0.1% modified
packages/sdk/src/cli/commands/apply/config-id-injector.ts 94.7% +94.7% added
packages/sdk/src/cli/commands/apply/executor.ts 79.8% +0.4% modified
packages/sdk/src/cli/commands/apply/function-registry.ts 89.5% +0.0% modified
packages/sdk/src/cli/commands/apply/idp.ts 79.6% +0.2% modified
packages/sdk/src/cli/commands/apply/label.ts 100.0% 0.0% modified
packages/sdk/src/cli/commands/apply/resolver.ts 79.1% -0.3% modified
packages/sdk/src/cli/commands/apply/secret-manager.ts 89.8% +0.1% modified
packages/sdk/src/cli/commands/apply/staticwebsite.ts 75.4% -2.8% modified
packages/sdk/src/cli/commands/apply/tailordb/index.ts 39.1% +0.1% modified
packages/sdk/src/cli/commands/apply/workflow.ts 74.7% -0.7% modified
packages/sdk/src/cli/commands/generate/service.ts 67.6% +0.1% modified
packages/sdk/src/cli/commands/remove.ts 1.3% 0.0% modified
packages/sdk/src/cli/services/application.ts 84.8% 0.0% modified
packages/sdk/src/cli/shared/config-loader.ts 82.9% -5.2% modified
packages/sdk/src/parser/app-config/schema.ts 100.0% +100.0% added
packages/sdk/src/types/app-config.ts 0.0% 0.0% modified

SDK Configure Bundle Size

main (fa0de36) #1118 (7b2aca6) +/-
configure-index-size 17.78KB 17.78KB 0KB
dependency-chunks-size 33.56KB 33.56KB 0KB
total-bundle-size 51.34KB 51.34KB 0KB

Runtime Performance

main (fa0de36) #1118 (7b2aca6) +/-
Generate Median 2,591ms 2,535ms -56ms
Generate Max 2,603ms 2,748ms 145ms
Apply Build Median 2,638ms 2,567ms -71ms
Apply Build Max 2,682ms 2,590ms -92ms

Type Performance (instantiations)

main (fa0de36) #1118 (7b2aca6) +/-
tailordb-basic 35,130 35,130 0
tailordb-optional 3,841 3,841 0
tailordb-relation 7,428 7,428 0
tailordb-validate 2,566 2,566 0
tailordb-hooks 5,767 5,767 0
tailordb-object 12,136 12,136 0
tailordb-enum 2,462 2,462 0
resolver-basic 9,424 9,424 0
resolver-nested 26,111 26,111 0
resolver-array 18,187 18,187 0
executor-schedule 4,234 4,234 0
executor-webhook 873 873 0
executor-record 8,166 8,166 0
executor-resolver 4,369 4,369 0
executor-operation-function 869 869 0
executor-operation-gql 869 869 0
executor-operation-webhook 888 888 0
executor-operation-workflow 1,714 1,714 0

Reported by octocov

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants