Skip to content

fix(mobile): show bound errors in profile name and description forms - #6756

Merged
iscekic merged 3 commits into
mainfrom
kwf/janitor-mobile-profiles-c096c4bcf7
Sep 28, 2026
Merged

iscekic merged 3 commits into
mainfrom
kwf/janitor-mobile-profiles-c096c4bcf7

Conversation

@iscekic

@iscekic iscekic commented Sep 26, 2026 •

Copy link
Copy Markdown
Collaborator

Fix proof

A profile name longer than the server's 100-character bound is refused by the Overview metadata form with the empty-field message "Enter a profile name" (and the save is blocked), because the screen i

Asserted value: apps/mobile/src/components/profiles/profile-overview-screen.tsx. Sense check (model): The added nameIssue === 'empty' ? t('profiles.nameRequired') : t('agentChat.newSession.nameTooLong') line now shows nameTooLong for the too-long case, fixing the claim in the traced file.

The scripts were proven on an earlier base, so only the head ran.

Head 41b8f5d9ff8c

Head log: backend-assert e7b1a6d835e2 exited 0
$ git diff --unified=0 d72f1f366dabae2752f480d1c65dff586f12d90f 41b8f5d9ff8cdcf1b11d429765e6fed334c9aca9 -- apps/mobile/src/components/profiles/profile-overview-screen.tsx
diff --git a/apps/mobile/src/components/profiles/profile-overview-screen.tsx b/apps/mobile/src/components/profiles/profile-overview-screen.tsx
--- a/apps/mobile/src/components/profiles/profile-overview-screen.tsx
+++ b/apps/mobile/src/components/profiles/profile-overview-screen.tsx
+        error={descriptionError ?? undefined}
-        <Skeleton className="h-[54px] w-full rounded-lg" />
-        <Skeleton className="h-[54px] w-full rounded-lg" />
-      </View>
-      <Skeleton className="h-[44px] w-full rounded-md" />
-    </View>
-  );
-}
-

The Overview metadata form forwards the description with no 500-character cap (the field sets no maxLength and submit never checks the length), so a longer description is sent and the user gets a raw

Asserted value: apps/mobile/src/components/profiles/profile-overview-screen.tsx. Sense check (model): The diff adds validateProfileDescription(description) with setDescriptionError(t('agentChat.newSession.descriptionTooLong')) and passes error={descriptionError} to the field in profile-overview-screen.tsx, replacing the uncapped forward with an inline length check.

The scripts were proven on an earlier base, so only the head ran.

Head 41b8f5d9ff8c

Head log: backend-assert e7b1a6d835e2 exited 0
$ git diff --unified=0 d72f1f366dabae2752f480d1c65dff586f12d90f 41b8f5d9ff8cdcf1b11d429765e6fed334c9aca9 -- apps/mobile/src/components/profiles/profile-overview-screen.tsx
diff --git a/apps/mobile/src/components/profiles/profile-overview-screen.tsx b/apps/mobile/src/components/profiles/profile-overview-screen.tsx
--- a/apps/mobile/src/components/profiles/profile-overview-screen.tsx
+++ b/apps/mobile/src/components/profiles/profile-overview-screen.tsx
+        error={descriptionError ?? undefined}
-        <Skeleton className="h-[54px] w-full rounded-lg" />
-        <Skeleton className="h-[54px] w-full rounded-lg" />
-      </View>
-      <Skeleton className="h-[44px] w-full rounded-md" />
-    </View>
-  );
-}
-

The agent form labels the slug field 'Limace d'agent' (the animal) while the error copy beside it says 'slug', giving profiles.agents.slug a wrong meaning on the field the user fills in.

Asserted value: apps/mobile/src/i18n/locales/fr.json. Sense check (model): The diff changes the traced fr.json slug key from "Limace d'agent" to "Slug de l'agent", matching the error copy's non-animal meaning as the claim requires.

The scripts were proven on an earlier base, so only the head ran.

Head 41b8f5d9ff8c

Head log: backend-assert ed2f3381284e exited 0
$ git diff --unified=0 d72f1f366dabae2752f480d1c65dff586f12d90f 41b8f5d9ff8cdcf1b11d429765e6fed334c9aca9 -- apps/mobile/src/i18n/locales/fr.json
diff --git a/apps/mobile/src/i18n/locales/fr.json b/apps/mobile/src/i18n/locales/fr.json
--- a/apps/mobile/src/i18n/locales/fr.json
+++ b/apps/mobile/src/i18n/locales/fr.json
@@ -3380 +3380 @@
-      "remoteType": "Télécommande",
+      "remoteType": "Distant",
@@ -3408 +3408 @@
-      "slug": "Limace d'agent",
+      "slug": "Slug de l'agent",

The MCP server type 'remote' is labelled 'Télécommande' (a remote control) instead of 'Distant'/'À distance', so the local/remote choice in the MCP editor is mistranslated.

Asserted value: apps/mobile/src/i18n/locales/fr.json. Sense check (jev): probability 0.92

The scripts were proven on an earlier base, so only the head ran.

Head 41b8f5d9ff8c

Head log: backend-assert ed2f3381284e exited 0
$ git diff --unified=0 d72f1f366dabae2752f480d1c65dff586f12d90f 41b8f5d9ff8cdcf1b11d429765e6fed334c9aca9 -- apps/mobile/src/i18n/locales/fr.json
diff --git a/apps/mobile/src/i18n/locales/fr.json b/apps/mobile/src/i18n/locales/fr.json
--- a/apps/mobile/src/i18n/locales/fr.json
+++ b/apps/mobile/src/i18n/locales/fr.json
@@ -3380 +3380 @@
-      "remoteType": "Télécommande",
+      "remoteType": "Distant",
@@ -3408 +3408 @@
-      "slug": "Limace d'agent",
+      "slug": "Slug de l'agent",

The Environment variables screen header is 'Matsalolin muhalli' ('environmental problems') instead of the catalog's term 'masu canjin yanayi', so profiles.variablesTitle names the wrong thing.

Asserted value: apps/mobile/src/i18n/locales/ha.json. Sense check (jev): probability 0.91

The scripts were proven on an earlier base, so only the head ran.

Head 41b8f5d9ff8c

Head log: backend-assert 204c44f9d053 exited 0
$ git diff --unified=0 d72f1f366dabae2752f480d1c65dff586f12d90f 41b8f5d9ff8cdcf1b11d429765e6fed334c9aca9 -- apps/mobile/src/i18n/locales/ha.json
diff --git a/apps/mobile/src/i18n/locales/ha.json b/apps/mobile/src/i18n/locales/ha.json
--- a/apps/mobile/src/i18n/locales/ha.json
+++ b/apps/mobile/src/i18n/locales/ha.json
@@ -3295 +3295 @@
-    "variablesTitle": "Matsalolin muhalli",
+    "variablesTitle": "Masu canjin yanayi",
@@ -3378 +3378 @@
-      "promptPlaceholder": "ka a...",
+      "promptPlaceholder": "Kai mataimaki ne...",

The agent system-prompt placeholder is the truncated fragment 'ka a...' rather than a full example, so profiles.agents.promptPlaceholder shows meaningless input guidance in the form field.

Asserted value: apps/mobile/src/i18n/locales/ha.json. Sense check (model): The diff changes apps/mobile/src/i18n/locales/ha.json promptPlaceholder from the truncated "ka a..." to the full "Kai mataimaki ne...", addressing the traced defect.

The scripts were proven on an earlier base, so only the head ran.

Head 41b8f5d9ff8c

Head log: backend-assert 204c44f9d053 exited 0
$ git diff --unified=0 d72f1f366dabae2752f480d1c65dff586f12d90f 41b8f5d9ff8cdcf1b11d429765e6fed334c9aca9 -- apps/mobile/src/i18n/locales/ha.json
diff --git a/apps/mobile/src/i18n/locales/ha.json b/apps/mobile/src/i18n/locales/ha.json
--- a/apps/mobile/src/i18n/locales/ha.json
+++ b/apps/mobile/src/i18n/locales/ha.json
@@ -3295 +3295 @@
-    "variablesTitle": "Matsalolin muhalli",
+    "variablesTitle": "Masu canjin yanayi",
@@ -3378 +3378 @@
-      "promptPlaceholder": "ka a...",
+      "promptPlaceholder": "Kai mataimaki ne...",

Changelog for users

  • A profile name over 100 characters now shows the name-too-long message instead of telling the user to enter a name they already typed.
  • A profile description over 500 characters now shows an inline description-too-long error instead of a raw server validation toast.
  • The New profile screen now flags a too-long name or description before it submits.
  • The French MCP server type now reads "Distant" instead of the remote-control word.
  • The French agent slug field now reads "Slug de l'agent" instead of the animal word.
  • The Hausa environment variables header now reads "Masu canjin yanayi" instead of "environmental problems".
  • The Hausa agent prompt placeholder now shows a full example sentence instead of a truncated fragment.

Changelog for maintainers

  • The 500-character description bound now lives in the shared form validator and backs the overview, new-profile, and save-as-profile checks.
  • The name validator distinguishes empty from too-long; both screens map too-long to the new-session copy, so check that branch first.
  • The New profile screen gained its own description error state and passes it to the field; the overview form does the same.
  • The save-as-profile sheet now validates through the shared description helper instead of its local constant.
  • French and Hausa locale values changed for the MCP type, agent slug, environment variables header, and prompt placeholder.

E2E proof

A profile name longer than the server's 100-character bound is refused by the Overview metadata form with the empty-field message "Enter a profile name" (and the save is blocked), because the screen ignores validateProfileName's 'too-long' result and always shows profiles.nameRequired; the user is told to enter a name they already entered and cannot save, unlike Save-as-profile which shows agentChat.newSession.nameTooLong for the same validator.

Code trace: apps/mobile/src/components/profiles/profile-overview-screen.tsx:35 changed in e99c6734c05b63651cf55c75e0ae08b5d20ed6d0. Sense check (model): The new line nameIssue === 'empty' ? t('profiles.nameRequired') : t('agentChat.newSession.nameTooLong') in profile-overview-screen.tsx replaces the unconditional profiles.nameRequired, so a too-long name now shows the tooLong message and the save is blocked via the added return.

Changed lines
-import { validateProfileName } from '@/lib/agent-profile-forms';
+import { validateProfileDescription, validateProfileName } from '@/lib/agent-profile-forms';
+  const [descriptionError, setDescriptionError] = useState<string | null>(null);
-    if (validateProfileName(name) !== null) {
-      setNameError(t('profiles.nameRequired'));
+    const nameIssue = validateProfileName(name);
+    if (nameIssue !== null) {
+      setNameError(
+        nameIssue === 'empty' ? t('profiles.nameRequired') : t('agentChat.newSession.nameTooLong')
+      );
+      return;
+    }
+    const description = descriptionRef.current.trim();
+    if (validateProfileDescription(description) !== null) {
+      setDescriptionError(t('agentChat.newSession.descriptionTooLong'));
-    onSave({ name, description: descriptionRef.current.trim() });
+    setDescriptionError(null);
+    onSave({ name, description });
+        error={descriptionError ?? undefined}
+          if (descriptionError !== null && validateProfileDescription(value) === null) {
+            setDescriptionError(null);
+          }

The Overview metadata form forwards the description with no 500-character cap (the field sets no maxLength and submit never checks the length), so a longer description is sent and the user gets a raw server-validation toast instead of the "Description is too long" inline message the Save-as-profile sheet shows; the New profile screen has the same gap.

Code trace: apps/mobile/src/components/profiles/profile-overview-screen.tsx:35 changed in e99c6734c05b63651cf55c75e0ae08b5d20ed6d0. Sense check (model): profile-overview-screen.tsx now calls validateProfileDescription(description) and setDescriptionError(t('agentChat.newSession.descriptionTooLong')) on submit, giving the inline too-long message instead of the raw server toast

Changed lines
-import { validateProfileName } from '@/lib/agent-profile-forms';
+import { validateProfileDescription, validateProfileName } from '@/lib/agent-profile-forms';
+  const [descriptionError, setDescriptionError] = useState<string | null>(null);
-    if (validateProfileName(name) !== null) {
-      setNameError(t('profiles.nameRequired'));
+    const nameIssue = validateProfileName(name);
+    if (nameIssue !== null) {
+      setNameError(
+        nameIssue === 'empty' ? t('profiles.nameRequired') : t('agentChat.newSession.nameTooLong')
+      );
+      return;
+    }
+    const description = descriptionRef.current.trim();
+    if (validateProfileDescription(description) !== null) {
+      setDescriptionError(t('agentChat.newSession.descriptionTooLong'));
-    onSave({ name, description: descriptionRef.current.trim() });
+    setDescriptionError(null);
+    onSave({ name, description });
+        error={descriptionError ?? undefined}
+          if (descriptionError !== null && validateProfileDescription(value) === null) {
+            setDescriptionError(null);
+          }

The agent form labels the slug field 'Limace d'agent' (the animal) while the error copy beside it says 'slug', giving profiles.agents.slug a wrong meaning on the field the user fills in.

Code trace: apps/mobile/src/i18n/locales/fr.json:3380 changed in e99c6734c05b63651cf55c75e0ae08b5d20ed6d0. Sense check (model): The diff line + "slug": "Slug de l'agent" replaces the animal label "Limace d'agent" at fr.json:3380, matching the claim's named location and defect.

Changed lines
-      "remoteType": "Télécommande",
+      "remoteType": "Distant",
-      "slug": "Limace d'agent",
+      "slug": "Slug de l'agent",

The MCP server type 'remote' is labelled 'Télécommande' (a remote control) instead of 'Distant'/'À distance', so the local/remote choice in the MCP editor is mistranslated.

Code trace: apps/mobile/src/i18n/locales/fr.json:3380 changed in e99c6734c05b63651cf55c75e0ae08b5d20ed6d0. Sense check (jev): probability 0.92

Changed lines
-      "remoteType": "Télécommande",
+      "remoteType": "Distant",
-      "slug": "Limace d'agent",
+      "slug": "Slug de l'agent",

The Environment variables screen header is 'Matsalolin muhalli' ('environmental problems') instead of the catalog's term 'masu canjin yanayi', so profiles.variablesTitle names the wrong thing.

Code trace: apps/mobile/src/i18n/locales/ha.json:3295 changed in e99c6734c05b63651cf55c75e0ae08b5d20ed6d0. Sense check (jev): probability 0.91

Changed lines
-    "variablesTitle": "Matsalolin muhalli",
+    "variablesTitle": "Masu canjin yanayi",
-      "promptPlaceholder": "ka a...",
+      "promptPlaceholder": "Kai mataimaki ne...",

The agent system-prompt placeholder is the truncated fragment 'ka a...' rather than a full example, so profiles.agents.promptPlaceholder shows meaningless input guidance in the form field.

Code trace: apps/mobile/src/i18n/locales/ha.json:3295 changed in e99c6734c05b63651cf55c75e0ae08b5d20ed6d0. Sense check (model): apps/mobile/src/i18n/locales/ha.json:3295 now sets promptPlaceholder to "Kai mataimaki ne...", replacing the truncated 'ka a...' fragment the claim names

Changed lines
-    "variablesTitle": "Matsalolin muhalli",
+    "variablesTitle": "Masu canjin yanayi",
-      "promptPlaceholder": "ka a...",
+      "promptPlaceholder": "Kai mataimaki ne...",
Owner request

Fix 6 janitor findings in mobile/profiles. Fix every one; the proof covers each.

  1. A profile name longer than the server's 100-character bound is refused by the Overview metadata form with the empty-field message "Enter a profile name" (and the save is blocked), because the screen ignores validateProfileName's 'too-long' result and always shows profiles.nameRequired; the user is told to enter a name they already entered and cannot save, unlike Save-as-profile which shows agentChat.newSession.nameTooLong for the same validator.
    Trace: apps/mobile/src/components/profiles/profile-overview-screen.tsx:100: A profile name longer than the server's 100-character bound is refused by the Overview metadata form with the empty-field message "Enter a profile name" (and the save is blocked), because the screen ignores validateProfileName's 'too-long' result and always shows profiles.nameRequired; the user is told to enter a name they already entered and cannot save, unlike Save-as-profile which shows agentChat.newSession.nameTooLong for the same validator. (janitor area features-workflows).
    Files: apps/mobile/src/components/profiles/profile-overview-screen.tsx, apps/mobile/src/components/profiles/new-profile-screen.tsx.
  2. The Overview metadata form forwards the description with no 500-character cap (the field sets no maxLength and submit never checks the length), so a longer description is sent and the user gets a raw server-validation toast instead of the "Description is too long" inline message the Save-as-profile sheet shows; the New profile screen has the same gap.
    Trace: apps/mobile/src/components/profiles/profile-overview-screen.tsx:104: The Overview metadata form forwards the description with no 500-character cap (the field sets no maxLength and submit never checks the length), so a longer description is sent and the user gets a raw server-validation toast instead of the "Description is too long" inline message the Save-as-profile sheet shows; the New profile screen has the same gap. (janitor area features-workflows).
    Files: apps/mobile/src/components/profiles/profile-overview-screen.tsx, apps/mobile/src/components/profiles/new-profile-screen.tsx.
  3. The agent form labels the slug field 'Limace d'agent' (the animal) while the error copy beside it says 'slug', giving profiles.agents.slug a wrong meaning on the field the user fills in.
    Trace: apps/mobile/src/i18n/locales/fr.json:3408: The agent form labels the slug field 'Limace d'agent' (the animal) while the error copy beside it says 'slug', giving profiles.agents.slug a wrong meaning on the field the user fills in. (janitor area i18n, locale fr).
    Files: apps/mobile/src/i18n/locales/fr.json.
  4. The MCP server type 'remote' is labelled 'Télécommande' (a remote control) instead of 'Distant'/'À distance', so the local/remote choice in the MCP editor is mistranslated.
    Trace: apps/mobile/src/i18n/locales/fr.json:3380: The MCP server type 'remote' is labelled 'Télécommande' (a remote control) instead of 'Distant'/'À distance', so the local/remote choice in the MCP editor is mistranslated. (janitor area i18n, locale fr).
    Files: apps/mobile/src/i18n/locales/fr.json.
  5. The Environment variables screen header is 'Matsalolin muhalli' ('environmental problems') instead of the catalog's term 'masu canjin yanayi', so profiles.variablesTitle names the wrong thing.
    Trace: apps/mobile/src/i18n/locales/ha.json:3295: The Environment variables screen header is 'Matsalolin muhalli' ('environmental problems') instead of the catalog's term 'masu canjin yanayi', so profiles.variablesTitle names the wrong thing. (janitor area i18n, locale ha).
    Files: apps/mobile/src/i18n/locales/ha.json.
  6. The agent system-prompt placeholder is the truncated fragment 'ka a...' rather than a full example, so profiles.agents.promptPlaceholder shows meaningless input guidance in the form field.
    Trace: apps/mobile/src/i18n/locales/ha.json:3378: The agent system-prompt placeholder is the truncated fragment 'ka a...' rather than a full example, so profiles.agents.promptPlaceholder shows meaningless input guidance in the form field. (janitor area i18n, locale ha).
    Files: apps/mobile/src/i18n/locales/ha.json.

@iscekic iscekic added the kwf-janitor Admitted to the workflow from a janitor finding label Sep 26, 2026
Comment thread apps/mobile/src/lib/agent-profile-forms.ts
@kilo-code-bot

kilo-code-bot Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental changes extract the profile overview skeleton into its own module and add unit tests covering the description validator's 500/501 and trim-before-length boundaries; the previously reported untested-validator suggestion is resolved and no new issues were found.

Files Reviewed (3 files)
  • apps/mobile/src/components/profiles/profile-overview-screen.tsx
  • apps/mobile/src/components/profiles/profile-overview-skeleton.tsx
  • apps/mobile/src/lib/agent-profile-forms.test.ts
Previous Review Summary (commit 11d827c)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 11d827c)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
apps/mobile/src/lib/agent-profile-forms.ts 55 New validateProfileDescription is untested despite the module's stated invariant that every function has direct unit tests; no 500/501 boundary coverage.
Files Reviewed (6 files)
  • apps/mobile/src/components/agents/save-profile-sheet.tsx - 0 issues
  • apps/mobile/src/components/profiles/new-profile-screen.tsx - 0 issues
  • apps/mobile/src/components/profiles/profile-overview-screen.tsx - 0 issues
  • apps/mobile/src/i18n/locales/fr.json - 0 issues
  • apps/mobile/src/i18n/locales/ha.json - 0 issues
  • apps/mobile/src/lib/agent-profile-forms.ts - 1 issue

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

@iscekic iscekic self-assigned this Sep 26, 2026
@iscekic iscekic added the human-ready The PR is ready for human review. label Sep 26, 2026
@iscekic iscekic added merge-by-human the merge bot routed this PR to a human merge-by-bot and removed human-ready The PR is ready for human review. merge-by-human the merge bot routed this PR to a human labels Sep 26, 2026
@iscekic
iscekic marked this pull request as draft September 28, 2026 08:40
@iscekic
iscekic marked this pull request as ready for review September 28, 2026 08:44
@iscekic
iscekic marked this pull request as draft September 28, 2026 08:52
@iscekic
iscekic marked this pull request as ready for review September 28, 2026 09:01
@iscekic
iscekic marked this pull request as draft September 28, 2026 09:05
@iscekic
iscekic marked this pull request as ready for review September 28, 2026 09:10
@iscekic
iscekic marked this pull request as draft September 28, 2026 09:21
@iscekic
iscekic marked this pull request as ready for review September 28, 2026 09:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kwf-janitor Admitted to the workflow from a janitor finding merge-by-bot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants