Skip to content

feat(batch): functional & explanatory redesign for /batch + /batch/files - #2849

Merged
diegosouzapw merged 26 commits into
release/v3.8.8from
refactor/pages-v3-20-batch-files-functional-redesign
May 30, 2026
Merged

diegosouzapw merged 26 commits into
release/v3.8.8from
refactor/pages-v3-20-batch-files-functional-redesign

Conversation

@diegosouzapw

Copy link
Copy Markdown
Owner

Summary

  • NewBatchWizard (4-step modal: destination → input → validate → cost) on /dashboard/batch — supports JSONL upload and CSV with column mapping
  • UploadFileModal + "Used by" column + expiration urgency on /dashboard/batch/files
  • Cancel / download output / download errors / retry actions per row + 30s polling with visibility-pause + concept cards on both pages
  • 6 new pure helpers in src/lib/batches/{types,schemas,csvToJsonl,validateJsonl,costEstimator,retryFailed}.ts — no new endpoints, no migrations

Implements the full critério de aceitação §9 from _tasks/features-v3.8.6/refactorpages/20-batch-files-functional-redesign.plan.md. Orchestrated via 10 parallel Sonnet frentes (F1–F10) + 1 gap-fix frente (FIX-1). Master plan saved at _tasks/features-v3.8.6/refactorpages/_orchestration/master-plan-20.md.

Test plan

  • Wizard JSONL: pick provider → upload .jsonl → validate → cost → create → batch appears in list
  • Wizard CSV: paste CSV → map columns (custom_id, content, max_tokens) → validate → cost → create
  • Files: drag/drop .jsonl → uploads with purpose=batch → appears in list with "Used by: none"
  • Cancel: batch in_progress → click ✕ → confirm dialog → status becomes cancelling
  • Retry: completed_with_failures + errorFileId → click ↻ → confirm → new batch with N failed requests reprocessed
  • Polling: open /batch, wait 30s → list refreshes (visible spinner) ; switch tab → polling pauses ; return → resumes
  • Files: file in use by active batch → delete button disabled with tooltip
  • ExpirationBadge: < 1h → red ; < 6h → yellow ; < 24h → emerald ; expired → gray
  • BatchConceptCard + FilesConceptCard: collapsible with localStorage persistence
  • i18n: EN + pt-BR have all new keys; other 40 locales fall back to EN automatically
  • Sanitization: simulate 500 from POST /v1/files → banner shows t("uploadModalError"), no at /home/, no stack trace
  • Coverage gate (40/40/40/40 — lowered per user request): npm run test:coverage passes

Hard Rules compliance

Frentes paralelas

Frente Escopo Commits
F1 types + Zod schemas 1
F2 4 pure helpers (csv→jsonl, validate, cost, retry) — 61 tests, 100% local cov 1
F3 4 UI atoms (ConceptCards, ExpirationBadge, ProgressBarBicolor) 1
F4 NewBatchWizard 4-step modal + 12 tests 1
F5 UploadFileModal + Used-by column + 9 tests 1
F6 Batch tab refinements + useBatchActions hook + 15 tests 1
F7 BatchDetailModal action footer + 11 tests 1
F8 i18n EN+pt-BR + fallback EN for 40 other locales + sync script 1
F9 integration tests + sanitization asserts + coverage gap fillers (58 tests) 1
F10 audit final (lint/types/cycles/build/coverage validated) 1 (perf fix)
FIX-1 gap analysis fixes G2–G7 1

Stats: 134 files changed, 11619 insertions, 1480 deletions across 20 commits.

…0 other locales (F8)

Adds 70 new keys to the common namespace for the batch/files functional
redesign (wizard, upload modal, concept cards, list actions, expiration
badges, detail modal). EN and pt-BR translated manually; all other
41 locales filled with EN fallback via fill-missing-from-en.mjs.
… ProgressBarBicolor (F3)

Shared UI atoms for /dashboard/batch redesign (master-plan-20 §5.F3):
- BatchConceptCard: collapsible with localStorage persistence (key omniroute:concept-batch-collapsed)
- FilesConceptCard: collapsible with 3 type pills (input/output/error) and localStorage persistence
- ExpirationBadge: dynamic tier badge (critical/warning/normal/expired) with 60s setInterval auto-update
- ProgressBarBicolor: green+red dual-segment bar, handles total=0 without NaN
- 14 smoke tests covering all 4 tiers, null expiresAt, compact variant, total=0, labels toggle
…batch/files (F5)

- Create UploadFileModal: drag/drop + click-to-pick, .jsonl + 512MB validation, purpose=batch upload, D14 error sanitization, Escape key handler
- Modify files/page.tsx: integrate FilesConceptCard (F3) + Upload toolbar button + UploadFileModal wired to fetchAll refresh
- Modify FilesListTab.tsx: add "Used by" column (D12 — derives related batches client-side), download button per row, delete button with canDelete guard (terminal-only or no related batches), colspan updated 6→8
- Create UploadFileModal.test.tsx (9 tests, all passing): render, invalid ext, valid .jsonl, >512MB (size property mock), upload 200 → onUploaded, upload 500 → sanitized error, Escape→onClose, drag-drop, sanitization assert (no /home/ in alert text)
…mns, row actions, 30s polling on /batch (F6)
# Conflicts:
#	src/app/(dashboard)/dashboard/batch/components/NewBatchWizard.tsx
…gap fillers (F9)

- Add tests/unit/batches-f9-helpers.test.ts (19 tests, top-level for c8 coverage gate)
  covering uncovered branches: alias-match pricing, blank CSV rows, body.input/prompt paths,
  non-object JSON lines, invalid Anthropic params, body-is-array validation
- Add tests/unit/dashboard/batch/concept-cards.test.tsx (16 tests)
  covering BatchConceptCard + FilesConceptCard: render, toggle, localStorage hydration, sanitization
- Add tests/unit/dashboard/batch/list-regression.test.tsx (15 tests)
  covering BatchListTab + FilesListTab: render N items, Remove-completed flow,
  status/purpose filter, loading/empty states, sanitization
- Add tests/unit/dashboard/batch/sanitization.test.tsx (8 tests)
  covering NewBatchWizard + UploadFileModal + useBatchActions: each error path
  asserts zero stack-trace/path leakage into the UI (D14 / Hard Rule #12)
- Fix bug in validateJsonl.ts: body=array was not caught as invalid
  (typeof array === "object" is true — add Array.isArray guard, 1-line fix)

Local src/lib/batches/ coverage: 100% stmts / 93.7% branches / 100% funcs / 100% lines.
Global coverage gate: 75.96% stmts / 71.97% branches / 75.52% funcs (all above 75/75/75/70).
…files, polling spinner, i18n confirm, error keys, retention bullet
…files, polling spinner, i18n confirm, error keys, retention bullet)
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@kilo-code-bot

kilo-code-bot Bot commented May 28, 2026

Copy link
Copy Markdown

Kilo Code Review could not run — your account is out of credits.

Add credits or switch to a free model to enable reviews on this change.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a comprehensive batch processing and batch file management feature, including a new batch wizard, file upload modal, concept cards, progress indicators, and localized strings across multiple languages. It also adds utility libraries for CSV-to-JSONL conversion, cost estimation, validation, and retrying failed requests, along with corresponding unit tests. Feedback on these changes highlights several critical improvements: resolving a potential byte overlap bug in file sampling, fixing TypeScript and runtime type safety issues in the CSV parser and provider loading flows, defensively validating file upload responses, and restoring the test coverage gate to 75% to comply with repository style guidelines.

Comment on lines +18 to +26
async function readFileContent(file: File): Promise<string> {
if (file.size <= MAX_FULL_BYTES) {
return await file.text();
}
// Sampling for large files (D7)
const headText = await file.slice(0, SAMPLE_HEAD_BYTES).text();
const tailText = await file.slice(file.size - SAMPLE_TAIL_BYTES).text();
return headText + "\n[...sample only...]\n" + tailText;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In readFileContent, when the file size is slightly larger than MAX_FULL_BYTES (5 MB), the start of the tail slice (file.size - SAMPLE_TAIL_BYTES) can overlap with the head slice (SAMPLE_HEAD_BYTES). This causes overlapping bytes to be duplicated in the concatenated string, which leads to false duplicate custom_id validation errors during the validation step.

To prevent this, ensure the tail slice starts at least at SAMPLE_HEAD_BYTES.

Suggested change
async function readFileContent(file: File): Promise<string> {
if (file.size <= MAX_FULL_BYTES) {
return await file.text();
}
// Sampling for large files (D7)
const headText = await file.slice(0, SAMPLE_HEAD_BYTES).text();
const tailText = await file.slice(file.size - SAMPLE_TAIL_BYTES).text();
return headText + "\n[...sample only...]\n" + tailText;
}
async function readFileContent(file: File): Promise<string> {
if (file.size <= MAX_FULL_BYTES) {
return await file.text();
}
// Sampling for large files (D7)
const headText = await file.slice(0, SAMPLE_HEAD_BYTES).text();
const tailStart = Math.max(SAMPLE_HEAD_BYTES, file.size - SAMPLE_TAIL_BYTES);
const tailText = await file.slice(tailStart).text();
return headText + "\n[...sample only...]\n" + tailText;
}

Comment on lines +127 to +141
let cur: Record<string, unknown> = target;
for (let i = 0; i < tokens.length - 1; i++) {
const k = tokens[i];
const next = tokens[i + 1];
if (!Object.prototype.hasOwnProperty.call(cur, k) || cur[k] == null) {
const child: unknown = typeof next === "number" ? [] : Object.create(null);
safePropSet(cur, k, child);
}
cur = Object.prototype.hasOwnProperty.call(cur, k) ? cur[k] : undefined;
if (cur == null) return; // bail if tree navigation failed
}

const lastKey = tokens.at(-1)!;
if (typeof lastKey === "string" && FORBIDDEN_KEYS.has(lastKey)) return;
safePropSet(cur, lastKey, value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In setByPath, cur is typed as Record<string, unknown>, but cur[k] is typed as unknown. Assigning cur[k] directly to cur without a type assertion can cause a TypeScript compilation error under strict mode. Additionally, if cur is a primitive (e.g., due to conflicting mappings), calling safePropSet on it will throw a runtime TypeError.

Adding defensive checks to ensure cur is an object before property access and safePropSet prevents these issues.

  let cur: Record<string, unknown> = target;
  for (let i = 0; i < tokens.length - 1; i++) {
    const k = tokens[i];
    const next = tokens[i + 1];
    if (typeof cur !== "object" || cur === null) return;
    if (!Object.prototype.hasOwnProperty.call(cur, k) || cur[k] == null) {
      const child: unknown = typeof next === "number" ? [] : Object.create(null);
      safePropSet(cur, k, child);
    }
    cur = Object.prototype.hasOwnProperty.call(cur, k) ? (cur[k] as Record<string, unknown>) : undefined;
    if (cur == null) return; // bail if tree navigation failed
  }

  const lastKey = tokens.at(-1)!;
  if (typeof lastKey === "string" && FORBIDDEN_KEYS.has(lastKey)) return;
  if (typeof cur !== "object" || cur === null) return;
  safePropSet(cur, lastKey, value);

Comment on lines +136 to +143
const data = (await res.json()) as {
connections: Array<{ provider: string; is_active?: boolean }>;
};
const connected = new Set(
(data.connections ?? [])
.filter((c) => BATCH_SUPPORTED.includes(c.provider))
.map((c) => c.provider),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When parsing the response from /api/providers, there is no check to ensure data is a non-null object and data.connections is an array. If the API returns null or an unexpected response, this will throw a runtime TypeError. Adding a defensive check makes the provider loading flow much more robust.

          const data = (await res.json()) as {
            connections: Array<{ provider: string; is_active?: boolean }>;
          } | null;
          const connections = data && typeof data === "object" && Array.isArray(data.connections)
            ? data.connections
            : [];
          const connected = new Set(
            connections
              .filter((c) => c && BATCH_SUPPORTED.includes(c.provider))
              .map((c) => c.provider),
          );

Comment on lines +206 to +217
const file = (await fileRes.json()) as { id: string };

// Step 2: create batch
const batchRes = await fetch("/api/v1/batches", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
input_file_id: file.id,
endpoint: state.destination.endpoint,
completion_window: "24h",
}),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Defensively validate that the parsed file upload response is a non-null object and contains a valid id string before using it to create the batch. This prevents runtime errors or bad requests if the file upload API returns an unexpected response.

      const file = (await fileRes.json()) as { id?: string } | null;
      if (!file || typeof file.id !== "string") {
        console.error("[NewBatchWizard] file upload response missing id:", file);
        dispatch({ type: "SET_ERROR", error: t("wizardErrorUpload") });
        return;
      }

      // Step 2: create batch
      const batchRes = await fetch("/api/v1/batches", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          input_file_id: file.id,
          endpoint: state.destination.endpoint,
          completion_window: "24h",
        }),
      });

Comment on lines +137 to +148
const file = (await fileRes.json()) as { id: string };

// 4. Create new batch with same endpoint + 24h window (D9)
const batchRes = await fetch("/api/v1/batches", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
input_file_id: file.id,
endpoint: batch.endpoint,
completion_window: "24h",
}),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Defensively validate that the parsed file upload response is a non-null object and contains a valid id string before using it to create the retry batch. This prevents runtime errors or bad requests if the file upload API returns an unexpected response.

        const file = (await fileRes.json()) as { id?: string } | null;
        if (!file || typeof file.id !== "string") {
          console.error("[useBatchActions] retry file upload response missing id:", file);
          setError(opts.t("batchActionRetryError"));
          return null;
        }

        // 4. Create new batch with same endpoint + 24h window (D9)
        const batchRes = await fetch("/api/v1/batches", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            input_file_id: file.id,
            endpoint: batch.endpoint,
            completion_window: "24h",
          }),
        });

Comment thread package.json
"test:ecosystem": "node scripts/dev/run-ecosystem-tests.mjs",
"test:system": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx --import ./open-sse/utils/setupPolyfill.ts --test --test-force-exit --test-concurrency=1 tests/e2e/system-failover.test.ts",
"test:coverage": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true c8 --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov --check-coverage --statements 75 --lines 75 --functions 75 --branches 70 node --max-old-space-size=8192 --import tsx --import ./open-sse/utils/setupPolyfill.ts --test --test-force-exit --test-concurrency=8 tests/unit/*.test.ts",
"test:coverage": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true c8 --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov --check-coverage --statements 40 --lines 40 --functions 40 --branches 40 node --max-old-space-size=8192 --import tsx --import ./open-sse/utils/setupPolyfill.ts --test --test-force-exit --test-concurrency=8 tests/unit/*.test.ts",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Lowering the test coverage gate to 40% violates the repository style guide (Section 2, Rule 10), which states that coverage must stay ≥ 75% statements / 75% lines / 75% functions / 70% branches. Please restore the coverage gate thresholds to comply with the repository standards.

Suggested change
"test:coverage": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true c8 --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov --check-coverage --statements 40 --lines 40 --functions 40 --branches 40 node --max-old-space-size=8192 --import tsx --import ./open-sse/utils/setupPolyfill.ts --test --test-force-exit --test-concurrency=8 tests/unit/*.test.ts",
"test:coverage": "cross-env DISABLE_SQLITE_AUTO_BACKUP=true c8 --output-dir coverage --exclude=tests/** --exclude=**/*.test.* --reporter=text-summary --reporter=html --reporter=json-summary --reporter=lcov --check-coverage --statements 75 --lines 75 --functions 75 --branches 70 node --max-old-space-size=8192 --import tsx --import ./open-sse/utils/setupPolyfill.ts --test --test-force-exit --test-concurrency=8 tests/unit/*.test.ts",
References
  1. Coverage must stay ≥ 75 % statements / 75 % lines / 75 % functions / 70 % branches (real measured: ~82 %). (link)

…l) suffix

- FilesListTab: add (input)/(output)/(error) role label next to batch id in Used by column + tooltip (G-AUD1, plan §4 wireframe `b1 (input)`)
- BatchListTab: add -50% inline badge on Cost column per wireframe §3 `$6.20 (-50%)` (G-AUD2) + (partial) suffix on progress when expired_with_failures (G-AUD3)
- ExpirationBadge: document <1h/<6h/<24h tier semantics + >24h graceful fallback (G-AUD4)
- 4 new i18n keys in en + pt-BR (filesListUsedByRoleInput/Output/Error, batchListProgressPartial); 40 locales auto-filled via fill-missing-from-en.mjs
- Update list-regression test #13 to assert new used-by format (truncated id + role label + tooltip carries full id+role)
…g, 24h window, Provider column, race guard, banner toast, i18n cleanup

13 fixes from independent round-2 code review:

- B-1: Fix FileRecord wrong import in batch-utils.ts (TS2305 masked by limited typecheck-core scope); include batch-utils.ts + 5 lib/batches/* in tsconfig.typecheck-core.json so future regressions are caught
- A-2: role="dialog" + aria-modal + aria-labelledby on NewBatchWizard + BatchDetailModal panels (a11y consistency with UploadFileModal)
- A-3: "Janela de conclusão de 24h" line in CostEstimateStep (spec §5 explicit)
- A-7: "campos obrigatórios válidos" appended to JsonlValidationStep success summary (spec §5)
- A-9 + B-7: 18 hardcoded UI strings → i18n keys (Size, Refresh/Refreshing, Remove, Uploading, Reading file, Ready, Large file warning, JSONL generated, etc.)
- B-4: Strip UTF-8 BOM in validateJsonl + csvToJsonl (Windows-saved files no longer fail "invalid JSON" cryptically)
- B-5: Remove dead exports WizardStep + BatchProviderConfig from types.ts
- A-1: Add Provider column with derived heuristic (gpt-/o1-/o3-/text-embedding-/dall-e- → OpenAI; claude- → Anthropic; gemini → Gemini; else "—") in BatchListTab (BatchRecord has no provider field, so derivation is display-only)
- A-5: Enter key advances wizard step via data-wizard-next button trigger (skip when focus in INPUT/TEXTAREA/SELECT)
- A-6: Auto-dismiss "Batch {id} criado" banner on /batch page after wizard completes; consumes onCreated id (was discarded as _id)
- B-2: Race guard in InputStep.processFile (early-return if isReading) + drop zone pointer-events-none while reading
- C-tests: 6 new regression tests covering body=[] Array.isArray guard, BOM stripping, alias-match pricing path, (partial) suffix on expired_with_failures, -50% inline badge on Cost column, Provider column derivation per family

Side fix: narrow Record<string,unknown> child navigation in csvToJsonl.ts:135 to silence TS2322 once file is in typecheck scope.

22 new i18n keys (filesListSizeColumn, batchListProviderColumn/Unknown/BatchCreated/Dismiss/Refreshing/Refresh, uploadFileModalRemove/Uploading, wizardInputReading/Ready/LargeFileLabel/CsvJsonlReady/LargeFileWarning, wizardCostWindow24h, wizardValidationFieldsOk) added in en.json + pt-BR.json and propagated to 40 locales via fill-missing-from-en.mjs.
…vider chatgpt-/o-series + i18n, useRef race guard

3 fixes from independent round-3 code review:

- R1: Exclude BUTTON from the wizard global Enter handler. With Back/Cancel/Create focused, the browser already activates the focused button on Enter; a global Next dispatch on top would conflict (Back focused + Enter → both back and next dispatched in the same tick, last-write-wins is indeterminate). Now Enter only fires the Next dispatch when focus is on a non-interactive element (modal body). Verified the reducer SET_STEP uses an absolute step value so even if a double-dispatch were possible, it converges — but excluding BUTTON eliminates the redundant work and the focus-on-Back failure mode.

- R2: deriveProvider in BatchListTab refactored to return a discriminator ("OpenAI"/"Anthropic"/"Gemini"/"other"/"unknown") with vendor names left un-translated (proper nouns) and other/unknown routed through t("batchListProviderOther") / t("batchListProviderUnknown") at the call-site. Heuristic expanded: gpt-, chatgpt-, /^o[1-9](-|$)/ (catches o1-preview, o3-mini, o4-mini), text-embedding-, dall-e, whisper, tts- → OpenAI; claude- → Anthropic; gemini → Gemini. Kills the "chatgpt-4o-latest → Other" misclassification + the previously dead batchListProviderUnknown key + a hardcoded English "Other" leak.

- B-2b: InputStep race guard moved from useState to useRef (isReadingRef) so concurrent processFile calls in the same tick (drop + file-pick before the next React render) cannot both pass the early-return. State mirror kept for UI rendering.

Tests: 2 new cases in list-regression — test 19 covers chatgpt-4o-latest / o1-preview / o3-mini all rendering "OpenAI" 3×; test 20 asserts unknown + null model produce t("batchListProviderOther") / t("batchListProviderUnknown") (proves no hardcoded English leak). 1 new i18n key (batchListProviderOther) added in en + pt-BR and propagated to 40 locales via fill-missing-from-en.mjs.
…, wizard strings, sr-only urgency

3 polish items from R4 acceptance audit (operator-approved scope):

- P1: BatchListTab status filter dropdown now renders translated labels (t("batchStatusInProgress") etc.) instead of raw snake_case ("in_progress", "cancelling"). STATUS_LABELS refactored to STATUS_LABEL_KEYS — a single map from raw/composite status → i18n key — so StatusBadge and the dropdown share one source of truth. Falls back to snake→space transform for unknown statuses.

- P2: 18 hardcoded English strings replaced by t() calls.
  BatchListTab: title ("Batches"), count "{count} batches" (ICU placeholder), Removing…/Remove completed, 6 table headers (Status/ID/Endpoint/Model/Progress/Created/Expires), Loading…, No batches found, Validating… progress cell.
  CostEstimateStep: Estimating cost…, Requests, input tok, output tok, Window.
  DestinationStep: Select a provider…, Select a model…, Connect a provider.

- P3: ExpirationBadge — added <span class="sr-only">{label}:</span> in both compact and default variants so colorblind users and screen-readers get the urgency tier (Critical/Soon/Pending) instead of color-only signaling. The visual is unchanged (compact still shows just the time string).

Tests: list-regression #2 + #3 updated to look for the i18n key literal "batchListRemoveCompleted" (mock t() returns keys) instead of the now-translated "Remove completed" string. All 20 list-regression tests pass.

35 new i18n keys (14 status labels — 9 raw + 5 _with_failures composites — + 14 BatchListTab + 4 CostEstimateStep + 3 DestinationStep) added in en.json + pt-BR.json and propagated to 40 locales via fill-missing-from-en.mjs.

Note on R4 finding C1 (auditor claimed Hard Rule #9 violation from the 75→40 coverage gate drop): false positive. The audit compared CLAUDE.md in the worktree (branch refactor/pages-v3-20-... reflecting the new gate of 40, since operator explicitly requested it: "pode baixar os testes para 40/40/40") against CLAUDE.md in the repo root (branch release/v3.8.6, still at 75 because the PR has not landed yet). Same file, different branches — expected intermediate state for an active PR. Actual measured coverage remains ~77% (well above the 40 gate), so the gate change is a sanctioned threshold relaxation, not a masking workaround.
@diegosouzapw
diegosouzapw changed the base branch from release/v3.8.6 to release/v3.8.7 May 29, 2026 22:05
@diegosouzapw
diegosouzapw changed the base branch from release/v3.8.7 to release/v3.8.8 May 30, 2026 06:37
…l redesign)

Conflicts: CLAUDE.md base; i18n en/pt-BR deep-merge — 3 apiManager keys resolved to base pt-BR translations (HEAD had stale EN), costsSection=Custos; .source --theirs+regenerated. 40 other locales auto-merged. No migrations/open-sse. Batch redesign confirmed complete in prior code review.
@diegosouzapw
diegosouzapw merged commit 6253f31 into release/v3.8.8 May 30, 2026
2 checks passed
@diegosouzapw
diegosouzapw deleted the refactor/pages-v3-20-batch-files-functional-redesign branch May 30, 2026 13:01
diegosouzapw added a commit that referenced this pull request Jun 1, 2026
…env-doc fixes

- bump package.json / open-sse / electron / openapi / llm.txt to 3.8.8
- restructure CHANGELOG: Unreleased -> [3.8.8], dedup broken Notion/MCP block (was 12x)
- add every PR since v3.8.7 that was missing: Quota Share Engine (#2859/#3022/#3032),
  page redesigns (#2827/#2839/#2847/#2849/#2869/#2873), and fixes #2960/#2973/#2984/
  #3021/#3029/#3031/#3035/#3036/#3037/#3039/#3043/#3028; folded #2978/#2988/#3041
- insert [3.8.8] section into all 41 i18n CHANGELOGs + sync llm.txt mirrors
- document OMNIROUTE_PLUGINS_ALLOW_EXEC in .env.example + ENVIRONMENT.md (env-doc-sync gap)
@diegosouzapw diegosouzapw mentioned this pull request Jun 2, 2026
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…-v3-20-batch-files-functional-redesign

feat(batch): functional & explanatory redesign for /batch + /batch/files
HouMinXi pushed a commit to HouMinXi/OmniRoute that referenced this pull request Aug 2, 2026
…env-doc fixes

- bump package.json / open-sse / electron / openapi / llm.txt to 3.8.8
- restructure CHANGELOG: Unreleased -> [3.8.8], dedup broken Notion/MCP block (was 12x)
- add every PR since v3.8.7 that was missing: Quota Share Engine (diegosouzapw#2859/diegosouzapw#3022/diegosouzapw#3032),
  page redesigns (diegosouzapw#2827/diegosouzapw#2839/diegosouzapw#2847/diegosouzapw#2849/diegosouzapw#2869/diegosouzapw#2873), and fixes diegosouzapw#2960/diegosouzapw#2973/diegosouzapw#2984/
  diegosouzapw#3021/diegosouzapw#3029/diegosouzapw#3031/diegosouzapw#3035/diegosouzapw#3036/diegosouzapw#3037/diegosouzapw#3039/diegosouzapw#3043/diegosouzapw#3028; folded diegosouzapw#2978/diegosouzapw#2988/diegosouzapw#3041
- insert [3.8.8] section into all 41 i18n CHANGELOGs + sync llm.txt mirrors
- document OMNIROUTE_PLUGINS_ALLOW_EXEC in .env.example + ENVIRONMENT.md (env-doc-sync gap)
Poid-ZA pushed a commit to Poid-ZA/OmniRoute that referenced this pull request Aug 5, 2026
…-v3-20-batch-files-functional-redesign

feat(batch): functional & explanatory redesign for /batch + /batch/files
Poid-ZA pushed a commit to Poid-ZA/OmniRoute that referenced this pull request Aug 5, 2026
…env-doc fixes

- bump package.json / open-sse / electron / openapi / llm.txt to 3.8.8
- restructure CHANGELOG: Unreleased -> [3.8.8], dedup broken Notion/MCP block (was 12x)
- add every PR since v3.8.7 that was missing: Quota Share Engine (diegosouzapw#2859/diegosouzapw#3022/diegosouzapw#3032),
  page redesigns (diegosouzapw#2827/diegosouzapw#2839/diegosouzapw#2847/diegosouzapw#2849/diegosouzapw#2869/diegosouzapw#2873), and fixes diegosouzapw#2960/diegosouzapw#2973/diegosouzapw#2984/
  diegosouzapw#3021/diegosouzapw#3029/diegosouzapw#3031/diegosouzapw#3035/diegosouzapw#3036/diegosouzapw#3037/diegosouzapw#3039/diegosouzapw#3043/diegosouzapw#3028; folded diegosouzapw#2978/diegosouzapw#2988/diegosouzapw#3041
- insert [3.8.8] section into all 41 i18n CHANGELOGs + sync llm.txt mirrors
- document OMNIROUTE_PLUGINS_ALLOW_EXEC in .env.example + ENVIRONMENT.md (env-doc-sync gap)
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…-v3-20-batch-files-functional-redesign

feat(batch): functional & explanatory redesign for /batch + /batch/files
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…env-doc fixes

- bump package.json / open-sse / electron / openapi / llm.txt to 3.8.8
- restructure CHANGELOG: Unreleased -> [3.8.8], dedup broken Notion/MCP block (was 12x)
- add every PR since v3.8.7 that was missing: Quota Share Engine (diegosouzapw#2859/diegosouzapw#3022/diegosouzapw#3032),
  page redesigns (diegosouzapw#2827/diegosouzapw#2839/diegosouzapw#2847/diegosouzapw#2849/diegosouzapw#2869/diegosouzapw#2873), and fixes diegosouzapw#2960/diegosouzapw#2973/diegosouzapw#2984/
  diegosouzapw#3021/diegosouzapw#3029/diegosouzapw#3031/diegosouzapw#3035/diegosouzapw#3036/diegosouzapw#3037/diegosouzapw#3039/diegosouzapw#3043/diegosouzapw#3028; folded diegosouzapw#2978/diegosouzapw#2988/diegosouzapw#3041
- insert [3.8.8] section into all 41 i18n CHANGELOGs + sync llm.txt mirrors
- document OMNIROUTE_PLUGINS_ALLOW_EXEC in .env.example + ENVIRONMENT.md (env-doc-sync gap)
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