Skip to content

Stand down when a sync belongs to another app in the repo - #119

Merged
arvida merged 2 commits into
mainfrom
fix/841-sync-ownership
Oct 8, 2026
Merged

arvida merged 2 commits into
mainfrom
fix/841-sync-ownership

Conversation

@arvida

@arvida arvida commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Part of localheroai/localhero-ai#841. Server side: localheroai/localhero-ai#860 (merged).

The bug

In a monorepo with one Localhero project per app, every matrix job receives the same localhero-sync dispatch. Each runs ci in sync mode, and the API key is organization-wide, so a sibling app fetches another app's sync and tries to write its files into its own folder. On newsroom-demo that was a red portal job (Source file is required for creating new JSON translation files) and a cancelled editor job.

The change

  • getSyncTranslations sends the config's projectId; the server answers with project_matches, resolved with friendly_id so a slug or a numeric id both work.
  • On project_matches: false, runSyncMode prints one line (a ::notice:: in Actions) and returns before validating config, writing files, saving config, committing, or completing the sync update. ci exits 0: a job that is not the target has nothing to do.
  • No project_matches (older server): unchanged behaviour.

Ownership is checked with the raw config ci() already read, before getValidProjectConfig(), so a sibling app whose config would fail validation still exits 0 instead of failing the matrix.

Also in this branch: the Jest ignore for .claude/ is anchored to <rootDir>. The main checkout still skips worktree copies (#111), and npm test inside a .claude/worktrees/ checkout finds its own tests again instead of none.

Verified

  • Unit tests: mismatch does nothing (multi-page fixture and a sync version, so "no further pages" and "no completion" are real branches); projectId sent on every page.
  • tests/commands/ci-monorepo.test.ts: two app folders on a real filesystem, each with its own localhero.json, run from each. Fails with the guard disabled.
  • Full suite: 1477 passed.
  • Local end to end against the server change with the newsroom-demo monorepo:
    • 0.0.78 from apps/portal reproduces #841, exit 1
    • this branch from apps/portal: notice, exit 0, no file changed
    • this branch from apps/editor: the edit lands, with the slug or the numeric id in localhero.json
    • this branch from apps/portal with outputLocales: []: still exit 0

Not covered locally: the dispatch, the Action matrix and the commit. Next step is an RC on newsroom-demo with portal back in the matrix.

arvida added 2 commits October 8, 2026 09:53
- Send the config's projectId when fetching a sync; the server answers
  with project_matches (localheroai/localhero-ai#841)
- On a mismatch, print a notice and return before validating config,
  writing files, saving config, committing or completing the update
- Exit 0: a job that is not the target has nothing to do
- No project_matches from an older server: behave as before
- Real-filesystem test with two app folders, each with its own
  localhero.json
- Anchor the .claude ignore to <rootDir>, so the main checkout still
  skips worktree copies (#111) while a worktree no longer ignores itself
- Before, npm test in .claude/worktrees/<name> found no tests at all
@arvida
arvida merged commit 7c666fd into main Oct 8, 2026
1 check passed
@arvida arvida mentioned this pull request Oct 8, 2026
arvida added a commit that referenced this pull request Oct 8, 2026
- Monorepo syncs apply only in the app they belong to (#119)
- .po catalogs with #~| obsolete entries are read (#117);
  requires Node.js 20
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.

1 participant