Skip to content

fix(engine): Tab preenche a indentação esperada do target na corrida (#41) - #42

Merged
caioross merged 1 commit into
mainfrom
auto/issue-41-tab-indent
Jul 19, 2026
Merged

fix(engine): Tab preenche a indentação esperada do target na corrida (#41)#42
caioross merged 1 commit into
mainfrom
auto/issue-41-tab-indent

Conversation

@caioross

Copy link
Copy Markdown
Owner

Contexto

O Tab-para-indentar já estava shipado (CodeEditor.tsx), mas não inseria nada para o Iniciante em Python/Fácil (fricção nº1, Discussion #27) — affordance quebrado, pior que ausente.

Raiz (confirmada pelo Parecer do Conselho)

  • (A) Índice cruzado value↔target: o handler lia o run de espaços a partir de target[caret], mas caret é offset em value/typed. Isso só alinha enquanto value for prefixo exato de target. Basta 1 erro anteriorhandleInput conta o erro mas não corrige o texto — para o índice desalinhar e o Tab ler o run errado (vazio). Em Python erra-se cedo e a indentação é a parede → "Tab não indenta".
  • (B) Fallback tóxico if (!ins) ins = " ": quando target[caret] não era espaço, injetava 2 espaços que handleInput contava como erro, derrubando a precisão silenciosamente.

O que mudou

  • Nova função pura src/lib/indent.tsindentEdit(value, target, selStart, selEnd?). A indentação esperada é derivada da linha lógica atual (nº de \n antes do caret → mesma linha em target), imune a divergências de comprimento upstream (mata A). Só insere quando o caret está na zona de indentação da linha e há espaços a preencher; caso contrário é no-op honesto (mata B — sem 2 espaços tóxicos, sem poluir a precisão).
  • CodeEditor.tsx onKeyDown passa a delegar a indentEdit; no-op não dispara onChange (sem re-render — área sagrada intacta). Shift+Tab, disabled e preventDefault (foco nunca sai) preservados.

Acceptance criteria

  • Caret no início de linha com N espaços em target → insere exatamente N, caret após eles.
  • Espaços inseridos batem targetnão geram erro (validado via correctChars).
  • Shift+Tab e disabled continuam sem inserir; Tab nunca move o foco.
  • Área sagrada intacta (O(indent), no-op não re-renderiza).
  • Teste automatizado da inserção — reusa o harness existente, não duplica.

Validação (gate real)

  • pnpm typecheck ✓ · pnpm build
  • node .claude/skills/cr-typing-engine/scripts/validate-metrics.mjs37/37 (10 novos casos de indentação: início de linha, erro upstream, linha rasa=no-op, completar parcial, meio do código=no-op, target curto, seleção)
  • node scripts/validate-persistence.mjs → 33/33 ✓
  • lint = N/A (repo sem config ESLint; CI não roda lint)

Nota de verificação

Cobertura via testes unitários da função pura (onde vive 100% da lógica) + typecheck/build. O e2e em sala real precisa de Supabase (.env.local) e o harness só-de-dev da #37 ainda não existe — quando existir, cobrir a fase racing Python/Fácil visualmente. Segui o plano do Conselho (extrair pura + cobrir no runner disponível, pois a #31/Vitest não mergeou).

Riscos

Baixo. Mudança localizada num handler de tecla; sem novas deps, sem tocar API/persistência/migração/CI/anti-cheat.

Closes #41

…41)

O handler de Tab lia `target[caret]` cru, que só alinha enquanto `value` for
prefixo exato de `target`. Um erro anterior (comum em Python, a parede da
indentação) deslocava o índice e o Tab "não inseria nada"; o fallback `"  "`
ainda injetava 2 espaços tóxicos contados como erro.

Extrai a lógica pura para `src/lib/indent.ts` (`indentEdit`): a indentação é
derivada da LINHA LÓGICA (nº de `\n` antes do caret), imune a divergências
upstream, e é no-op honesto quando não há indentação a preencher. Cobertura
com 10 casos espelhados em validate-metrics.mjs (Vitest da #31 ainda não
mergeou).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

@caioross is attempting to deploy a commit to the caioross' projects team on Vercel, but is not a member of this team. To resolve this issue, you can:

  • Make your repository public. Collaboration is free for open source and public repositories.
  • Upgrade to pro and add @caioross as a member. A Pro subscription is required to access Vercel's collaborative features.
    • If you're the owner of the team, click here to upgrade and add @caioross as a member.
    • If you're the user who initiated this build request, click here to request access.
    • If you're already a member of the caioross' projects team, make sure that your Vercel account is connected to your GitHub account.

To read more about collaboration on Vercel, click here.

@caioross

Copy link
Copy Markdown
Owner Author

🩺 Parecer do PR Doctor — APROVADA (Normal, HANDBOOK §7.3)

Diff lido inteiro. Classe Normal (engine de digitação; sem API/persistência/migração/CI/dep nova).

  • Corretude: a raiz do bug (índice cru target[caret] que só alinha enquanto value é prefixo de target, + fallback tóxico " ") é morta pela derivação da indentação a partir da linha lógica (nº de \n antes do caret) — imune a erro upstream. No-op honesto quando não há o que preencher.
  • Área sagrada intacta: text === value → early-return sem onChange, sem re-render; a lógica só dispara no Tab, nunca por keystroke da corrida.
  • Gate real (rodado do branch): validate-metrics.mjs37/37 (10 casos novos: início de linha, erro upstream, linha rasa=no-op, meio do código=no-op, target curto, seleção). O espelho em validate-metrics.mjs é logicamente idêntico a src/lib/indent.ts (só assinatura/comentários diferem). CI (typecheck+build) verde; a checagem "Vercel" falha por permissão de deploy do autor, não por código.
  • Closes #41 correto (resolve a fricção inteira).

Squash-merge.

@caioross
caioross merged commit 1da6666 into main Jul 19, 2026
2 of 3 checks passed
@caioross
caioross deleted the auto/issue-41-tab-indent branch July 19, 2026 00:11
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.

Engine/Input: Tab-para-indentar existe mas não insere a indentação na corrida (CodeEditor.tsx:95–115) — fricção nº1 do Iniciante

1 participant