Promote main -> release (conflict-resolved) - #5433
Conversation
…eature (tinyhumansai#5049) (tinyhumansai#5061) Co-authored-by: Steven Enamakel <31011319+senamakel@users.noreply.github.com>
…nscript (ChatThreadView) (tinyhumansai#5097)
…ansai#5091) Co-authored-by: Cursor <cursoragent@cursor.com>
…ai#4786) Co-authored-by: Sami Rusani <14844597+samrusani@users.noreply.github.com>
…inyhumansai#4772) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: binyangzhu000-sudo <224954946+binyangzhu000-sudo@users.noreply.github.com> Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
…nsai#5103) Co-authored-by: Sami Rusani <14844597+samrusani@users.noreply.github.com>
…ting/http-server gates (tinyhumansai#5048) (tinyhumansai#5068)
…4929) (tinyhumansai#4998) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Steven Enamakel <31011319+senamakel@users.noreply.github.com> Co-authored-by: Cyrus Gray <144336577+graycyrus@users.noreply.github.com> Co-authored-by: oxoxDev <164490987+oxoxDev@users.noreply.github.com> Co-authored-by: YellowSnnowmann <167776381+YellowSnnowmann@users.noreply.github.com> Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai> Co-authored-by: CodeGhost21 <164498022+CodeGhost21@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: sanil-23 <sanil@tinyhumans.ai> Co-authored-by: M3gA-Mind <elvin@mahadao.com> Co-authored-by: oxoxDev <oxoxdev@users.noreply.github.com>
Co-authored-by: Sami Rusani <14844597+samrusani@users.noreply.github.com> Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
…roval prompt (tinyhumansai#5094) Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
…d profiling optimizations (tinyhumansai#5107)
…completes epic tinyhumansai#4795 (tinyhumansai#5029) Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai>
…umansai#5365) Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ansai#5366) Co-authored-by: Medulla <medulla@tinyhumans.ai>
…transcript soak (tinyhumansai#5396) Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ssor (tinyhumansai#5405) Co-authored-by: Medulla <medulla@tinyhumans.ai>
…nyhumansai#5401) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ers (tinyhumansai#5367) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…local-agent relay handler (tinyhumansai#5399) (tinyhumansai#5407)
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…the parked queue (tinyhumansai#5427) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Brings release to main's tree at 8deb5f2. The only files that differ from main are the six version-bearing ones, held at release's v0.63.10 rather than main's v0.63.6 — a release must never go backwards. All 13 conflicts were squash-trap artifacts, not divergence. Release's nine unique commits are five version bumps, three squashed promotes of main's own content, and one appimage fix (tinyhumansai#5251) whose two files are byte-identical to main's copy (tinyhumansai#5252). Verified further: main and release differ in 37 paths, every one a modification with nothing added or deleted in either direction, and every one of release's blobs is reachable in main's history — so release carries no code main lacks. The conflicts arise because the promotes were squash-merged, freezing the merge-base at 2219d42, so git cannot see that release already holds main's tree and re-derives the kernelization's own moves as add/add and rename/delete pairs.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
@coderabbitai review |
📝 WalkthroughWalkthroughThe PR adds failed Memory Tree job retries, local mascot image uploads, realtime voice token forwarding, scoped cloud credential resolution, failure-cause supersession, localized messages, tests, analytics support, and a TinyCortex revision update. ChangesMemory Tree retry flow
Mascot image avatars
Realtime voice session
Cloud credentials
TinyCortex reference
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6c3d648263
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| type MemorySyncStatusRow, | ||
| memoryTreePipelineStatus, | ||
| type MemoryTreePipelineStatus, | ||
| memoryTreeRetryFailed, |
There was a problem hiding this comment.
Recreate this as a real promote merge
This is a commit-level issue rather than a problem with this import: git rev-list --parents -n 1 40a0edc4 shows only parent 2ba803a246f8af20e3278c8acb62f34be2b421f5 and does not record 8deb5f2769c97ad059be2a6acae9f23c9c00dc3b as a second parent, even though the release promotion path is supposed to be a merge from main into release. If this lands, main is still not an ancestor of release, so the next promote/back-merge keeps the stale merge-base and re-fights these same conflicts; recreate it as a true two-parent merge before merging.
Useful? React with 👍 / 👎.
| if (!isAllowedMimeType(file.type)) { | ||
| console.debug('[mascot-avatar] rejected upload: unsupported type', file.type); | ||
| setCustomGifError(t('settings.mascot.customGifInvalidType')); | ||
| return; |
There was a problem hiding this comment.
Invalidate pending uploads on rejected file picks
If a valid avatar is already being read and the user then chooses an unsupported or too-large file, these early-return validation branches do not increment avatarWriteIdRef. The older read still sees its writeId as current, clears the new error, and dispatches the stale avatar, so a rejected second selection can still leave the first image saved; bump the write id before any validation return.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 10
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/components/settings/panels/MascotPanel.tsx`:
- Around line 223-226: Update the Upload image Button and accepted-upload
handling in MascotPanel: assign the Button a stable content-free analyticsId,
and call trackAnalyticsEvent only after the accepted upload has been stored via
setCustomMascotGifUrl. Use only non-sensitive fixed dimensions, excluding
File.name, the data URL, and error text.
- Around line 200-213: Update onUploadAvatarFile so avatarWriteIdRef is
incremented immediately after the !file guard, before MIME-type and size
validation, invalidating any pending valid read when a replacement file is
rejected. Preserve the existing rejection errors and add coverage for a pending
valid read followed by an invalid file selection.
In `@app/src/lib/i18n/ar.ts`:
- Line 5726: Update the Arabic translation string for
settings.mascot.customGifError to remove the local-URL wording while preserving
the HTTPS URL option, upload action, and supported image formats.
In `@app/src/lib/i18n/de.ts`:
- Around line 1354-1355: Update the German translations for
memoryTree.status.retryFailed and memoryTree.status.retryFailedBusy to describe
requeuing failed jobs rather than executing them, matching the wording used by
memoryTree.status.retryFailedDone and keeping the action and busy-state
terminology consistent.
- Line 6020: Update the German user-facing message in the translation entry to
describe HTTPS, file://, and local paths as parallel supported Bild-URL forms,
while retaining the existing PNG, GIF, JPEG, WebP, and BMP formats and the
upload option. Keep the message limited to normal URL and file-upload paths.
In `@app/src/lib/i18n/fr.ts`:
- Around line 5998-6000: Update the French custom mascot localization entries,
including settings.mascot.customGifHeading, settings.mascot.customGifLabel, and
the related message at the second occurrence, to use natural “image d’avatar
personnalisée” wording. Replace implementation-specific file:// language with
concise user-facing guidance describing a local path, while preserving the
supported image-format and URL/upload guidance.
In `@app/src/lib/i18n/hi.ts`:
- Line 5970: Update the persona appearance description string in hi.ts to use
the plural Hindi agreement ending for the three listed settings, replacing the
singular “कॉन्फ़िगर किया गया है” while preserving the rest of the translation.
- Around line 5855-5863: Update the user-facing custom mascot image URL error
message near the preceding mascot settings translations to mention only HTTPS
image URLs and file uploads. Remove the file:// and स्थानीय इमेज URL guidance,
while retaining PNG, GIF, JPEG, WebP, and BMP in the supported format list.
In `@src/openhuman/memory/tree/tree/rpc.rs`:
- Around line 1889-1933: Extend the test coverage around plant_failed_and_done
to create a failed job with a typed failure and completed_at_ms set to NULL,
then assert latest_failed_job_failure returns the expected PipelineFailure. Add
a separate helper or test setup path rather than requiring failed_at_ms, while
preserving the existing timestamped failed-row coverage.
In `@vendor/tinycortex`:
- Line 1: Update requeue_failed_where so failed rows whose dedupe key exists in
active_keys are marked cancelled and have their failure fields cleared before
being skipped. Ensure retry_all_failed no longer leaves these stale failures
counted, while preserving existing requeue behavior for other failed rows.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 349a0a86-4d8e-44bd-bc31-089da4e0391b
📒 Files selected for processing (31)
app/src/components/intelligence/MemoryTreeStatusPanel.test.tsxapp/src/components/intelligence/MemoryTreeStatusPanel.tsxapp/src/components/settings/panels/MascotPanel.tsxapp/src/components/settings/panels/__tests__/MascotPanel.test.tsxapp/src/features/human/voice/useRealtimeVoiceSession.test.tsapp/src/features/human/voice/useRealtimeVoiceSession.tsapp/src/lib/i18n/ar.tsapp/src/lib/i18n/bn.tsapp/src/lib/i18n/de.tsapp/src/lib/i18n/en.tsapp/src/lib/i18n/es.tsapp/src/lib/i18n/fr.tsapp/src/lib/i18n/hi.tsapp/src/lib/i18n/id.tsapp/src/lib/i18n/it.tsapp/src/lib/i18n/ko.tsapp/src/lib/i18n/pl.tsapp/src/lib/i18n/pt.tsapp/src/lib/i18n/ru.tsapp/src/lib/i18n/zh-CN.tsapp/src/services/analytics.tsapp/src/store/__tests__/mascotSlice.test.tsapp/src/store/mascotSlice.tsapp/src/utils/tauriCommands/memoryTree.test.tsapp/src/utils/tauriCommands/memoryTree.tssrc/openhuman/config/mod.rssrc/openhuman/config/schema/load/mod.rssrc/openhuman/config/schema/mod.rssrc/openhuman/inference/embeddings/cloud_adapter.rssrc/openhuman/memory/tree/tree/rpc.rsvendor/tinycortex
| const onUploadAvatarFile = async (file: File | undefined) => { | ||
| if (!file) return; | ||
| if (!isAllowedMimeType(file.type)) { | ||
| console.debug('[mascot-avatar] rejected upload: unsupported type', file.type); | ||
| setCustomGifError(t('settings.mascot.customGifInvalidType')); | ||
| return; | ||
| } | ||
| if (file.size > MAX_CUSTOM_MASCOT_AVATAR_UPLOAD_BYTES) { | ||
| console.debug('[mascot-avatar] rejected upload: too large', file.size); | ||
| setCustomGifError(t('settings.mascot.customGifTooLarge')); | ||
| return; | ||
| } | ||
| avatarWriteIdRef.current += 1; | ||
| const writeId = avatarWriteIdRef.current; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Invalidate pending reads before rejecting a replacement file.
Lines 202-211 return before incrementing avatarWriteIdRef. If a valid upload is still reading, then the user selects an invalid or oversize file, the earlier read remains current and can later set the avatar despite the rejection error.
Increment the write ID immediately after the !file check. Add a test where a pending valid read is followed by an invalid file selection.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/components/settings/panels/MascotPanel.tsx` around lines 200 - 213,
Update onUploadAvatarFile so avatarWriteIdRef is incremented immediately after
the !file guard, before MIME-type and size validation, invalidating any pending
valid read when a replacement file is rejected. Preserve the existing rejection
errors and add coverage for a pending valid read followed by an invalid file
selection.
| console.debug('[mascot-avatar] upload accepted', file.type, file.size); | ||
| setCustomGifError(null); | ||
| setCustomGifDraft(''); | ||
| dispatch(setCustomMascotGifUrl(dataUri)); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add required analytics for the upload flow.
Give the Upload image Button a stable, content-free analyticsId. Call trackAnalyticsEvent only after an accepted upload is stored. Do not send File.name, the data URL, or error text in analytics dimensions.
Also applies to: 690-697
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/components/settings/panels/MascotPanel.tsx` around lines 223 - 226,
Update the Upload image Button and accepted-upload handling in MascotPanel:
assign the Button a stable content-free analyticsId, and call
trackAnalyticsEvent only after the accepted upload has been stored via
setCustomMascotGifUrl. Use only non-sensitive fixed dimensions, excluding
File.name, the data URL, and error text.
Sources: Coding guidelines, Learnings
| 'settings.mascot.customGifHeading': 'الصورة الرمزية GIF المخصصة', | ||
| 'settings.mascot.customGifLabel': 'الصورة الرمزية GIF المخصصة URL', | ||
| 'settings.mascot.customGifPlaceholder': 'https://example.com/avatar.gif', | ||
| 'أدخل رابط صورة HTTPS أو file:// أو رابطًا محليًا (PNG أو GIF أو JPEG أو WebP أو BMP)، أو ارفع ملفًا.', |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Remove the local-URL implementation detail.
“رابطًا محليًا” exposes the developer-oriented loopback URL path. Keep the HTTPS URL, upload action, and supported format list.
Proposed fix
- 'أدخل رابط صورة HTTPS أو file:// أو رابطًا محليًا (PNG أو GIF أو JPEG أو WebP أو BMP)، أو ارفع ملفًا.',
+ 'أدخل رابط صورة HTTPS أو file:// (PNG أو GIF أو JPEG أو WebP أو BMP)، أو ارفع ملفًا.',Based on learnings, “Do not enumerate … developer-oriented loopback HTTP URLs” in settings.mascot.customGifError.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 'أدخل رابط صورة HTTPS أو file:// أو رابطًا محليًا (PNG أو GIF أو JPEG أو WebP أو BMP)، أو ارفع ملفًا.', | |
| 'أدخل رابط صورة HTTPS أو file:// (PNG أو GIF أو JPEG أو WebP أو BMP)، أو ارفع ملفًا.', |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/lib/i18n/ar.ts` at line 5726, Update the Arabic translation string
for settings.mascot.customGifError to remove the local-URL wording while
preserving the HTTPS URL option, upload action, and supported image formats.
Source: Learnings
| 'memoryTree.status.retryFailed': 'Fehlgeschlagene Jobs erneut ausführen', | ||
| 'memoryTree.status.retryFailedBusy': 'Wird wiederholt...', |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Align the retry wording with the command behavior.
memoryTree.status.retryFailed says that failed jobs are executed again. This command requeues them. Use the same wording as memoryTree.status.retryFailedDone for the action and busy state.
Based on the PR objective, the retry command requeues failed Memory Tree jobs rather than executing them immediately.
Suggested wording
- 'memoryTree.status.retryFailed': 'Fehlgeschlagene Jobs erneut ausführen',
- 'memoryTree.status.retryFailedBusy': 'Wird wiederholt...',
+ 'memoryTree.status.retryFailed': 'Fehlgeschlagene Jobs erneut einreihen',
+ 'memoryTree.status.retryFailedBusy':
+ 'Fehlgeschlagene Jobs werden erneut eingereiht…',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 'memoryTree.status.retryFailed': 'Fehlgeschlagene Jobs erneut ausführen', | |
| 'memoryTree.status.retryFailedBusy': 'Wird wiederholt...', | |
| 'memoryTree.status.retryFailed': 'Fehlgeschlagene Jobs erneut einreihen', | |
| 'memoryTree.status.retryFailedBusy': | |
| 'Fehlgeschlagene Jobs werden erneut eingereiht…', |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/lib/i18n/de.ts` around lines 1354 - 1355, Update the German
translations for memoryTree.status.retryFailed and
memoryTree.status.retryFailedBusy to describe requeuing failed jobs rather than
executing them, matching the wording used by memoryTree.status.retryFailedDone
and keeping the action and busy-state terminology consistent.
| 'settings.mascot.customGifHeading': 'Benutzerdefinierter GIF-Avatar', | ||
| 'settings.mascot.customGifLabel': 'URL für benutzerdefinierten GIF-Avatar', | ||
| 'settings.mascot.customGifPlaceholder': 'https://example.com/avatar.gif', | ||
| 'Gib eine HTTPS-, file:// oder lokale Bild-URL (PNG, GIF, JPEG, WebP oder BMP) ein oder lade eine Datei hoch.', |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Clarify the URL forms in the error message.
HTTPS-, file:// oder lokale Bild-URL is not a parallel German phrase. Keep the same supported schemes and formats, but describe them as one Bild-URL list.
Based on learnings, keep this user-facing message limited to normal URL and upload paths, and keep BMP in the format list.
Suggested wording
- 'Gib eine HTTPS-, file:// oder lokale Bild-URL (PNG, GIF, JPEG, WebP oder BMP) ein oder lade eine Datei hoch.',
+ 'Gib eine Bild-URL über HTTPS oder file:// (PNG, GIF, JPEG, WebP oder BMP) ein oder lade eine Datei hoch.',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 'Gib eine HTTPS-, file:// oder lokale Bild-URL (PNG, GIF, JPEG, WebP oder BMP) ein oder lade eine Datei hoch.', | |
| 'Gib eine Bild-URL über HTTPS oder file:// (PNG, GIF, JPEG, WebP oder BMP) ein oder lade eine Datei hoch.', |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/lib/i18n/de.ts` at line 6020, Update the German user-facing message
in the translation entry to describe HTTPS, file://, and local paths as parallel
supported Bild-URL forms, while retaining the existing PNG, GIF, JPEG, WebP, and
BMP formats and the upload option. Keep the message limited to normal URL and
file-upload paths.
Source: Learnings
| 'Saisissez une URL d’image HTTPS, file:// ou locale (PNG, GIF, JPEG, WebP ou BMP), ou importez un fichier.', | ||
| 'settings.mascot.customGifHeading': 'Avatar image personnalisé', | ||
| 'settings.mascot.customGifLabel': 'URL de l’avatar image personnalisé', |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use natural French for the custom avatar wording.
Avatar image personnalisé, URL de l’avatar image personnalisé, and avatar personnalisé en image are not idiomatic French. The file:// wording is also too implementation-specific and ambiguous for users.
Use image d’avatar personnalisée and describe the local option as a local path.
Proposed wording
- 'Saisissez une URL d’image HTTPS, file:// ou locale (PNG, GIF, JPEG, WebP ou BMP), ou importez un fichier.',
- 'settings.mascot.customGifHeading': 'Avatar image personnalisé',
- 'settings.mascot.customGifLabel': 'URL de l’avatar image personnalisé',
+ 'Saisissez une URL d’image HTTPS ou un chemin local (PNG, GIF, JPEG, WebP ou BMP), ou importez un fichier.',
+ 'settings.mascot.customGifHeading': 'Image d’avatar personnalisée',
+ 'settings.mascot.customGifLabel': 'URL de l’image d’avatar personnalisée',
...
- "La couleur de la mascotte, l'avatar personnalisé en image et la voix de réponse sont configurés dans les paramètres de la mascotte.",
+ "La couleur de la mascotte, l'image d'avatar personnalisée et la voix de réponse sont configurées dans les paramètres de la mascotte.",Based on learnings, keep custom avatar messages concise and focused on user-facing URL and upload guidance.
Also applies to: 6117-6117
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/lib/i18n/fr.ts` around lines 5998 - 6000, Update the French custom
mascot localization entries, including settings.mascot.customGifHeading,
settings.mascot.customGifLabel, and the related message at the second
occurrence, to use natural “image d’avatar personnalisée” wording. Replace
implementation-specific file:// language with concise user-facing guidance
describing a local path, while preserving the supported image-format and
URL/upload guidance.
Source: Learnings
| 'HTTPS, file://, या स्थानीय इमेज URL (PNG, GIF, JPEG, WebP, या BMP) दर्ज करें, या कोई फ़ाइल अपलोड करें।', | ||
| 'settings.mascot.customGifHeading': 'कस्टम इमेज अवतार', | ||
| 'settings.mascot.customGifLabel': 'कस्टम इमेज अवतार URL', | ||
| 'settings.mascot.customGifPlaceholder': 'https://example.com/avatar.png', | ||
| 'settings.mascot.customGifUpload': 'इमेज अपलोड करें', | ||
| 'settings.mascot.customGifInvalidType': | ||
| 'असमर्थित फ़ाइल प्रकार। PNG, GIF, JPEG, WebP, या BMP इमेज अपलोड करें।', | ||
| 'settings.mascot.customGifTooLarge': 'इमेज बहुत बड़ी है। 1.5 MB तक की फ़ाइल अपलोड करें।', | ||
| 'settings.mascot.customGifReadError': 'यह इमेज पढ़ी नहीं जा सकी। कृपया दूसरी फ़ाइल आज़माएँ।', |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Remove implementation-only URL schemes from the user-facing error.
The message already directs users to upload a file, but it also lists file:// and स्थानीय इमेज URL. These inputs are not clear normal user guidance. Focus the message on HTTPS image URLs and file uploads. Keep BMP in the format list.
Based on learnings: custom mascot avatar errors should omit developer-only URL inputs and include BMP when upload validation supports it.
Proposed wording
'settings.mascot.customGifError':
- 'HTTPS, file://, या स्थानीय इमेज URL (PNG, GIF, JPEG, WebP, या BMP) दर्ज करें, या कोई फ़ाइल अपलोड करें।',
+ 'एक HTTPS इमेज URL दर्ज करें, या PNG, GIF, JPEG, WebP, या BMP फ़ाइल अपलोड करें।',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 'HTTPS, file://, या स्थानीय इमेज URL (PNG, GIF, JPEG, WebP, या BMP) दर्ज करें, या कोई फ़ाइल अपलोड करें।', | |
| 'settings.mascot.customGifHeading': 'कस्टम इमेज अवतार', | |
| 'settings.mascot.customGifLabel': 'कस्टम इमेज अवतार URL', | |
| 'settings.mascot.customGifPlaceholder': 'https://example.com/avatar.png', | |
| 'settings.mascot.customGifUpload': 'इमेज अपलोड करें', | |
| 'settings.mascot.customGifInvalidType': | |
| 'असमर्थित फ़ाइल प्रकार। PNG, GIF, JPEG, WebP, या BMP इमेज अपलोड करें।', | |
| 'settings.mascot.customGifTooLarge': 'इमेज बहुत बड़ी है। 1.5 MB तक की फ़ाइल अपलोड करें।', | |
| 'settings.mascot.customGifReadError': 'यह इमेज पढ़ी नहीं जा सकी। कृपया दूसरी फ़ाइल आज़माएँ।', | |
| 'एक HTTPS इमेज URL दर्ज करें, या PNG, GIF, JPEG, WebP, या BMP फ़ाइल अपलोड करें।', | |
| 'settings.mascot.customGifHeading': 'कस्टम इमेज अवतार', | |
| 'settings.mascot.customGifLabel': 'कस्टम इमेज अवतार URL', | |
| 'settings.mascot.customGifPlaceholder': 'https://example.com/avatar.png', | |
| 'settings.mascot.customGifUpload': 'इमेज अपलोड करें', | |
| 'settings.mascot.customGifInvalidType': | |
| 'असमर्थित फ़ाइल प्रकार। PNG, GIF, JPEG, WebP, या BMP इमेज अपलोड करें।', | |
| 'settings.mascot.customGifTooLarge': 'इमेज बहुत बड़ी है। 1.5 MB तक की फ़ाइल अपलोड करें।', | |
| 'settings.mascot.customGifReadError': 'यह इमेज पढ़ी नहीं जा सकी। कृपया दूसरी फ़ाइल आज़माएँ।', |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/lib/i18n/hi.ts` around lines 5855 - 5863, Update the user-facing
custom mascot image URL error message near the preceding mascot settings
translations to mention only HTTPS image URLs and file uploads. Remove the
file:// and स्थानीय इमेज URL guidance, while retaining PNG, GIF, JPEG, WebP, and
BMP in the supported format list.
Source: Learnings
| 'settings.persona.appearanceHeading': 'अवतार और आवाज', | ||
| 'settings.persona.appearanceDesc': | ||
| 'Mascot रंग, कस्टम GIF अवतार, और उत्तर आवाज Mascot सेटिंग्स में कॉन्फ़िगर किया गया है।', | ||
| 'Mascot रंग, कस्टम इमेज अवतार, और उत्तर आवाज Mascot सेटिंग्स में कॉन्फ़िगर किया गया है।', |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Fix plural agreement in the persona appearance description.
The sentence lists three settings but uses the singular ending कॉन्फ़िगर किया गया है. Use plural agreement.
Proposed wording
- 'Mascot रंग, कस्टम इमेज अवतार, और उत्तर आवाज Mascot सेटिंग्स में कॉन्फ़िगर किया गया है।',
+ 'Mascot का रंग, कस्टम इमेज अवतार और उत्तर की आवाज़ Mascot सेटिंग्स में कॉन्फ़िगर किए जाते हैं।',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 'Mascot रंग, कस्टम इमेज अवतार, और उत्तर आवाज Mascot सेटिंग्स में कॉन्फ़िगर किया गया है।', | |
| 'Mascot का रंग, कस्टम इमेज अवतार और उत्तर की आवाज़ Mascot सेटिंग्स में कॉन्फ़िगर किए जाते हैं।', |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/lib/i18n/hi.ts` at line 5970, Update the persona appearance
description string in hi.ts to use the plural Hindi agreement ending for the
three listed settings, replacing the singular “कॉन्फ़िगर किया गया है” while
preserving the rest of the translation.
| fn plant_failed_and_done( | ||
| cfg: &Config, | ||
| reason: &str, | ||
| failed_at_ms: i64, | ||
| done_at_ms: Option<i64>, | ||
| ) { | ||
| use crate::openhuman::memory::queue::store as queue_store; | ||
| use crate::openhuman::memory::queue::types::{FlushStalePayload, NewJob}; | ||
|
|
||
| let failed_job = | ||
| NewJob::flush_stale(&FlushStalePayload::default(), "2026-07-10", 3).unwrap(); | ||
| let failed_id = queue_store::enqueue(cfg, &failed_job) | ||
| .unwrap() | ||
| .expect("enqueue failed-row"); | ||
|
|
||
| let done_id = done_at_ms.map(|_| { | ||
| let done_job = | ||
| NewJob::flush_stale(&FlushStalePayload::default(), "2026-08-06", 3).unwrap(); | ||
| queue_store::enqueue(cfg, &done_job) | ||
| .unwrap() | ||
| .expect("enqueue done-row") | ||
| }); | ||
|
|
||
| chunk_store::with_connection(cfg, |conn| { | ||
| conn.execute( | ||
| "UPDATE mem_tree_jobs | ||
| SET status = 'failed', | ||
| failure_reason = ?2, | ||
| failure_class = 'unrecoverable', | ||
| completed_at_ms = ?3 | ||
| WHERE id = ?1", | ||
| rusqlite::params![failed_id, reason, failed_at_ms], | ||
| )?; | ||
| if let (Some(done_id), Some(done_at_ms)) = (done_id.as_ref(), done_at_ms) { | ||
| conn.execute( | ||
| "UPDATE mem_tree_jobs | ||
| SET status = 'done', completed_at_ms = ?2 | ||
| WHERE id = ?1", | ||
| rusqlite::params![done_id, done_at_ms], | ||
| )?; | ||
| } | ||
| Ok(()) | ||
| }) | ||
| .unwrap(); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Cover the legacy failed-row branch.
Line 1892 requires a non-null failed_at_ms. Line 1920 always writes it to completed_at_ms. The new tests therefore do not exercise Lines 743-748, where a typed failure without a timestamp must remain visible.
Add a test that writes completed_at_ms = NULL for a typed failed row and asserts that latest_failed_job_failure returns its PipelineFailure.
As per coding guidelines, add tests for new or changed behavior.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/openhuman/memory/tree/tree/rpc.rs` around lines 1889 - 1933, Extend the
test coverage around plant_failed_and_done to create a failed job with a typed
failure and completed_at_ms set to NULL, then assert latest_failed_job_failure
returns the expected PipelineFailure. Add a separate helper or test setup path
rather than requiring failed_at_ms, while preserving the existing timestamped
failed-row coverage.
Source: Coding guidelines
| @@ -1 +1 @@ | |||
| Subproject commit e0a8738980965411f514f4a62c09f941efdea90c | |||
| Subproject commit 5fabcf18d9e3907d6b26b59528ad49cebfc1c271 | |||
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
submodule="vendor/tinycortex"
old="e0a8738980965411f514f4a62c09f941efdea90c"
new="5fabcf18d9e3907d6b26b59528ad49cebfc1c271"
url="$(git config -f .gitmodules --get "submodule.${submodule}.url")"
test -n "$url"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
git init -q "$tmp/repo"
git -C "$tmp/repo" remote add origin "$url"
git -C "$tmp/repo" fetch --quiet --no-tags origin "$old" "$new"
git -C "$tmp/repo" cat-file -e "${old}^{commit}"
git -C "$tmp/repo" cat-file -e "${new}^{commit}"
echo "Changed files:"
git -C "$tmp/repo" diff --name-status "$old" "$new"
echo "Diff summary:"
git -C "$tmp/repo" diff --stat "$old" "$new"
echo "Relevant API definitions:"
for revision in "$old" "$new"; do
echo "== $revision =="
git -C "$tmp/repo" grep -n -E 'self_heal|run_summarization_observed' "$revision" -- || true
doneRepository: tinyhumansai/openhuman
Length of output: 10544
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
submodule="vendor/tinycortex"
old="e0a8738980965411f514f4a62c09f941efdea90c"
new="5fabcf18d9e3907d6b26b59528ad49cebfc1c271"
url="$(git config -f .gitmodules --get "submodule.${submodule}.url")"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
git init -q "$tmp/repo"
git -C "$tmp/repo" remote add origin "$url"
git -C "$tmp/repo" fetch --quiet --no-tags origin "$old" "$new"
echo "=== TinyCortex diff ==="
git -C "$tmp/repo" diff --find-renames --find-copies --unified=80 "$old" "$new" -- \
src/memory/queue/store_settle.rs \
src/memory/queue/store_settle_tests.rs
echo "=== API definitions at both revisions ==="
for revision in "$old" "$new"; do
echo "--- $revision: scheduler.rs ---"
git -C "$tmp/repo" show "$revision:src/memory/queue/scheduler.rs" | sed -n '1,180p'
echo "--- $revision: tree/runtime/engine.rs ---"
git -C "$tmp/repo" show "$revision:src/memory/tree/runtime/engine.rs" | sed -n '1,180p'
done
echo "=== Parent call sites ==="
rg -n -C 8 'tinycortex|self_heal|run_summarization_observed' \
src vendor/tinycortex 2>/dev/null || trueRepository: tinyhumansai/openhuman
Length of output: 50379
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
log="/tmp/coderabbit-shell-logs/shell-output-qMXSEv"
echo "=== Diff section markers ==="
rg -n '^===|^---|^diff --git|^@@' "$log" | head -n 200
echo "=== Relevant caller sections ==="
rg -n -C 12 'self_heal|run_summarization_observed' "$log" | head -n 500
echo "=== TinyCortex changed-file diff excerpts ==="
python3 - "$log" <<'PY'
from pathlib import Path
import sys
text = Path(sys.argv[1]).read_text(errors="replace")
start = text.find("=== TinyCortex diff ===")
end = text.find("=== API definitions at both revisions ===")
if start < 0 or end < 0:
raise SystemExit("diff markers not found")
section = text[start:end]
lines = section.splitlines()
for i, line in enumerate(lines):
if line.startswith("diff --git") or line.startswith("@@") or "self_heal" in line or "store_settle" in line:
lo = max(0, i - 20)
hi = min(len(lines), i + 80)
print("\n".join(lines[lo:hi]))
print("\n--- excerpt boundary ---")
PYRepository: tinyhumansai/openhuman
Length of output: 47144
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
log="/tmp/coderabbit-shell-logs/shell-output-wgRFSN"
echo "=== Exact changed implementation ==="
sed -n '1,240p' "$log"
echo "=== Parent scheduler and tree callers ==="
sed -n '5280,5320p' "$log"
sed -n '1675,1710p' "$log"
echo "=== New tests and all changed implementation identifiers ==="
rg -n 'requeue_failed_where|requeue_failed|requeue_transient_failed|active|dedup|duplicate|cancel|job_key|payload' "$log" | head -n 300Repository: tinyhumansai/openhuman
Length of output: 18448
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
submodule="vendor/tinycortex"
old="e0a8738980965411f514f4a62c09f941efdea90c"
new="5fabcf18d9e3907d6b26b59528ad49cebfc1c271"
url="$(git config -f .gitmodules --get "submodule.${submodule}.url")"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
git init -q "$tmp/repo"
git -C "$tmp/repo" remote add origin "$url"
git -C "$tmp/repo" fetch --quiet --no-tags origin "$old" "$new"
for revision in "$old" "$new"; do
echo "=== $revision: store_settle.rs relevant range ==="
git -C "$tmp/repo" show "$revision:src/memory/queue/store_settle.rs" |
nl -ba | sed -n '200,390p'
done
echo "=== Raw diff, implementation only ==="
git -C "$tmp/repo" diff --unified=12 "$old" "$new" -- src/memory/queue/store_settle.rs |
sed -n '1,260p'
echo "=== Queue schema and key definitions at new revision ==="
for path in \
src/memory/queue/store.rs \
src/memory/queue/types.rs \
src/memory/queue/schema.rs \
src/memory/queue/mod.rs
do
if git -C "$tmp/repo" cat-file -e "$new:$path" 2>/dev/null; then
echo "--- $path ---"
git -C "$tmp/repo" show "$new:$path" |
rg -n -C 8 'CREATE TABLE|CREATE UNIQUE|job_key|dedup|payload|status|failure_class'
fi
doneRepository: tinyhumansai/openhuman
Length of output: 282
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
submodule="vendor/tinycortex"
old="e0a8738980965411f514f4a62c09f941efdea90c"
new="5fabcf18d9e3907d6b26b59528ad49cebfc1c271"
url="$(git config -f .gitmodules --get "submodule.${submodule}.url")"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
git init -q "$tmp/repo"
git -C "$tmp/repo" remote add origin "$url"
git -C "$tmp/repo" fetch --quiet --no-tags origin "$old" "$new"
for revision in "$old" "$new"; do
echo "=== $revision: store_settle.rs relevant range ==="
git -C "$tmp/repo" show "$revision:src/memory/queue/store_settle.rs" |
sed -n '200,390p'
done
echo "=== Raw diff, implementation only ==="
git -C "$tmp/repo" diff --unified=12 "$old" "$new" -- src/memory/queue/store_settle.rs |
sed -n '1,260p'
echo "=== Queue schema and key definitions at new revision ==="
for path in \
src/memory/queue/store.rs \
src/memory/queue/types.rs \
src/memory/queue/schema.rs \
src/memory/queue/mod.rs
do
if git -C "$tmp/repo" cat-file -e "$new:$path" 2>/dev/null; then
echo "--- $path ---"
git -C "$tmp/repo" show "$new:$path" |
rg -n -C 8 'CREATE TABLE|CREATE UNIQUE|job_key|dedup|payload|status|failure_class'
fi
doneRepository: tinyhumansai/openhuman
Length of output: 39923
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
submodule="vendor/tinycortex"
revision="5fabcf18d9e3907d6b26b59528ad49cebfc1c271"
url="$(git config -f .gitmodules --get "submodule.${submodule}.url")"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
git init -q "$tmp/repo"
git -C "$tmp/repo" remote add origin "$url"
git -C "$tmp/repo" fetch --quiet --no-tags origin "$revision"
echo "=== Dedupe-key implementations ==="
git -C "$tmp/repo" grep -n -E -C 8 'fn dedupe_key|dedupe_key\(' "$revision" -- \
src/memory/queue/payloads.rs src/memory/queue
echo "=== New settlement tests ==="
git -C "$tmp/repo" show "$revision:src/memory/queue/store_settle_tests.rs" |
sed -n '150,430p'
echo "=== All uses of cancelled status ==="
git -C "$tmp/repo" grep -n -E -C 5 \"cancelled|JobStatus::Cancelled\" "$revision" -- src
echo "=== Commit identity and changed paths ==="
git -C "$tmp/repo" cat-file -e "${revision}^{commit}"
git -C "$tmp/repo" show --format='%H%n%P%n%s' --no-patch "$revision"
git -C "$tmp/repo" diff-tree --no-commit-id --name-status -r "$revision"Repository: tinyhumansai/openhuman
Length of output: 47559
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
submodule="vendor/tinycortex"
revision="5fabcf18d9e3907d6b26b59528ad49cebfc1c271"
url="$(git config -f .gitmodules --get "submodule.${submodule}.url")"
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
git init -q "$tmp/repo"
git -C "$tmp/repo" remote add origin "$url"
git -C "$tmp/repo" fetch --quiet --no-tags origin "$revision"
echo "=== Failed-job status consumers ==="
git -C "$tmp/repo" grep -n -E -C 6 \
"count_by_status|JobStatus::Failed|status = 'failed'|retry_all_failed|requeue_failed" \
"$revision" -- src
echo "=== Queue status schema and retired-job handling ==="
git -C "$tmp/repo" grep -n -E -C 10 \
"idx_mem_tree_jobs_dedupe_active|CREATE TABLE mem_tree_jobs|topic_route|digest_daily|purge_retired_jobs" \
"$revision" -- src
echo "=== Settlement API documentation ==="
git -C "$tmp/repo" show "$revision:src/memory/queue/store_settle.rs" |
sed -n '225,370p'Repository: tinyhumansai/openhuman
Length of output: 50379
Clear failed duplicates when an active row owns the dedupe key.
requeue_failed_where skips the failed row but leaves it in failed when active_keys contains the same key. This allows retry_all_failed to return while stale failures remain counted. Mark the skipped row cancelled and clear its failure fields.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@vendor/tinycortex` at line 1, Update requeue_failed_where so failed rows
whose dedupe key exists in active_keys are marked cancelled and have their
failure fields cleared before being skipped. Ensure retry_all_failed no longer
leaves these stale failures counted, while preserving existing requeue behavior
for other failed rows.
What this does
Brings
releasetomain's tree at8deb5f276.Only the six version-bearing files differ from main, and they are held at release's higher v0.63.10 rather than main's v0.63.6 — a release must never go backwards.
Every hunk in those six is the same substitution,
0.63.6→0.63.10. Nothing else in the tree differs from main in either direction.It is a real two-parent merge, which is the point of doing it this way:
Release carried no unique code
Two independent checks, because the promote commits in release's history were hand-resolved and a wrong resolution is exactly the thing that would hide release-only content.
By commit. Release's nine unique commits are five version bumps (
v0.63.6…v0.63.10), three squashed promotes of main's own content (#5242, #5256, #5414), and one real change —42cdf77e7, the appimage userns fix (#5251). That fix's two files,scripts/release/test-strip-appimage-rpaths.shandscripts/release/validate-appimage-runtime.sh, are byte-identical between main and release: it reached main separately as #5252 (9750b8077).By tree, which is the stronger check.
mainandreleasediffer in 37 paths, every one a modification — nothing added and nothing deleted in either direction:For each of the 31 non-version paths, release's blob is reachable in main's history, appearing as the pre-image of a later main commit — i.e. release holds an older state of a file main has since moved past. There is no path where release's content is novel.
So taking main's tree wholesale discards nothing.
The 14 conflicts are squash-trap artifacts
13 unmerged entries (the 14th line in the conflict output is the rename/delete half of a pair whose unmerged entry sits on the new path):
None of them is divergence. The promotes were squash-merged, so no merge commit recorded main as an ancestor and the merge-base is frozen at
2219d4207. Git therefore cannot see that release already holds main's tree, and re-derives moves main made itself during the kernelization as add/add and rename/delete pairs —embeddings/cloud_adapter.rs→inference/embeddings/cloud_adapter.rsis precisely that.Resolution:
git read-tree -u --reset upstream/mainto set index and worktree to main's tree exactly — which is also what clears the rename/delete leftover a per-file checkout would have stranded — then the six version files restored fromupstream/release.MERGE_HEADsurvives that, so the result is a genuine merge commit rather than a squashed snapshot.Maintainer note — please read before merging
Squashing this PR will recreate the problem it is fixing.
The repository allows squash merges only (
allow_merge_commit: false). Squashed, this lands as a single commit with one parent, main is again not recorded as an ancestor, the merge-base stays at2219d4207, and the next promote and the next back-merge re-fight this same conflict set — with everything merged in between added to it.That has now cost three hand-resolutions in one day (#5414, this, and the mirror back-merge). It is not a git accident; it is a settings consequence, and it compounds.
Two durable fixes, either of which ends it:
Promote main to releaseworkflow so the sanctioned path works. It is currently unusable for two separate reasons: a dispatch from 17:40 is stuckwaitingon theRelease-PR-Automationenvironment approval, whichM3gA-Mindcannot grant; and even once it runs it cannot resolve conflicts by hand, so it would fail on these 13 regardless.Until one of those happens, every promote needs a human to re-derive this resolution from scratch, and the conflict set only grows.
Verification
git diff --stat upstream/main→ the six version files, nothing else (pasted above)git log -1 --pretty=%P→ two parents, release then main (pasted above)git merge-base --is-ancestor upstream/main HEAD→ yes; same forupstream/releasegit status --porcelain→ clean; no path present here and absent on mainSummary by CodeRabbit
New Features
Bug Fixes
Localization