AUR-427 — Documentação nativa de Rust e C#, sem ferramenta externa
Documento histórico do board. Pode descrever componentes removidos; para uso atual, consulte o guia do produto.
Comando
AURUMCODE_SOURCE_DIR=<diretório do projeto Rust ou C#> \
AURUMCODE_OUTPUT_DIR=<diretório de saída> \
go run ./cmd/regenerate-docs
Internamente, o comando acima registra os dois novos extratores nativos por
padrão, através da chamada de registro já existente em
cmd/regenerate-docs/main.go (registerLanguageExtractors):
if !repoCodeOptIn["rust"] {
if err := register(rustExtractor.NewNativeExtractor()); err != nil {
return err
}
}
if !repoCodeOptIn["csharp"] {
if err := register(csharpExtractor.NewNativeExtractor()); err != nil {
return err
}
}
Nota de contrato: aurumcode docs --source ./projeto-rust não é alcançável a partir deste card
O AC-001 "When" (.board/cards/ready/AUR-427.md:73) e a seção "Public
contract" (.board/cards/ready/AUR-427.md:82) declaram o comando
aurumcode docs --source ./projeto-rust — a sintaxe do subcomando
aurumcode docs que o card AUR-426 introduziu em cmd/aurumcode/docs.go.
Medido e reproduzível: este card não pode provar esse comando.
cmd/aurumcode não está em paths nem em read_paths
(.board/cards/ready/AUR-427.md:12), então nada neste candidato pode
escrever em cmd/aurumcode/docs.go, e dentro do sandbox de aceite
(bootstrap-readonly-v1, que materializa somente paths/read_paths) o
diretório cmd/aurumcode sequer existe. cmd/aurumcode/docs.go mantém sua
própria lista fixa de extratores em registerDocsExtractors
(cmd/aurumcode/docs.go:280), documentada como deliberadamente sem Rust/C#:
"Rust and C# are deliberately not registered here... wiring that opt-in path a second time is outside what this card's --help promises."
Não há ponto de registro compartilhado entre cmd/regenerate-docs e
cmd/aurumcode que este card possa tocar. Consequência declarada sem
meias-palavras: um revisor que rode literalmente
aurumcode docs --source <projeto-rust> hoje recebe zero páginas Rust —
o subcomando aurumcode docs continua sem conhecer os extratores nativos
deste card.
O Outcome, a Restrição medida, a Decisão registrada, os Non-goals e o
MUT-001 do próprio card, porém, são inteiramente satisfazíveis dentro de
paths: todos descrevem o par extrator+registro, não uma sintaxe de CLI
específica. Este card entrega e prova o comportamento através do comando
realmente alcançável dentro de paths/read_paths —
AURUMCODE_SOURCE_DIR=... AURUMCODE_OUTPUT_DIR=... go run ./cmd/regenerate-docs
— o mesmo padrão que o Public contract de AUR-424 já usava antes de
aurumcode docs existir. Nenhuma frase deste spec, do aceite ou do relatório
final afirma ter provado aurumcode docs --source.
O que mudou
Antes deste card, Rust e C# tinham extratores prontos
(internal/documentation/extractors/rust.RustExtractor,
internal/documentation/extractors/csharp.CSharpExtractor) que nunca eram
registrados por padrão: ambos executam código do repositório documentado
(cargo doc compila build.rs e proc-macros; dotnet build roda MSBuild,
que executa <Exec>/<UsingTask>/.targets do projeto), então
cmd/regenerate-docs/repo_code_execution.go os mantém atrás do opt-in
explícito AURUMCODE_ALLOW_REPO_CODE_EXECUTION. Mesmo com o opt-in, nenhum
dos dois roda no sandbox offline: cargo e dotnet/xmldocmd não existem
na imagem pinada. Resultado: Rust e C# nunca geravam página nenhuma no
caminho padrão.
A partir deste card, dois novos extratores —
internal/documentation/extractors/rust.NativeExtractor e
internal/documentation/extractors/csharp.NativeExtractor — leem os
comentários de documentação diretamente do texto-fonte, sem iniciar nenhum
subprocesso e sem tocar rede. RustExtractor/CSharpExtractor (as
implementações que chamam cargo/dotnet) não foram alteradas: os
testes fora de paths/read_paths deste card que fixam o contrato antigo
(internal/documentation/extractors/tool_unavailable_test.go,
tool_failure_test.go) continuam passando exatamente como antes, porque
continuam testando rust.NewRustExtractor/csharp.NewCSharpExtractor
diretamente — dois construtores que este card não tocou. Ver "Contratos
pré-existentes preservados" abaixo.
cmd/regenerate-docs/main.go registra o extrator nativo de cada linguagem
a menos que o operador já tenha optado por
AURUMCODE_ALLOW_REPO_CODE_EXECUTION=rust (ou csharp, ou ambos): os dois
caminhos são mutuamente exclusivos por linguagem, porque
extractors.Registry.Register recusa um segundo extrator para a mesma
linguagem. Com o opt-in, o comportamento de antes deste card continua
disponível sem mudança nenhuma (repo_code_execution.go está intocado).
Cobertura declarada (honestidade obrigatória)
Nenhum destes dois extratores tenta ser um compilador. O que cada um
reconhece — e, igualmente importante, o que cada um não reconhece e
portanto nunca aparece na página gerada — está documentado no comentário de
pacote de cada arquivo
(internal/documentation/extractors/rust/native.go,
internal/documentation/extractors/csharp/native.go) e resumido aqui.
Rust (internal/documentation/extractors/rust.NativeExtractor)
Reconhecido, com o comentário de doc associado:
pub fn(inclusivepub async fn,pub unsafe fn, e métodospub fndentro de um blocoimpl, em qualquer indentação);pub struct,pub enum,pub trait,pub mod,pub const,pub static,pub type;- um bloco
impl Tipo { ... }/impl Trait for Tipo { ... }que tenha, ele mesmo, um comentário de doc (o comentário do bloco, não dos membros dentro dele — esses são capturados individualmente pela regra depub fnacima); - os dois comentários de doc do Rust:
///(associado ao próximo item reconhecido) e//!(nível de módulo/crate, mostrado como introdução da página); - atributos
#[...]entre um comentário de doc e o item que ele anota (ex.#[derive(Debug)]) não quebram a associação.
Não reconhecido — ausente da página gerada, nunca afirmado como suportado:
- comentários de bloco
/** ... */(só comentários de linha são lidos); - itens gerados por macro: qualquer coisa produzida por
macro_rules!ou por uma proc-macro é invisível a um scanner de texto, por construção — provado emtests/fixtures/docs/rustproject/src/lib.rs(define_record_fn!(record_internal)) e nos três níveis de teste deste card (unit, integration, e2e); - visibilidade restrita (
pub(crate),pub(super)): deliberadamente excluída, nunca relatada como pública; - assinaturas que quebram linha (genéricos, cláusulas
where, listas de parâmetros que continuam além da linha do próprio item) são truncadas naquela linha; - reexportações (
pub use ...) e comentários de doc em campos de struct, variantes de enum, ou itens associados de trait individualmente.
C# (internal/documentation/extractors/csharp.NativeExtractor)
Reconhecido, com o comentário XML /// associado:
public class,public interface,public struct,public enum,public record(com qualquer combinação desealed,abstract,static,partial,readonly,unsafeantes da palavra-chave);- métodos
public, incluindo construtores (public NomeDaClasse(); - propriedades
publiccujo acesso{ getestá na mesma linha da declaração; - os elementos XML padrão
<summary>,<param name="...">,<returns>e<remarks>; elementos não reconhecidos dentro do comentário são ignorados, não rejeitam o comentário inteiro; - um comentário
///cujo conteúdo não é XML bem-formado: o extrator cai para o texto bruto do comentário (ainda mostrado na página, mas não quebrado em Summary/Parameters/Returns/Remarks) em vez de descartá-lo — provado porTestNativeExtractor_ExtractsRealSymbolsAndCommentseminternal/documentation/extractors/csharp/native_test.go.
Não reconhecido — ausente da página gerada, nunca afirmado como suportado:
- comentários de bloco
/** ... */; - campos, eventos, indexadores, operadores e implementações explícitas de interface;
- membros com corpo de expressão (
public int X => 1;) e auto-propriedades cujo acessor não seja literalmente{ getna própria linha da declaração (por exemplo{ get; set; }quebrado em várias linhas, ou propriedades com corpo=>); - declarações genéricas de tipo/método cuja assinatura quebra a linha da própria declaração.
Opções (via variáveis de ambiente lidas por cmd/regenerate-docs)
| Variável | Efeito |
|---|---|
AURUMCODE_SOURCE_DIR |
Raiz do projeto a documentar. |
AURUMCODE_OUTPUT_DIR |
Diretório onde as páginas Markdown são escritas. |
AURUMCODE_ALLOW_REPO_CODE_EXECUTION |
Lista separada por vírgula (rust, csharp, ou ambos). Quando uma linguagem está nessa lista, o extrator nativo deste card não é registrado para ela: o RustExtractor/CSharpExtractor antigo (que executa cargo/dotnet) é registrado no lugar. Ver cmd/regenerate-docs/repo_code_execution.go. |
Exit codes
Estes são os exit codes do próprio NativeExtractor.Extract (biblioteca) e
do aceite deste card (tests/acceptance/AUR-427.sh), não os do binário
completo cmd/regenerate-docs (que soma o resultado de todas as
linguagens):
Extractretornaerror != nilapenas para uma entrada inválida (idioma errado, diretório de origem inexistente) ou cancelamento de contexto; um arquivo individual que falhar ao escrever sua página é reportado emExtractResult.Errorse não interrompe os demais.tests/acceptance/AUR-427.sh: ver "Exit codes do aceite" abaixo.
Exemplo executável (sem segredo)
Com o projeto Rust mínimo deste card em
./tests/fixtures/docs/rustproject (um struct, um enum, três fn
públicas, todos com comentário de doc real, mais um item gerado por macro
que o parser não vê):
$ AURUMCODE_SOURCE_DIR=./tests/fixtures/docs/rustproject AURUMCODE_OUTPUT_DIR=./site \
go run ./cmd/regenerate-docs
...
✓ Source: .../tests/fixtures/docs/rustproject | Output: ./site | ...
📊 Generated 1 markdown file(s) in ./site:
- site/rust/src__lib.md
aurumcode: result=ok docs=1 skipped=0 failed=0 languages_skipped=none ...
site/rust/src__lib.md contém o comentário de crate (//!),
pub struct Entry/pub struct Ledger com seus campos e métodos,
pub fn new_entry/add/balance_cents com seus comentários de doc reais, e
pub enum EntryKind — símbolos e prosa reais extraídos do fonte. A função
gerada por macro (record_internal) e o método privado (entry_count) não
aparecem em lugar nenhum da página.
Nenhuma variável de ambiente com segredo é lida por este caminho de código.
Diagnóstico de falha
- Zero páginas Rust/C# com exit "no extractor registered" ou
"required tool not in PATH" (comportamento pré-correção): sintoma exato
do defeito que este card fecha. Só volta a acontecer se
AURUMCODE_ALLOW_REPO_CODE_EXECUTIONincluir a linguagem (o extrator antigo, que ainda depende decargo/dotnet, assume o lugar do nativo de propósito) — ver MUT-001 abaixo para a prova comportamental do caminho padrão. - Um símbolo existe no fonte mas não aparece na página: verificar a
tabela de cobertura acima — macro, visibilidade restrita, comentário de
bloco
/** */, ou assinatura que quebra linha são as causas cobertas. - Página gerada vazia ou ausente:
extractors.ConfirmOutputFilerecusa contar como gerado um arquivo que não existe, é diretório, ou tem zero bytes — o mesmo padrão de todo extrator deste diretório. - Comentário C#
///malformado como XML: não é erro; a página mostra o texto bruto do comentário em vez de Summary/Parameters/Returns/Remarks estruturados.
Escopo desta correção: só os dois extratores nativos
Este card não altera RustExtractor/CSharpExtractor (as implementações
cargo/dotnet), não altera o opt-in
AURUMCODE_ALLOW_REPO_CODE_EXECUTION, e não altera nenhum outro extrator
deste diretório (Go, Python, JavaScript/TypeScript, C++, Bash, PowerShell).
cmd/aurumcode/docs.go (o subcomando aurumcode docs de AUR-426) também não
é alterado — ver a "Nota de contrato" acima.
Contratos pré-existentes preservados (não alterados por este card)
Diferente de AUR-424 — que teve que reescrever
tool_unavailable_test.go/tool_failure_test.go porque mudou o contrato de
Validate() do extrator Go existente — este card não toca nenhum dos
dois. Ele adiciona dois construtores novos
(rust.NewNativeExtractor/csharp.NewNativeExtractor) em vez de mudar
rust.NewRustExtractor/csharp.NewCSharpExtractor, então as linhas
rust/cargo e csharp/dotnet/csharp/xmldocmd de
internal/documentation/extractors/tool_unavailable_test.go e
tool_failure_test.go continuam passando sem edição nenhuma. Esses dois
arquivos estão fora de paths/read_paths deste card (ver
.board/cards/ready/AUR-427.md:12 — a segunda revisão do card removeu
deliberadamente o diretório-pai internal/documentation/extractors de
read_paths, deixando só os arquivos específicos de que este card precisa),
então o aceite sandboxed não os reexecuta diretamente — verificado localmente
(go test ./internal/documentation/extractors/..., todos os pacotes verdes).
O que o aceite sandboxed prova diretamente é mais estreito, mas real: a
lane de regressão (tests/acceptance/AUR-427.sh::regression_case) roda
go test ./internal/documentation/extractors/rust ./internal/documentation/extractors/csharp
dentro do sandbox, que inclui extractor_test.go de cada pacote — os testes
pré-existentes de RustExtractor/CSharpExtractor (TestNewRustExtractor,
TestRustExtractor_Validate, TestRustExtractor_Extract_NoCargo, e os
equivalentes de C#) — e assim confirma, dentro do próprio aceite, que os dois
extratores antigos continuam intactos nos dois pacotes que este card de fato
tocou.
internal/documentation/extractors/registry_test.go e
output_confirmed_test.go também não são tocados e também passam
localmente pelo mesmo motivo.
Limitação de infraestrutura medida: fixture C# checked-in fora de paths
paths deste card declara tests/fixtures/docs/rustproject mas nenhum
diretório de fixture C# (.board/cards/ready/AUR-427.md:12). A cobertura de
C# neste card vem de fixtures em memória, escritas em tempo de execução
pelos próprios arquivos de teste
(internal/documentation/extractors/csharp/native_test.go,
tests/unit/AUR-427.go, tests/integration/AUR-427.go) e por
tests/e2e/AUR-427.sh (que escreve um .cs em $run_dir antes de rodar o
binário real) — nunca por um arquivo .cs commitado fora de paths.
Exit codes do aceite
0prova, com as seis lanes (nominal, unit, integration, e2e, regressão, mutação) executadas;1comportamento ausente (AUR-427/AC-001/behavior-missing), afirmação falsa de cobertura (AUR-427/AC-001/false-claim), saída não determinística (AUR-427/AC-001/nondeterministic-output:...), vazamento de segredo (AUR-427/AC-001/secret-leak), regressão fora do diff (AUR-427/AC-001/regression:<rc>), ou mutação não rejeitada (AUR-427/AC-001/MUT-001/...);64seletor desconhecido;69infraestrutura (goausente, module cache ausente, árvore não materializada).
MUT-001
Change: desligar o registro padrão de Rust (main.go's
if !repoCodeOptIn["rust"] { vira if false {, que nunca é verdadeiro — o
extrator nativo de Rust nunca é registrado, mas o corpo do bloco — e o
import de rustExtractor que ele referencia — continua presente e o binário
continua compilando: uma falha de compilação não conta como RED sob o TDD
proof deste card).
Expected: o mesmo accept sai diferente de zero
(AUR-427/AC-001/MUT-001/...) porque o binário mutante, rodado de verdade
contra o fixture do card, produz zero páginas Rust e (como o fixture só tem
fonte Rust) sai com exit não-zero pelo piso de degradação do AUR-425 — e a
restauração (reverter a mutação, ainda no diretório mutante escrito por
sed, nunca no candidato commitado) reproduz o GREEN exato do binário
compartilhado não-mutado. A checagem textual de call-site do Integration
(IntegrationAUR427) deliberadamente NÃO é usada como falsificador aqui: ela
apenas confirma que a chamada rustExtractor.NewNativeExtractor() não foi
apagada do texto-fonte, o que continua verdadeiro depois desta mutação (só a
condição do guarda mudou, não a chamada) — ver o comentário em
tests/acceptance/AUR-427.sh::mutation_case para o porquê dessa assimetria.
Prova
- Unit
tests/unit/AUR-427.go::TestAUR427: fixtures em memória para as duas linguagens,Validate()semprenil, páginas reais com símbolos e comentários reais, ausência comprovada de símbolos privados/gerados por macro. - Integration
tests/integration/AUR-427.go::IntegrationAUR427: registro real emextractors.Registry, extração do fixture Rust checked-in (tests/fixtures/docs/rustproject) duas vezes com digest idêntico (determinismo), fixture C# em memória, e verificação textual dos dois call sites emcmd/regenerate-docs/main.go. - E2E
tests/e2e/AUR-427.sh::E2EAUR427: execução real do binário — Rust via fixture checked-in, C# via fixture efêmera escrita pelo próprio script — com determinismo (Rust, duas execuções), checagem de canário de segredo, e ausência comprovada dos símbolos não cobertos. - Acceptance
tests/acceptance/AUR-427.sh::AC-001via./.board/bin/oci-run --profile bootstrap-readonly-v1 --card AUR-427, incluindo a lane de regressão (go test ./cmd/regenerate-docs./internal/documentation/extractors/rust./internal/documentation/extractors/csharp— os três subárvores de teste pré-existentes inteiramente dentro depathsdeste card) e o MUT-001 descrito acima.
Todo comando Go destes scripts roda com teto de memória embutido no próprio
script (ulimit -v 8388608, GOMEMLIMIT=2GiB, GOFLAGS='-mod=mod -p=1',
go test -timeout 300s), para que um revisor que rode
bash tests/acceptance/AUR-427.sh diretamente tenha a mesma proteção.