-
Notifications
You must be signed in to change notification settings - Fork 2
feat(corpus): convenção _* em todo o engine e reagrupamento por livro #71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
15231c8
a5f0de4
39e4042
ab66089
5c048bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| feature: 029-chapters-regroup | ||
| mode: act | ||
| pipeline_state: READY_FOR_COMMIT | ||
| branch: feat/029-chapters-regroup | ||
| last_updated: 2026-08-06 | ||
| --- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| --- | ||
| feature: 029-chapters-regroup | ||
| status: validated | ||
| validated_at: 2026-08-06 | ||
| validated_by: orquestrador (Fable 5); premissas da exploração de 2026-08-05 reconferidas contra main pós-#70 | ||
| --- | ||
|
|
||
| # CONTRACT — 029-chapters-regroup | ||
|
|
||
| ## Premissas técnicas verificadas | ||
|
|
||
| | # | Premissa | Verificação | Estado | | ||
| |---|---|---|---| | ||
| | 1 | Os 7 furos de `_*` existem e são os únicos | exploração 2026-08-05: `lint.py:33,53`, `heal.py:85-89`, `archive.py:44-45,72`, `compile.py:592-593`, `stats.py:4-8`; honram: search, embeddings, lexical, graph, api | **confirmado** | | ||
| | 2 | heal pode tocar `_summaries` hoje | `heal.py:85-89` exclui só `_index.md` e `.heal_backup`; 1.027 summaries elegíveis ao sorteio | **confirmado — bug latente que C1 corrige** | | ||
| | 3 | `manifest.book` existe para agrupar | 028 materializou 849 ligações com `book`; 126 `unresolved` fora | **confirmado** | | ||
| | 4 | Manutenção de manifest em move existe | `update_article_path`/`mark_archived` (028 B1/B4) com testes | **confirmado** | | ||
| | 5 | Mover arquivo não exige re-embedar | build por hash/relpath descarta e re-adota; `_chapters/` fica invisível após C1 | **confirmado** | | ||
| | 6 | Sem cron do kb | `crontab -l` reverificado 2026-08-05 | **confirmado** | | ||
| | 7 | `find_orphans` marcaria os 975 pós-move | 973/975 sem backlink (medição do ADR) — C1 antes de C4 é hard gate | **confirmado** | | ||
|
|
||
| ## Premissas de produto | ||
|
|
||
| - Move para `_chapters/` SÓ com aprovação explícita do dono no C4, ciente de que a wiki visível esvazia (~5 artigos + unresolved) até o compile multi-fonte. | ||
| - `unresolved` nunca é movido por inferência — permanece na wiki como pendência humana. | ||
| - Commit por livro; tag antes do lote; tudo move, nunca unlink. | ||
| - Golden set preservado em disco; perda de retrievability aceita pelo ADR-0018 e registrada. | ||
|
|
||
| ## Riscos aceitos | ||
|
|
||
| | Risco | Mitigação | | ||
| |---|---| | ||
| | Move em massa com path novo quebra wikilinks qualificados dos unresolved que ficam | Relatório do C4 lista; wikilink por stem continua resolvendo via graph (stem inalterado) | | ||
| | Nome de livro sujo (sufixos de fonte) vira slug ruim | Sanitização com teste; relatório mostra o slug antes do apply | | ||
| | Bench sem objeto pós-move | Aceito; registrado no REPORT | | ||
|
|
||
| ## Gate de TDD | ||
|
|
||
| 2 condições binárias de risco (I/O em store real; output estrutural do plano de move) → `test-design` com `test-red` base; cada módulo adotante do C1 tem teste próprio de exclusão. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # PLAN — 029-chapters-regroup | ||
|
|
||
| **Branch:** `feat/029-chapters-regroup` | ||
| **Data:** 2026-08-06 | ||
| **Spec:** `features/029-chapters-regroup/SPEC.md` · **Domain:** `features/027-noise-retro/DOMAIN.md` | ||
|
|
||
| ## Contexto técnico | ||
|
|
||
| | Campo | Valor | | ||
| |---|---| | ||
| | Alvo | `kb/fsutil.py` (helper), `kb/lint.py:33,53`, `kb/heal.py:85-104`, `kb/archive.py:44-45,72`, `kb/compile.py:592-593`, `kb/stats.py:4-8`, novo `kb/regroup.py`, `kb/cli.py` | | ||
| | Reuso | `graph._e_artigo` (semântica de referência), `archive.move_to_archive`, `state.mark_archived`/`update_article_path`/`load_manifest`, `compile.update_index`, `refresh_embeddings_index`, maquinaria de lote HITL das 027/028 | | ||
| | Estratégia de testes | test-design: I/O em store real (move em massa + manifest) e output estrutural (plano de move é contrato do gate humano) | | ||
|
|
||
| ## Desenho | ||
|
|
||
| 1. **C1 — `kb/fsutil.iter_articles(wiki_dir)`**: generator com a semântica de `graph._e_artigo` (`_`/`.` em qualquer componente, symlink fora). Adotado em: `lint.find_ambiguous_wikilinks` e `lint_wiki`; `heal._sample_paths`; `archive.find_orphans`/`find_by_age`; `compile.update_index`; `stats`. `graph._e_artigo` passa a delegar ao helper (uma semântica, um lugar). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: C1's description is inaccurate and will mislead future readers documenting the single-source-of-truth goal. Prompt for AI agents |
||
| 2. **C2 — heal sem unlink**: `_remove_stub` usa `move_to_archive` (dest `ARCHIVE_DIR/<rel>`), remove o `_backup` caseiro para stubs (o backup versionado do archive cobre) e chama `mark_archived`. `.heal_backup` legado permanece intocado. | ||
| 3. **C3 — `kb/regroup.py`**: `plan_regroup(wiki_dir, manifest)` → grupos `{book: [(artigo, destino)]}` + `unresolved: [artigo]`; destinos `wiki/_chapters/<book-slug>/<nome>` e summary espelho em `wiki/_summaries/_chapters/<book-slug>/`. `apply_book(book)` move via `move_to_archive`-like (mesma contenção, mas destino é `_chapters/` — usar move com `atomic`/`shutil.move` + backup versionado próprio), `update_article_path`, `update_index`, refresh. Book-slug: slugify do nome do livro (nomes vindos de metadata têm " -- Anna's Archive" etc. — sanitizar). | ||
| 4. **C4 — ops**: preflight + tag `pre-regroup-<data>` → `regroup scan` → relatório por livro (contagem, exemplos, unresolved) → aprovação explícita → apply livro a livro (commit por livro) → `kb index build` + smoke + tela. | ||
|
|
||
| ## Riscos | ||
|
|
||
| - `update_index`/embeddings ficam consistentes porque C1 os ensina a ignorar `_chapters/` ANTES de qualquer move (ordem C1 → C3 é hard gate). | ||
| - Slug de livro com nomes sujos de metadata → sanitização com teste. | ||
| - 126 `unresolved` permanecem na wiki — visíveis no relatório, decisão humana posterior. | ||
| - Bench/golden perdem objeto após o move — aceito (ADR), registrado. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # REPORT — 029-chapters-regroup | ||
|
|
||
| **Estado:** `DONE_WITH_CONCERNS` | ||
| **Branch:** `feat/029-chapters-regroup` | ||
|
|
||
| ## Contexto | ||
|
|
||
| Terceira e última feature do esforço de higiene (etapa 3 do ADR-0018). Antes dela: sete pontos do engine ignoravam a convenção `_*` (o heal podia deletar summary hoje), o heal era a última remoção destrutiva (`unlink`), e os 975 artigos de capítulo seguiam misturados na wiki visível. | ||
|
|
||
| ## Mudanças (engine) | ||
|
|
||
| - **C1 — `kb/fsutil.iter_articles`**: semântica única de artigo vivo (`_*`, `.*`, symlink fora), adotada por lint, heal, archive (órfãos e idade), `update_index` e stats. Fecha o bug latente do heal sobre `_summaries` e o cenário em que `find_orphans` arrastaria `_chapters/` inteiro para `archive/`. | ||
| - **C2 — heal sem unlink** (V7 mínimo): stub vai para `archive/` com hierarquia e backup versionado; manifest marcado `archived`. A unificação do formato do `.heal_backup` legado fica como dívida registrada. | ||
| - **C3 — `kb regroup scan|apply --book`**: plano por proveniência do manifest (nunca cosseno), slug sanitizado por livro, summaries espelhados, `unresolved` jamais movido por inferência, commit por livro via `move_to_archive` com raiz de contenção em `_chapters/`. | ||
|
|
||
| ## Lote final (C4, gate explícito do dono) | ||
|
|
||
| Decisão do dono em 2026-08-06: **mover 37 livros (630 artigos); `transcripts-youtube` (207) e `harness` (14) ficam** — não são livros, e com os 124 `unresolved` a plataforma mantém ~345 artigos visíveis até o compile multi-fonte. | ||
|
|
||
| Executado em 2026-08-06: **37 livros, 630 artigos + summaries movidos, 37 commits** (um por livro), zero erros, tag `pre-regroup-2026-08-06`. Vault final: **345 artigos vivos** (207 transcripts + 14 harness + 124 unresolved — soma exata), 630 em `_chapters/`. Smoke: índice em 345/345 artigos (2.666 chunks), `kb search` e `kb stats` respondendo, plataforma com home povoada e artigo vivo abrindo (tela conferida). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: The final count of '124 unresolved' (and implied 851 with provenance) contradicts the feature's own baseline of 126 unresolved stated in SPEC.md, CONTRACT.md premise 3, and PLAN.md. The −2 delta implies 2 articles left the unresolved set during C4 but the report never documents that event, breaking the documentary-traceability standard the project follows. Reconcile the numbers against the baseline or add a note explaining the two resolved articles. Prompt for AI agents |
||
|
|
||
| ## Incidente do ciclo (registrado, não escondido) | ||
|
|
||
| O RED do C2 expôs a **terceira ocorrência do dia** da mesma classe: teste sem isolamento moveu stubs de fixture para o `archive/` do vault real e regenerou o `_index.md` real. Limpeza aprovada pelo dono; fix estrutural: o piso autouse do conftest agora cobre `ARCHIVE_DIR` e `kb.compile.WIKI_DIR`, como cobre `STATE_DIR` desde 2026-07-29. | ||
|
|
||
| ## Validação | ||
|
|
||
| **1.042 passed** (13 testes novos de fsutil/regroup + reescritas de heal), ruff limpo, appeasement exit 0, cobertura 93%. | ||
|
|
||
| ## Riscos e dívida | ||
|
|
||
| | Item | Estado | | ||
| |---|---| | ||
| | 28 menções a paths `wiki/` em `claims.jsonl`/`knowledge.json` dangling pós-move | Aceito pelo ADR; jobs decay/contradiction não instalados | | ||
| | Golden set do bench sem objeto (851 slugs referenciados) | Aceito pelo ADR; golden preservado em disco | | ||
| | `.heal_backup` legado com formato próprio | Dívida registrada (V7 completo) | | ||
| | `transcripts-youtube`/`harness` seguem como artigo de capítulo | Decisão do dono; reavaliar quando o compile multi-fonte definir o que é tema | | ||
|
|
||
| ## Próximos passos | ||
|
|
||
| O esforço do ADR-0018 (etapas 1–3) fecha aqui. O próximo é o **compile multi-fonte** (pré-requisitos agora existem: proveniência materializada, `library/` íntegra, `_chapters/` populado) — esforço novo, com wayfinder/spec próprio. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| --- | ||
| feature: 029-chapters-regroup | ||
| title: Convenção _* honrada em todo o engine e reagrupamento por livro | ||
| epic: infra | ||
| status: done | ||
| created: 2026-08-06 | ||
| pr: | ||
| --- | ||
|
|
||
| # Convenção `_*` honrada em todo o engine e reagrupamento por livro | ||
|
|
||
| ## Objetivo | ||
|
|
||
| Hoje sete pontos do engine ignoram a convenção `_*` (o heal pode deletar summary **hoje**; pós-move, `find_orphans` arrastaria `_chapters/` inteiro para `archive/`) e os 975 artigos de capítulo seguem misturados na wiki; ao final, `_*` é invisível para todo o engine, nenhuma remoção é `unlink`, e os capítulos estão agrupados por livro em `wiki/_chapters/` — com o move final executado apenas sob aprovação explícita do dono, ciente de que a wiki visível esvazia até o compile multi-fonte existir. | ||
|
|
||
| ## Requisitos funcionais | ||
|
|
||
| - [x] RF-01 [P1] (C1): Dado qualquer diretório `_*` ou `.*` sob `wiki/`, quando `lint`, `heal`, `archive` (órfãos e idade), `update_index` e `stats` rodarem, então nenhum arquivo dentro dele é listado, amostrado, indexado, contado ou marcado como candidato — mesma semântica já usada por search/embeddings/graph. | ||
| - [x] RF-02 [P1] (C2): Dado um stub detectado pelo heal, quando a remoção executar, então o arquivo vai para `archive/` com a semântica de `move_to_archive` (hierarquia + backup versionado), nunca `unlink`; o manifest é atualizado (`mark_archived`). | ||
| - [x] RF-03 [P1] (C3): Dado `kb regroup scan`, quando rodar, então agrupa os artigos vivos por livro via proveniência do manifest (com os `unresolved` listados como braço de decisão humana) e imprime o plano de move `wiki/<...> → wiki/_chapters/<livro>/`, sem alterar nada. | ||
| - [x] RF-04 [P1] (C3): Dado `kb regroup apply --book <slug>`, quando executar, então move os artigos do livro (e seus summaries, para `wiki/_summaries/_chapters/<livro>/`) preservando o nome, atualiza `update_article_path` no manifest, regenera `_index.md`, refresca embeddings e commita **por livro**. | ||
| - [x] RF-05 [P1] (C4): Dado o lote final, quando o dono aprovar explicitamente ("a wiki esvazia"), então os livros aprovados são movidos um a um, com tag git prévia e smoke de search/stats ao final; sem aprovação, nada se move. | ||
| - [x] RF-06 [P2]: Dado um artigo `unresolved` (sem proveniência), quando o regroup rodar, então ele permanece na wiki e aparece no relatório como pendência humana — nunca é movido por inferência. | ||
|
|
||
| ## Requisitos técnicos | ||
|
|
||
| - Helper único (`kb/fsutil.iter_articles(wiki_dir)` ou equivalente) com a semântica de `graph._e_artigo` (`_` e `.`), adotado nos sete pontos; sem mudança de assinatura pública dos comandos. | ||
| - `heal` mantém `--commit` e o registro de backup; a política de remoção única (move) fecha a dívida V7 no escopo do heal — a unificação do formato de backup do `.heal_backup` legado fica fora. | ||
| - Agrupamento pela chave `book` do manifest (materializada na 028); cosseno/`MAPA-DE-TEMAS.md` são insumo do relatório para temas transversais, não critério de move. | ||
| - Golden set e links do workspace `teach` quebram no move — perda aceita pelo ADR-0018, registrada no REPORT. | ||
| - Checar `claims.jsonl`/`knowledge.json` por referências a paths antes do C4; dangle aceito e registrado se houver. | ||
|
|
||
| ## Mudanças de API/CLI | ||
|
|
||
| - Novo sub-app `regroup`: `kb regroup scan` e `kb regroup apply --book <slug> [--no-commit|--commit]`. | ||
| - `heal`: mudança de comportamento documentada (stub vai para `archive/` em vez de `unlink`). | ||
|
|
||
| ## Testes | ||
|
|
||
| - Unit: `iter_articles` exclui `_*`/`.*`/symlink; cada adotante coberto (lint não lista, heal não sorteia, archive não marca, update_index não indexa, stats não conta artigo sob `_*`); heal move stub com backup e marca manifest; regroup agrupa por `book`, ignora `unresolved`, calcula destinos. | ||
| - Integration: vault fixture com manifest → `regroup scan` imprime plano; `apply --book` move artigo+summary, atualiza manifest, regenera índice, commita por livro (git fixture); artigo movido some de search/stats/_index. | ||
| - Manual (C4, HITL): preflight + tag → relatório de grupos → aprovação explícita do dono → apply livro a livro → `kb index build` + smoke + tela da plataforma. | ||
|
|
||
| ## Dados de contexto | ||
|
|
||
| | Chave | Valor | | ||
| |-------|-------| | ||
| | Estimativa | 8h | | ||
| | Bloqueador | não | | ||
| | Risk | média-alta — move em massa; mitigada por commit por livro, tags, manifest e gate final humano | | ||
|
|
||
| ## Dependências | ||
|
|
||
| - 028 mergeada (PR #70): `manifest.book`, `mark_archived`, `update_article_path`. | ||
| - DOMAIN compartilhado: `features/027-noise-retro/DOMAIN.md`. | ||
|
|
||
| ## Notas | ||
|
|
||
| Terceira e última feature do esforço (etapa 3 do ADR-0018). Estado do vault na abertura: 975 artigos vivos, 856 entradas de manifest (849 com proveniência, 126 `unresolved` fora), 10 topics canônicos. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # TASKS — 029-chapters-regroup | ||
|
|
||
| **Spec:** `features/029-chapters-regroup/SPEC.md` | ||
| **Plan:** `features/029-chapters-regroup/PLAN.md` | ||
|
|
||
| ```yaml | ||
| - id: C1 | ||
| priority: P1 | ||
| parallel: false | ||
| depends_on: [] | ||
| ac_ref: RF-01 | ||
| tag: AFK | ||
| vertical_slice: yes | ||
| behavior: "iter_articles único honra _*/.*/symlink e é adotado por lint, heal, archive, update_index e stats; heal deixa de poder tocar _summaries hoje." | ||
| verify: "python -m pytest tests/unit/test_fsutil_articles.py tests/unit/test_lint.py tests/unit/test_heal.py tests/unit/test_archive.py tests/unit/test_stats.py -q" | ||
| state: passing | ||
| ``` | ||
|
|
||
| ```yaml | ||
| - id: C2 | ||
| priority: P1 | ||
| parallel: false | ||
| depends_on: [C1] | ||
| ac_ref: RF-02 | ||
| tag: AFK | ||
| vertical_slice: yes | ||
| behavior: "Stub removido pelo heal vai para archive/ com backup versionado e manifest marcado archived — nunca unlink (V7 mínimo)." | ||
| verify: "python -m pytest tests/unit/test_heal.py -q" | ||
| state: passing | ||
| ``` | ||
|
|
||
| ```yaml | ||
| - id: C3 | ||
| priority: P1 | ||
| parallel: false | ||
| depends_on: [C1] | ||
| ac_ref: RF-03, RF-04, RF-06 | ||
| tag: AFK | ||
| vertical_slice: yes | ||
| behavior: "kb regroup scan agrupa por manifest.book com unresolved como braço humano; apply --book move artigo+summary para _chapters/, atualiza manifest e índices, commita por livro." | ||
| verify: "python -m pytest tests/unit/test_regroup.py tests/integration/test_regroup_cli.py -q" | ||
| state: passing | ||
| ``` | ||
|
|
||
| ```yaml | ||
| - id: C4 | ||
| priority: P1 | ||
| parallel: false | ||
| depends_on: [C2, C3] | ||
| ac_ref: RF-05 | ||
| tag: HITL | ||
| vertical_slice: yes | ||
| behavior: "Gate final do dono: relatório de grupos → aprovação explícita (a wiki esvazia) → apply livro a livro com tag prévia → index build + smoke + tela." | ||
| verify: "relatório aprovado + contagens + tela" | ||
| state: passing | ||
| ``` | ||
|
|
||
| ## Definition of Done | ||
|
|
||
| `state: passing` = verify verde + (HITL) evidência de aprovação e tela. Feature fecha com C1–C4 passing e `quality-gate` PASS. |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -30,6 +30,7 @@ | |||||||||
| "dedup scan | dedup apply [--no-commit|--commit]\n\n" | ||||||||||
| "topics normalize [--apply] [--no-commit|--commit] | topics assign [--apply] [--limit INT] [--no-commit|--commit]\n\n" | ||||||||||
| "archive [--stale] [--older-than INT] [--dry-run]\n\n" | ||||||||||
| "regroup scan | regroup apply --book <slug> [--no-commit|--commit]\n\n" | ||||||||||
| "compile (alvo) [--workers/-j INT] [--allow-sensitive] [--no-commit|--commit]" | ||||||||||
| " [--no-update-index]\n\n" | ||||||||||
| "qa <pergunta> [--file-back/-f] [--to-wiki] [--depth INT] [--no-traverse]" | ||||||||||
|
|
@@ -53,6 +54,7 @@ | |||||||||
| manifest_app = typer.Typer(help="Proveniência artigo→fonte no manifest (backfill)") | ||||||||||
| dedup_app = typer.Typer(help="Duplicatas de ingestão (scan/apply)") | ||||||||||
| topics_app = typer.Typer(help="Topics do frontmatter (normalize/assign)") | ||||||||||
| regroup_app = typer.Typer(help="Reagrupamento de capítulos por livro (scan/apply)") | ||||||||||
| app.add_typer(jobs_app, name="jobs") | ||||||||||
| app.add_typer(discovery_app, name="discovery") | ||||||||||
| app.add_typer(handoff_app, name="handoff") | ||||||||||
|
|
@@ -61,6 +63,67 @@ | |||||||||
| app.add_typer(manifest_app, name="manifest") | ||||||||||
| app.add_typer(dedup_app, name="dedup") | ||||||||||
| app.add_typer(topics_app, name="topics") | ||||||||||
| app.add_typer(regroup_app, name="regroup") | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def _regroup_plan(): | ||||||||||
| from kb.config import WIKI_DIR | ||||||||||
| from kb.regroup import plan_regroup | ||||||||||
| from kb.state import load_manifest | ||||||||||
|
|
||||||||||
| return plan_regroup(WIKI_DIR, load_manifest()) | ||||||||||
|
|
||||||||||
|
|
||||||||||
| @regroup_app.command("scan") | ||||||||||
| def regroup_scan(): | ||||||||||
| """Plano de reagrupamento por livro (dry-run; não altera nada).""" | ||||||||||
| from kb.config import WIKI_DIR | ||||||||||
|
|
||||||||||
| plan = _regroup_plan() | ||||||||||
| for slug in sorted(plan.groups): | ||||||||||
| artigos = plan.groups[slug] | ||||||||||
| typer.echo(f"[{slug}] {len(artigos)} artigo(s) — {plan.book_names[slug][:60]}") | ||||||||||
| for origem, destino in artigos: | ||||||||||
| typer.echo(f" {origem.relative_to(WIKI_DIR)} → {destino.relative_to(WIKI_DIR)}") | ||||||||||
| typer.echo( | ||||||||||
| f"{sum(len(v) for v in plan.groups.values())} artigo(s) em {len(plan.groups)} livro(s); " | ||||||||||
| f"{len(plan.unresolved)} unresolved (permanecem na wiki)" | ||||||||||
| ) | ||||||||||
| for artigo in plan.unresolved: | ||||||||||
| typer.echo(f"unresolved {artigo.relative_to(WIKI_DIR)}") | ||||||||||
|
|
||||||||||
|
|
||||||||||
| @regroup_app.command("apply") | ||||||||||
| def regroup_apply( | ||||||||||
| book: str = typer.Option(..., "--book", help="Slug do livro a mover (um por commit)"), | ||||||||||
| no_commit: bool = typer.Option(True, "--no-commit/--commit"), | ||||||||||
| ): | ||||||||||
| """Move os artigos de UM livro para _chapters/ (commit por livro).""" | ||||||||||
| from kb.config import MANIFEST_PATH, WIKI_DIR | ||||||||||
| from kb.regroup import apply_book | ||||||||||
|
|
||||||||||
| plan = _regroup_plan() | ||||||||||
| if book not in plan.groups: | ||||||||||
| typer.echo(f"livro desconhecido no plano: {book}", err=True) | ||||||||||
| raise typer.Exit(2) | ||||||||||
| log = apply_book(WIKI_DIR, plan, book) | ||||||||||
| moved = [entry for entry in log if entry["action"] == "moved"] | ||||||||||
| for entry in log: | ||||||||||
| if entry["action"] == "moved": | ||||||||||
| typer.echo(f"movido: {entry['dest']}") | ||||||||||
| else: | ||||||||||
| typer.echo(f"erro: {entry['source']} — {entry.get('detail', '')}", err=True) | ||||||||||
| typer.echo(f"{len(moved)} arquivo(s) movidos para _chapters/{book}/") | ||||||||||
| if moved and not no_commit: | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: A regroup that reports an error can still create a successful per-book commit containing only the moves that happened before the failure. The commit should be skipped whenever Prompt for AI agents
Suggested change
|
||||||||||
| from kb.git import commit | ||||||||||
|
|
||||||||||
| paths = [Path(entry["source"]) for entry in moved] | ||||||||||
| paths += [Path(entry["dest"]) for entry in moved] | ||||||||||
| paths += [Path(entry["backup"]) for entry in moved if "backup" in entry] | ||||||||||
| paths += [WIKI_DIR / "_index.md", MANIFEST_PATH] | ||||||||||
| commit(f"chore(corpus): reagrupa {book} em _chapters/", paths) | ||||||||||
| if any(entry["action"] == "error" for entry in log): | ||||||||||
| raise typer.Exit(1) | ||||||||||
|
|
||||||||||
|
|
||||||||||
| @topics_app.command("normalize") | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3: Premise 1 claims the '7 furos' are the only ones and that the API honors the
_*convention, but kb/api/articles.py:39 (the fingerprint rglob) only skips symlinks and does not exclude_*/.*paths, so files under_chapters/still get scanned/counted there. The actual index is built through graph.build_link_index (which honors_*), so there is no user-visible break — but the premise as recorded is inaccurate and RF-01's 'nenhum arquivo ... listado/contado' semantics isn't fully met at that site. Consider filtering_/.parts in the fingerprint too, or revising the premise/contract text to reflect this residual gap.Prompt for AI agents