# Worklogs
## 2026-06-10
### Repositorio inicial
[x] Repositorio Git existente en rama `main`.
[x] Fuente de verdad definida: `plan_libreria_xml_generica_rust.md`.
[x] Alcance limitado al motor XML.
[x] Dominios dejados fuera de alcance.
Commits conocidos:
[] `3b9d4c0` - `Initial XML engine planning repository`
[] `7b234a9` - `Record initial repository setup`
### Reestructuracion de tareas
[x] Rehacer documentos de tareas con criterios medibles.
[x] Agregar instrucciones ejecutables y verificables.
[x] Separar tareas por componente del motor.
### Decision de una sola crate
[x] Adaptar el backlog a una crate unica `xdoc`.
[x] Reinterpretar las crates del plan como carpetas/modulos internos.
[x] Mantener fuera de alcance el workspace multi-crate para el motor.
### Excepcion para proc-macro
[x] Documentar `xdoc-macros` como unica excepcion permitida a la crate unica.
[x] Limitar la excepcion a la macro procedural `xml!`.
### Direccion tipo Leptos para XML
[x] Documentar que la API objetivo debe parecerse a Leptos, pero para XML.
[x] Agregar tarea para modelo de componentes con props tipadas y children.
[x] Conectar builder, macro y transform con el modelo de componentes.
### Tarea 001 - Scope And Architecture
[x] Tarea actual: `docs/tasks/001-scope-and-architecture.md`.
[x] Estado exacto: completada como tarea documental; no se creo codigo Rust.
[x] Archivos tocados: `docs/tasks/001-scope-and-architecture.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: se mantiene una sola crate `xdoc`; los nombres `xdoc-*` del plan se interpretan como modulos internos `src/*`; no se habilitan tareas de dominio.
[x] Comandos ejecutados: `rg -n "El dominio depende del motor XML|src/core|src/signature|fuera de alcance" docs`; `rg -n "^# .*UBL|^# .*DIAN|^# .*SOAP" docs/tasks`.
[x] Verificacion: la primera busqueda encontro reglas y componentes principales; la segunda no encontro tareas tituladas como dominios UBL, DIAN o SOAP.
[x] Verificacion Rust: `cargo fmt --all -- --check`, `cargo check` y `cargo test` no aplican todavia porque no existe `Cargo.toml` ni codigo Rust suficiente; la siguiente tarea crea la crate.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/002-crate-scaffold.md`.
### Tarea 002 - Crate Scaffold
[x] Tarea actual: `docs/tasks/002-crate-scaffold.md`.
[x] Estado exacto: completada; existe una sola crate Rust `xdoc` con modulos internos minimos y binario `xdoc`.
[x] Archivos tocados: `Cargo.toml`, `src/lib.rs`, `src/bin/xdoc.rs`, `src/*/mod.rs`, `docs/tasks/002-crate-scaffold.md`, `docs/worklogs.md`; `Cargo.lock` fue generado por Cargo pero sigue ignorado por `.gitignore`.
[x] Decisiones tomadas: usar Rust edition 2021 para compatibilidad; no crear `crates/`; no crear `src/domains/`; mantener los modulos como shells documentados hasta sus tareas especificas.
[x] Comandos ejecutados: `cargo metadata --format-version 1 --no-deps`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `test ! -d crates || { test -d crates/xdoc-macros && test "$(find crates -mindepth 1 -maxdepth 1 -type d | wc -l)" -eq 1; }`; `test ! -d src/domains`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo metadata` lista un solo package llamado `xdoc`.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/003-core-names-namespaces-errors.md`.
### Tarea 003 - Core Names Namespaces And Errors
[x] Tarea actual: `docs/tasks/003-core-names-namespaces-errors.md`.
[x] Estado exacto: completada; el core expone `QName`, `NamespaceUri`, `NamespacePrefix`, `NamespaceDeclaration`, `NamespaceTable`, `XmlError`, `ErrorKind`, `Span` y `XmlResult`.
[x] Archivos tocados: `src/core/mod.rs`, `src/core/names.rs`, `src/core/namespace.rs`, `src/core/error.rs`, `docs/tasks/003-core-names-namespaces-errors.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: validacion inicial de nombres XML conservadora en ASCII; `:` no se acepta dentro de local names ni prefijos porque los namespaces se modelan estructuralmente; `NamespaceTable` usa `BTreeMap` para orden deterministico de prefijos.
[x] Comandos ejecutados: `cargo test qname`; `cargo test namespace`; `cargo test error`; `cargo test core`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 12 tests unitarios del core.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/004-core-document-tree.md`.
### Tarea 004 - Core Document Tree
[x] Tarea actual: `docs/tasks/004-core-document-tree.md`.
[x] Estado exacto: completada; el core representa documentos XML como arbol tipado con `Document`, `NodeId`, `Node`, `NodeKind`, `ElementData`, `Attribute` y `XmlPath`.
[x] Archivos tocados: `src/core/mod.rs`, `src/core/tree.rs`, `docs/tasks/004-core-document-tree.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: almacenar nodos en arena `Vec<Node>` y relacionarlos solo con `NodeId`; permitir un unico root element; permitir texto, comentario, CDATA y processing instruction como hijos de elementos; mantener `XmlPath` como ruta logica simple basada en nombres lexicales y tipos de nodo.
[x] Comandos ejecutados: `cargo test document`; `cargo test node`; `cargo test navigation`; `cargo test xml_path`; `cargo test core`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 22 tests unitarios del core.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/005-writer-serializer.md`.
### Tarea 005 - Writer Serializer
[x] Tarea actual: `docs/tasks/005-writer-serializer.md`.
[x] Estado exacto: completada; `src/writer/` serializa `Document` en modo compact y pretty con configuracion de declaracion XML, encoding e indentacion.
[x] Archivos tocados: `src/writer/mod.rs`, `tests/golden/writer_simple.xml`, `tests/golden/writer_namespaces.xml`, `tests/golden/writer_pretty.xml`, `docs/tasks/005-writer-serializer.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: los elementos vacios se serializan como self-closing tags (`<Tag/>`); la declaracion XML queda desactivada por defecto y usa `UTF-8`; namespaces y atributos se escriben en el orden estructural del documento; el writer solo depende de `core`.
[x] Comandos ejecutados: `cargo test writer`; `cargo test golden`; `cargo test escaping`; `cargo test namespaces`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 31 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/006-builder-api.md`.
### Tarea 006 - Builder API
[x] Tarea actual: `docs/tasks/006-builder-api.md`.
[x] Estado exacto: completada; `src/builder/` expone `DocumentBuilder`, `ElementBuilder`, `FragmentBuilder`, `XmlNode` e `IntoXmlFragment`.
[x] Archivos tocados: `src/builder/mod.rs`, `docs/tasks/006-builder-api.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: el builder compone primero fragmentos propios y materializa `Document` al final usando APIs publicas del core; `Option<T>`, `Vec<T>`, `XmlResult<T>`, strings, elementos y fragmentos implementan conversion hacia fragmentos; los componentes se modelan como funciones Rust normales que retornan builders.
[x] Comandos ejecutados: `cargo test builder`; `cargo test document_builder`; `cargo test fragment_builder`; `cargo test namespaces`; `cargo test collections`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 41 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/017-leptos-style-component-model.md`.
### Division de tarea 017 - Component Model
[x] Tarea actual: dividir `docs/tasks/017-leptos-style-component-model.md`.
[x] Estado exacto: `017` queda como tarea paraguas y se crean subtareas `017a` a `017f`.
[x] Archivos tocados: `docs/tasks/README.md`, `docs/tasks/017-leptos-style-component-model.md`, `docs/tasks/017a-component-contracts.md`, `docs/tasks/017b-typed-props-components.md`, `docs/tasks/017c-children-composition.md`, `docs/tasks/017d-conditional-and-lists.md`, `docs/tasks/017e-component-writer-integration.md`, `docs/tasks/017f-macro-readiness-notes.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: no crear crate adicional para componentes; mantener todo en `src/component/` dentro de `xdoc`; reservar `xdoc-macros` solo para una proc-macro futura de `xml!`.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/017a-component-contracts.md`.
### Tarea 017a - Component Contracts
[x] Tarea actual: `docs/tasks/017a-component-contracts.md`.
[x] Estado exacto: completada; `src/component/` expone `IntoXml`, `IntoXmlFragment`, `Fragment`, `Children`, `FragmentNode`, `document()` y `children()`.
[x] Archivos tocados: `src/component/mod.rs`, `docs/tasks/README.md`, `docs/tasks/017-leptos-style-component-model.md`, `docs/tasks/017a-component-contracts.md`, `docs/tasks/017b-typed-props-components.md`, `docs/tasks/017c-children-composition.md`, `docs/tasks/017d-conditional-and-lists.md`, `docs/tasks/017e-component-writer-integration.md`, `docs/tasks/017f-macro-readiness-notes.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: componentes son funciones Rust normales; `Fragment` y `Children` son aliases publicos del fragment builder; el backend sigue siendo `src/builder/`; no se crea crate adicional ni runtime reactivo.
[x] Comandos ejecutados: `cargo test component_contracts`; `cargo test into_xml`; `cargo test component`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 46 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/017b-typed-props-components.md`.
### Tarea 017b - Typed Props Components
[x] Tarea actual: `docs/tasks/017b-typed-props-components.md`.
[x] Estado exacto: completada; hay convencion y tests para componentes que reciben props como structs Rust normales.
[x] Archivos tocados: `src/component/mod.rs`, `docs/tasks/017b-typed-props-components.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: no agregar un trait especial de props todavia; las props tipadas son structs de usuario y los componentes son funciones Rust que retornan `XmlResult<ElementBuilder>` o cualquier `IntoXml`.
[x] Comandos ejecutados: `cargo test component_props`; `cargo test into_xml`; `cargo test component`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 50 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/017c-children-composition.md`.
### Tarea 017c - Children Composition
[x] Tarea actual: `docs/tasks/017c-children-composition.md`.
[x] Estado exacto: completada; componentes pueden recibir `Children`, envolverlos, retornar fragments con multiples nodos y componerse desde Rust normal.
[x] Archivos tocados: `src/component/mod.rs`, `docs/tasks/017c-children-composition.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `Children` sigue siendo un fragment explicito; los componentes de un solo elemento se convierten con `IntoXml::into_xml()` antes de agregarse como child; no se agrega macro ni runtime reactivo.
[x] Comandos ejecutados: `cargo test children`; `cargo test component`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 53 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/017d-conditional-and-lists.md`.
### Tarea 017d - Conditional And Lists
[x] Tarea actual: `docs/tasks/017d-conditional-and-lists.md`.
[x] Estado exacto: completada; componentes soportan `Option<T>`, `Vec<T>` e iteradores como contenido declarativo sin runtime reactivo.
[x] Archivos tocados: `src/component/mod.rs`, `docs/tasks/017d-conditional-and-lists.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: reutilizar conversiones de `builder::IntoXmlFragment`; los condicionales y listas se expresan con Rust normal y se validan por serializacion deterministica.
[x] Comandos ejecutados: `cargo test component_collections`; `cargo test collections`; `cargo test component`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 57 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/017e-component-writer-integration.md`.
### Tarea 017e - Component Writer Integration
[x] Tarea actual: `docs/tasks/017e-component-writer-integration.md`.
[x] Estado exacto: completada; hay tests `component_writer_*` para salida compacta, pretty y deterministica de componentes.
[x] Archivos tocados: `src/component/mod.rs`, `docs/tasks/017e-component-writer-integration.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: la integracion se prueba desde `component`; `src/writer/` sigue dependiendo solo de `core` y no conoce `component`.
[x] Comandos ejecutados: `cargo test component_writer`; `cargo test component`; `cargo test writer`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 62 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/017f-macro-readiness-notes.md`.
## 2026-06-11
### Tarea 017f - Macro Readiness Notes
[x] Tarea actual: `docs/tasks/017f-macro-readiness-notes.md`.
[x] Estado exacto: completada como tarea documental; no se implemento macro y no se creo crate adicional.
[x] Archivos tocados: `docs/tasks/017f-macro-readiness-notes.md`, `docs/tasks/017-leptos-style-component-model.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `xml!` queda definido conceptualmente como proc-macro ergonomica sobre `builder` y `component`; `builder` sigue siendo la capa generada por la macro; `component` sigue usable sin macro; `xdoc-macros` queda justificado para el MVP de `xml!` por requerir parser de tokens, AST, generacion de codigo Rust y diagnosticos de compilacion.
[x] Comandos ejecutados: `rg -n "macro|xml!|component|builder|xdoc-macros" docs/tasks/017* docs/context.md`; `cargo test component`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 62 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/008-macro-xml.md`.
### Ajuste de enfoque para 008 - Macro XML
[x] Tarea actual: ajustar documentacion de `docs/tasks/008-macro-xml.md`.
[x] Estado exacto: se corrigio la ruta de implementacion para que `008` arranque desde una proc-macro `xdoc-macros`, no desde un fallback de `macro_rules!`.
[x] Archivos tocados: `docs/tasks/017f-macro-readiness-notes.md`, `docs/tasks/008-macro-xml.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: el plan ya aporta suficiente base para `xml!` completo del MVP; quedan abiertas decisiones de diseno sobre tipo de retorno, fragments, componentes, namespaces, dependencias de proc-macro y tests de compilacion.
[x] Comandos ejecutados: `rg -n "macro_rules|fallback|futura si|proc-macro|xdoc-macros|Open Design Decisions|Design Baseline" docs/tasks/017f-macro-readiness-notes.md docs/tasks/008-macro-xml.md docs/worklogs.md`; `git diff -- docs/tasks/017f-macro-readiness-notes.md docs/tasks/008-macro-xml.md docs/worklogs.md`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 62 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: cerrar las decisiones de diseno antes de implementar `crates/xdoc-macros`.
### Division de tarea 008 - Macro XML
[x] Tarea actual: dividir `docs/tasks/008-macro-xml.md`.
[x] Estado exacto: `008` queda como tarea paraguas y se crean subtareas `008a` a `008h`.
[x] Archivos tocados: `docs/tasks/README.md`, `docs/tasks/008-macro-xml.md`, `docs/tasks/008a-macro-design-decisions.md`, `docs/tasks/008b-proc-macro-crate-scaffold.md`, `docs/tasks/008c-macro-output-bridge.md`, `docs/tasks/008d-macro-parser-and-ast.md`, `docs/tasks/008e-macro-basic-builder-codegen.md`, `docs/tasks/008f-macro-namespaces-and-comments.md`, `docs/tasks/008g-macro-components-props-children.md`, `docs/tasks/008h-macro-compile-tests-and-docs.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: partir la macro en decisiones de diseno, scaffold de proc-macro, contrato de salida, parser/AST, codegen basico, namespaces/comments, componentes y pruebas de compilacion.
[x] Comandos ejecutados: `rg` de secciones obligatorias en `docs/tasks/008*.md`; `rg` de enlaces `008a` a `008h`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 62 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/008a-macro-design-decisions.md`.
### Tarea 008a - Macro Design Decisions
[x] Tarea actual: `docs/tasks/008a-macro-design-decisions.md`.
[x] Estado exacto: completada como tarea documental; no se implemento macro ni se creo `crates/xdoc-macros`.
[x] Archivos tocados: `docs/tasks/008a-macro-design-decisions.md`, `docs/tasks/008-macro-xml.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `xml!` retorna `XmlResult<XmlTemplate>`; `XmlTemplate` vive en `src/macros/` y puede convertirse a `Document` o fragment; el codigo generado usa rutas `::xdoc`; componentes usan sintaxis explicita `<{ComponentPath}>` para no chocar con XML en mayuscula; props se mapean a `ComponentProps`; namespaces usan `xmlns` literal con scopes; `xdoc-macros` usa `proc_macro`, `proc-macro2` y `quote`, no `syn` en el MVP; compile tests usan `trybuild`.
[x] Comandos ejecutados: `rg -n "Decision|xml!|fragment|component|namespace|proc-macro|compile" docs/tasks/008a-macro-design-decisions.md docs/worklogs.md`; `cargo test component`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test component` ejecuto 23 tests filtrados; `cargo test` ejecuto 62 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/008b-proc-macro-crate-scaffold.md`.
### Tarea 008b - Proc Macro Crate Scaffold
[x] Tarea actual: `docs/tasks/008b-proc-macro-crate-scaffold.md`.
[x] Estado exacto: completada; existe `crates/xdoc-macros` como proc-macro crate y `xdoc` reexporta `xml!` desde `src/macros/`.
[x] Archivos tocados: `Cargo.toml`, `crates/xdoc-macros/Cargo.toml`, `crates/xdoc-macros/src/lib.rs`, `src/lib.rs`, `src/macros/mod.rs`, `docs/tasks/008b-proc-macro-crate-scaffold.md`, `docs/tasks/008-macro-xml.md`, `docs/worklogs.md`; `Cargo.lock` fue generado por Cargo pero sigue ignorado por `.gitignore`.
[x] Decisiones tomadas: `xdoc-macros` depende solo de `proc-macro2` y `quote`, no de `xdoc`; `src/lib.rs` agrega `extern crate self as xdoc` para que las rutas generadas `::xdoc::...` funcionen en tests internos; el placeholder de `xml!` devuelve `XmlError::InvalidOperation` y no implementa aun parsing/codegen del MVP.
[x] Comandos ejecutados: `cargo metadata --format-version 1 --no-deps`; `cargo metadata --format-version 1`; `cargo fmt --all -- --check`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `cargo test macros`; `test -d crates/xdoc-macros && test "$(find crates -mindepth 1 -maxdepth 1 -type d | wc -l)" -eq 1`.
[x] Verificacion: todos los comandos finales terminaron con codigo `0`; `cargo metadata --format-version 1` muestra `xdoc` y `xdoc-macros`; `cargo test macros` ejecuto 1 test filtrado; `cargo test` ejecuto 63 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/008c-macro-output-bridge.md`.
### Tarea 008c - Macro Output Bridge
[x] Tarea actual: `docs/tasks/008c-macro-output-bridge.md`.
[x] Estado exacto: completada; `src/macros/` expone `XmlTemplate` como salida runtime de `xml!`.
[x] Archivos tocados: `src/builder/mod.rs`, `src/macros/mod.rs`, `docs/tasks/008c-macro-output-bridge.md`, `docs/tasks/008-macro-xml.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `XmlTemplate` envuelve `FragmentBuilder`, implementa `IntoXmlFragment`, expone `from_fragment`, `into_fragment` e `into_document`; `into_document` usa `DocumentBuilder` y exige exactamente un root element; `FragmentBuilder::into_single_element()` queda como API acotada para consumir fragments que representan documentos.
[x] Comandos ejecutados: `cargo test macro_output`; `cargo test into_xml`; `cargo test component`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test macro_output` ejecuto 4 tests filtrados; `cargo test` ejecuto 67 tests unitarios/doc-tests en total.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/008d-macro-parser-and-ast.md`.
### Tarea 008d - Macro Parser And AST
[x] Tarea actual: `docs/tasks/008d-macro-parser-and-ast.md`.
[x] Estado exacto: completada; `xdoc-macros` tiene AST y parser internos para el subset MVP de `xml!`, pero la macro publica aun mantiene el placeholder hasta la tarea de codegen.
[x] Archivos tocados: `.gitignore`, `crates/xdoc-macros/src/ast.rs`, `crates/xdoc-macros/src/parser.rs`, `crates/xdoc-macros/src/lib.rs`, `docs/tasks/008d-macro-parser-and-ast.md`, `docs/tasks/008-macro-xml.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: el parser se mantiene interno a `xdoc-macros`; las expresiones Rust se capturan como `TokenStream` sin parsear con `syn`; comments se aceptan en el AST MVP; nombres prefijados se modelan como `XmlName { prefix, local }`; componentes se representan aparte con path Rust entre llaves.
[x] Comandos ejecutados: `cargo test --manifest-path crates/xdoc-macros/Cargo.toml macro_parser`; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml macro_ast`; `cargo fmt --all -- --check`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml`.
[x] Verificacion: todos los comandos finales terminaron con codigo `0`; `macro_parser` ejecuto 10 tests filtrados; `macro_ast` ejecuto 1 test filtrado; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml` ejecuto 11 tests unitarios/doc-tests; `cargo test` ejecuto 67 tests unitarios/doc-tests en la crate principal.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/008e-macro-basic-builder-codegen.md`.
### Tarea 008e - Macro Basic Builder Codegen
[x] Tarea actual: `docs/tasks/008e-macro-basic-builder-codegen.md`.
[x] Estado exacto: completada; `xml!` genera codigo builder para elementos XML basicos, texto, atributos e interpolaciones, y devuelve `XmlResult<XmlTemplate>`.
[x] Archivos tocados: `crates/xdoc-macros/src/codegen.rs`, `crates/xdoc-macros/src/lib.rs`, `crates/xdoc-macros/src/parser.rs`, `src/macros/mod.rs`, `docs/tasks/008e-macro-basic-builder-codegen.md`, `docs/tasks/008-macro-xml.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: el codegen produce closures que retornan `XmlResult` y construyen `XmlTemplate::from_fragment`; los elementos se generan mediante `::xdoc::builder::element`; atributos mediante `.attr`; children mediante `.child`; expressions se reinsertan como tokens Rust y deben implementar `IntoXmlFragment`; comments, namespaces y componentes devuelven error de compilacion hasta sus subtareas.
[x] Comandos ejecutados: `cargo test xml_macro_basic`; `cargo test macros`; `cargo test writer`; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test xml_macro_basic` ejecuto 5 tests filtrados; `cargo test macros` ejecuto 9 tests filtrados; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml` ejecuto 11 tests unitarios/doc-tests; `cargo test` ejecuto 71 tests unitarios/doc-tests en la crate principal.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/008f-macro-namespaces-and-comments.md`.
### Ejemplo ejecutable con xml!
[x] Tarea actual: crear un ejemplo minimo que genere un archivo XML usando el subset actual de `xml!`.
[x] Estado exacto: agregado `examples/generate_xml.rs`, ejecutable con `cargo run --example generate_xml -- target/xdoc-example.xml`.
[x] Archivos tocados: `examples/generate_xml.rs`, `docs/worklogs.md`.
[x] Decisiones tomadas: el ejemplo usa solo elementos, atributos literales, atributos dinamicos e interpolacion de texto porque namespaces, comentarios y componentes pertenecen a `008f` y `008g`; el archivo generado queda bajo `target/` por defecto para no ensuciar el arbol versionado.
[x] Comandos ejecutados: `cargo run --example generate_xml -- target/xdoc-example.xml`; `sed -n '1,160p' target/xdoc-example.xml`; `cargo fmt --all -- --check`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml`.
[x] Verificacion: el ejemplo genero `target/xdoc-example.xml`; la primera revision de formato pidio un ajuste mecanico y luego `cargo fmt --all -- --check`, `cargo check`, `cargo test` y `cargo test --manifest-path crates/xdoc-macros/Cargo.toml` terminaron con codigo `0`.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/008f-macro-namespaces-and-comments.md`.
### Tarea 008f - Macro Namespaces And Comments
[x] Tarea actual: `docs/tasks/008f-macro-namespaces-and-comments.md`.
[x] Estado exacto: completada; `xml!` genera builder code para namespaces default, namespaces con prefijo, elementos prefijados, atributos prefijados y comentarios validos.
[x] Archivos tocados: `crates/xdoc-macros/src/codegen.rs`, `src/macros/mod.rs`, `docs/tasks/008f-macro-namespaces-and-comments.md`, `docs/tasks/008-macro-xml.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: las declaraciones `xmlns` se consumen como scope lexico de namespace y no se serializan como atributos normales; los nombres prefijados se resuelven a URI y se generan con `ElementBuilder::qualified`/`qualified_attr`; los elementos sin prefijo usan `ElementBuilder::namespaced` cuando hay namespace default en scope; la macro MVP prueba comentarios validos y deja el rechazo de comentarios invalidos al writer cuando se construyen desde core/builder.
[x] Comandos ejecutados: `cargo test xml_macro_namespaces`; `cargo test xml_macro_comments`; `cargo test namespaces`; `cargo test writer`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 75 tests unitarios/doc-tests en la crate principal y `cargo test --manifest-path crates/xdoc-macros/Cargo.toml` ejecuto 11 tests unitarios/doc-tests.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/008g-macro-components-props-children.md`.
### Tarea 008g - Macro Components Props Children
[x] Tarea actual: `docs/tasks/008g-macro-components-props-children.md`.
[x] Estado exacto: completada; `xml!` puede invocar componentes Rust con sintaxis `<{Component}>`, props tipadas, children explicitos y componentes que retornan elemento o fragment.
[x] Archivos tocados: `crates/xdoc-macros/src/codegen.rs`, `src/macros/mod.rs`, `docs/tasks/008g-macro-components-props-children.md`, `docs/tasks/008-macro-xml.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: el codegen deriva el tipo de props reemplazando el ultimo segmento del path por `ComponentProps`; los props son atributos simples sin namespace y se generan como campos Rust; componentes self-closing reciben solo props; componentes con body reciben `Children` construido desde un `FragmentBuilder`; la macro no agrega runtime ni registry de componentes.
[x] Comandos ejecutados: `cargo test xml_macro_components`; `cargo test component_props`; `cargo test children`; `cargo test component`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 79 tests unitarios/doc-tests en la crate principal y `cargo test --manifest-path crates/xdoc-macros/Cargo.toml` ejecuto 11 tests unitarios/doc-tests.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/008h-macro-compile-tests-and-docs.md`.
### Tarea 008h - Macro Compile Tests And Docs
[x] Tarea actual: `docs/tasks/008h-macro-compile-tests-and-docs.md`.
[x] Estado exacto: completada; `008 - Macro XML` queda cerrada para el MVP actual.
[x] Archivos tocados: `Cargo.toml`, `Cargo.lock`, `crates/xdoc-macros/src/lib.rs`, `src/macros/mod.rs`, `tests/compile.rs`, `tests/compile/pass/xml_macro_pass.rs`, `tests/compile/fail/*.rs`, `tests/compile/fail/*.stderr`, `docs/tasks/008h-macro-compile-tests-and-docs.md`, `docs/tasks/008-macro-xml.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: se usa `trybuild` como dev-dependency para compile-pass/compile-fail; los casos validos cubren elementos, children, interpolacion, namespaces, comments y componentes; los casos invalidos cubren tags mal balanceados, atributo sin `=`, namespace no declarado e interpolacion Rust invalida; se quito el `;` de `compile_error!` generado para evitar diagnosticos secundarios ruidosos.
[x] Comandos ejecutados: `cargo test compile_pass`; `cargo test compile_fail`; `TRYBUILD=overwrite cargo test compile_fail`; `cargo test xml_macro`; `cargo fmt --all -- --check`; `cargo check`; `test -d crates/xdoc-macros && test "$(find crates -mindepth 1 -maxdepth 1 -type d | wc -l)" -eq 1`; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 79 tests unitarios/doc-tests en `xdoc` y 2 tests de integracion `trybuild`; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml` ejecuto 11 tests unitarios/doc-tests.
[x] Siguiente paso recomendado: continuar con `docs/tasks/007-parser.md` o con la siguiente tarea priorizada del backlog.
### Tarea 007 - Parser
[x] Tarea actual: `docs/tasks/007-parser.md`.
[x] Estado exacto: completada; `src/parser/` expone `ParserConfig`, `parse_str`, `parse_str_with_config`, `parse_reader` y `parse_reader_with_config`.
[x] Archivos tocados: `Cargo.toml`, `src/parser/mod.rs`, `docs/tasks/007-parser.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: se usa `quick-xml` como parser de eventos tecnico; `ParserConfig` tiene limites locales seguros de tamano, texto, profundidad y nodos porque `013 - Security Policies` sigue pendiente; se rechaza cualquier `DOCTYPE` y entidades generales no predefinidas por defecto; namespaces se resuelven a `QName` estructural y las declaraciones se preservan en el elemento.
[x] Comandos ejecutados: `cargo add quick-xml`; `cargo check`; `cargo test parser`; `cargo test parse_str`; `cargo test namespaces`; `cargo test security`; `cargo test roundtrip`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 88 tests unitarios/doc-tests en `xdoc` y 2 tests de integracion `trybuild`.
[x] Siguiente paso recomendado: ejecutar `docs/tasks/013-security-policies.md` para unificar limites compartidos, o continuar con `009 - Query Engine` si se prioriza el orden funcional.
### Tarea 013 - Security Policies
[x] Tarea actual: `docs/tasks/013-security-policies.md`.
[x] Estado exacto: completada; `src/security/` define limites y politicas compartidas y `ParserConfig` ya consume `ParserSecurityConfig`.
[x] Archivos tocados: `src/security/mod.rs`, `src/parser/mod.rs`, `docs/tasks/013-security-policies.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `SecurityLimits` centraliza limites de documento, texto, profundidad, nodos, query steps y expansion de transform; `EntityPolicy` bloquea entidades externas, red y filesystem por defecto; `QuerySecurityConfig` y `TransformSecurityConfig` exponen checks aun antes de implementar esos modulos; los errores usan `XmlError` estructurado.
[x] Comandos ejecutados: `cargo test security`; `cargo test defaults`; `cargo test limits`; `cargo test entity_policy`; `cargo test parser`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 94 tests unitarios/doc-tests en `xdoc` y 2 tests de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `009 - Query Engine`.
[x] Actualizacion posterior: se revalidaron los filtros de `013` y se sincronizo el indice global junto con la dependencia de `013` en `012 - Signature Base`.
### Tarea 009 - Query Engine
[x] Tarea actual: `docs/tasks/009-query-engine.md`.
[x] Estado exacto: completada; `src/query/` expone `Query`, `QueryResult`, `QueryValue`, `NamespaceContext` y `DocumentQueryExt`.
[x] Archivos tocados: `src/query/mod.rs`, `docs/tasks/009-query-engine.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: el MVP soporta paths absolutos, descendientes `//`, atributos, `text()`, predicados simples por atributo y aliases de namespace; los resultados pueden ser nodos, atributos o texto; la evaluacion consume `QuerySecurityConfig` para limitar pasos; no se implementa XQuery ni funciones fuera de `text()`.
[x] Comandos ejecutados: `cargo check`; `cargo test query`; `cargo test lexer`; `cargo test parser`; `cargo test evaluator`; `cargo test namespaces`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 107 tests unitarios/doc-tests en `xdoc` y 2 tests de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `010 - Transform Designer` o `011 - Schema Contract`, ambos dependen de query.
### Tarea 010 - Transform Designer
[x] Tarea actual: `docs/tasks/010-transform-designer.md`.
[x] Estado exacto: completada; `src/transform/` expone `BindingContext`, `Transform`, `Template` y `ElementTemplate`.
[x] Archivos tocados: `src/transform/mod.rs`, `docs/tasks/010-transform-designer.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: el transform MVP es programatico y se apoya en builder/query/component; `repeat` evalua su template contra un documento de iteracion cuyo root es el nodo seleccionado; `Template::from_xml_str` usa el parser para cargar templates externos basicos; los componentes pueden actuar como templates mediante `Template::from_fragment`.
[x] Comandos ejecutados: `cargo check`; `cargo test transform`; `cargo test template`; `cargo test select`; `cargo test repeat`; `cargo test conditionals`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 115 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `011 - Schema Contract`.
### Ejemplo xml! con componentes
[x] Tarea actual: extension puntual del ejemplo `examples/generate_xml.rs`.
[x] Estado exacto: completada; el ejemplo usa `xml!` con componentes Rust, props tipadas y children explicitos.
[x] Archivos tocados: `examples/generate_xml.rs`, `docs/worklogs.md`.
[x] Decisiones tomadas: se mantuvo el ejemplo en el motor generico; los componentes usan la convencion `<{Component}>`, structs `ComponentProps` y `Children` del modulo `component`.
[x] Comandos ejecutados: `cargo run --example generate_xml -- target/xdoc-example.xml`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; el ejemplo compilo y genero `target/xdoc-example.xml`; `cargo test` ejecuto 115 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `011 - Schema Contract`.
### Ejemplo xml! con children generados por xml!
[x] Tarea actual: ajuste puntual del ejemplo `examples/generate_xml.rs`.
[x] Estado exacto: completada; los children de `Section` y `LineItem` se construyen como fragments con `xml!` y se interpolan dentro de componentes.
[x] Archivos tocados: `examples/generate_xml.rs`, `docs/worklogs.md`.
[x] Decisiones tomadas: se mantuvo la convencion de componentes `<{Component}>`; `XmlTemplate` se usa como fragment interpolable para demostrar composicion de children generados por la macro.
[x] Comandos ejecutados: `cargo run --example generate_xml -- target/xdoc-example.xml`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; el ejemplo compilo y genero `target/xdoc-example.xml`; `cargo test` ejecuto 115 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `011 - Schema Contract`.
### Ejemplo componentes implementados con xml!
[x] Tarea actual: ajuste puntual del ejemplo `examples/generate_xml.rs`.
[x] Estado exacto: completada; `DocumentHeader`, `Section` y `LineItem` construyen su salida interna con `xml!`.
[x] Archivos tocados: `examples/generate_xml.rs`, `docs/worklogs.md`.
[x] Decisiones tomadas: los componentes mantienen firma `XmlResult<ElementBuilder>` y convierten el `XmlTemplate` de `xml!` con `into_fragment().into_single_element()`.
[x] Comandos ejecutados: `cargo run --example generate_xml -- target/xdoc-example.xml`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; el ejemplo compilo y genero `target/xdoc-example.xml`; `cargo test` ejecuto 115 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `011 - Schema Contract`.
### Ejemplo xml! iterando vectores
[x] Tarea actual: ajuste puntual del ejemplo `examples/generate_xml.rs`.
[x] Estado exacto: completada; el ejemplo define un `Vec<LineData>` y lo transforma en children XML con `iter().map(...)` y `xml!`.
[x] Archivos tocados: `examples/generate_xml.rs`, `docs/worklogs.md`.
[x] Decisiones tomadas: la iteracion produce `Vec<XmlTemplate>` mediante `collect::<XmlResult<Vec<_>>>()?`, aprovechando que `Vec<T>` implementa `IntoXmlFragment`.
[x] Comandos ejecutados: `cargo run --example generate_xml -- target/xdoc-example.xml`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; el ejemplo compilo y genero `target/xdoc-example.xml`; `cargo test` ejecuto 115 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `011 - Schema Contract`.
### Ejemplo xml! con namespaces
[x] Tarea actual: ajuste puntual del ejemplo `examples/generate_xml.rs`.
[x] Estado exacto: completada; el ejemplo usa namespace default, elementos con prefijo `doc` y atributos con prefijo `meta`.
[x] Archivos tocados: `examples/generate_xml.rs`, `docs/worklogs.md`.
[x] Decisiones tomadas: cada componente que usa nombres prefijados declara el prefijo en su propio `xml!`, porque la macro valida namespaces por invocacion.
[x] Comandos ejecutados: `cargo run --example generate_xml -- target/xdoc-example.xml`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; el ejemplo compilo y genero `target/xdoc-example.xml`; `cargo test` ejecuto 115 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `011 - Schema Contract`.
### Tarea 011 - Schema Contract
[x] Tarea actual: `docs/tasks/011-schema-contract.md`.
[x] Estado exacto: completada; `src/schema/` expone contratos XML propios y reportes estructurados de validacion.
[x] Archivos tocados: `src/schema/mod.rs`, `docs/tasks/011-schema-contract.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: el contrato compila paths con `src/query/`; `text_type` y `enum_value` aceptan paths a texto/atributos o a elementos con texto directo; las reglas custom devuelven issues; se agrego `XsdContractAdapter` como punto futuro sin implementar XSD completo.
[x] Comandos ejecutados: `cargo test schema`; `cargo test required`; `cargo test cardinality`; `cargo test types`; `cargo test report`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 123 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `012 - Signature Base`.
### Backlog de hardening previo a firma
[x] Tarea actual: crear tareas a partir de hallazgos tecnicos antes de iniciar `012 - Signature Base`.
[x] Estado exacto: completada la planificacion; se agregaron tareas `018*` para hardening y `012a` para decisiones de firma XML/XAdES.
[x] Archivos tocados: `docs/tasks/README.md`, `docs/tasks/012-signature-base.md`, `docs/tasks/016-quality-gate.md`, `docs/tasks/012a-signature-design-decisions.md`, `docs/tasks/018-hardening-before-signature.md`, `docs/tasks/018a-writer-text-preservation.md`, `docs/tasks/018b-parser-document-boundaries.md`, `docs/tasks/018c-parser-entity-handling.md`, `docs/tasks/018d-namespace-compliance-hardening.md`, `docs/tasks/018e-transform-security-limits.md`, `docs/tasks/018f-macro-crate-rename-compatibility.md`, `docs/tasks/018g-ci-workflow.md`, `docs/tasks/018h-project-licensing-and-lock-policy.md`, `docs/tasks/018i-public-module-status-docs.md`, `docs/tasks/018j-cli-minimum-utility.md`, `docs/tasks/018k-advanced-testing-fixtures.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `012` queda dependiente de hardening critico y `012a`; los hallazgos H-001 a H-013 se traducen a tareas rastreables; `hallazgos_xml_builder.md` queda como referencia local sin agregarse al commit por estar sin trackear.
[x] Comandos ejecutados: `rg -n "018a|018b|018c|018d|018e|018f|018g|018h|018i|018j|018k|012a|Hardening Before Signature|Signature Design" docs/tasks/README.md docs/tasks/012-signature-base.md docs/tasks/016-quality-gate.md docs/worklogs.md`; `ls docs/tasks/018* docs/tasks/012a-signature-design-decisions.md`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 123 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: comenzar por `018a - Writer Text Preservation`.
### Tarea 018a - Writer Text Preservation
[x] Tarea actual: `docs/tasks/018a-writer-text-preservation.md`.
[x] Estado exacto: completada; pretty writer preserva texto, CDATA y mixed content sin whitespace artificial.
[x] Archivos tocados: `src/writer/mod.rs`, `src/component/mod.rs`, `tests/golden/writer_pretty.xml`, `tests/golden/writer_pretty_mixed.xml`, `tests/golden/writer_pretty_cdata.xml`, `tests/golden/writer_pretty_structural_misc.xml`, `docs/tasks/018a-writer-text-preservation.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: pretty serialization solo indenta contenido estructural sin texto/CDATA; comentarios y processing instructions se tratan como contenido estructural cuando no hay texto significativo; no se implementa canonicalizacion en esta tarea.
[x] Comandos ejecutados: `cargo test writer`; `cargo test golden`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 126 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `018b - Parser Document Boundaries`.
### Tarea 018b - Parser Document Boundaries
[x] Tarea actual: `docs/tasks/018b-parser-document-boundaries.md`.
[x] Estado exacto: completada; parser acepta whitespace/misc fuera del root y rechaza documentos sin root o texto real fuera del root.
[x] Archivos tocados: `src/parser/mod.rs`, `docs/tasks/018b-parser-document-boundaries.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: comments y processing instructions fuera del root se aceptan pero no se materializan en el arbol porque `Document` representa un unico root; CDATA fuera del root se rechaza; `finish()` exige un elemento raiz.
[x] Comandos ejecutados: `cargo test parser`; `cargo test whitespace`; `cargo test empty`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 130 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `018c - Parser Entity Handling`.
### Tarea 018c - Parser Entity Handling
[x] Tarea actual: `docs/tasks/018c-parser-entity-handling.md`.
[x] Estado exacto: completada; parser rechaza entidades generales no predefinidas sin panic incluso con politica permisiva.
[x] Archivos tocados: `src/parser/mod.rs`, `docs/tasks/018c-parser-entity-handling.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: las entidades XML predefinidas se resuelven; entidades no predefinidas se bloquean por la politica default; si se habilitan entidades externas, parser devuelve error explicito porque la resolucion externa aun no esta implementada.
[x] Comandos ejecutados: `cargo test entity`; `cargo test security`; `cargo test parser`; `rg -n "unwrap_err" src/parser`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`, salvo `rg -n "unwrap_err" src/parser` que termino con codigo `1` porque no encontro coincidencias; `cargo test` ejecuto 133 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `018d - Namespace Compliance Hardening`.
### Tarea 018d - Namespace Compliance Hardening
[x] Tarea actual: `docs/tasks/018d-namespace-compliance-hardening.md`.
[x] Estado exacto: completada; core/parser/query endurecen reglas basicas de namespaces reservados y expanded names.
[x] Archivos tocados: `src/core/names.rs`, `src/core/namespace.rs`, `src/core/mod.rs`, `src/parser/mod.rs`, `src/query/mod.rs`, `README.md`, `docs/tasks/018d-namespace-compliance-hardening.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `xml` queda implicitamente disponible en parser y solo puede usar `http://www.w3.org/XML/1998/namespace`; `xmlns` no puede usarse como prefijo normal; atributos duplicados se detectan por `(namespace_uri, local)`; default namespace no aplica a atributos ni a query sin alias; se mantiene validacion ASCII conservadora de nombres XML.
[x] Comandos ejecutados: `cargo test namespace`; `cargo test query`; `cargo test parser`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 141 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `018e - Transform Security Limits`.
### Tarea 018e - Transform Security Limits
[x] Tarea actual: `docs/tasks/018e-transform-security-limits.md`.
[x] Estado exacto: completada; `Transform::apply` aplica defaults seguros y `apply_with_config`/`apply_document_with_config` aceptan `TransformConfig` con `TransformSecurityConfig`.
[x] Archivos tocados: `src/transform/mod.rs`, `src/builder/mod.rs`, `docs/tasks/018e-transform-security-limits.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: el modelo de templates no cambia; se agrego un contador interno de expansion que cuenta nodos XML recursivamente y valida cada fragmento generado por `repeat`, ademas de validar la salida final para fragments grandes; `ElementBuilder::child_nodes` expone lectura de hijos para poder contar sin consumir builders.
[x] Comandos ejecutados: `cargo test transform`; `cargo test security`; `cargo test expansion`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 143 pruebas unitarias/doc-tests de `xdoc` y 2 pruebas de integracion `trybuild`.
[x] Siguiente paso recomendado: continuar con `018f - Macro Crate Rename Compatibility`.
### Tarea 018f - Macro Crate Rename Compatibility
[x] Tarea actual: `docs/tasks/018f-macro-crate-rename-compatibility.md`.
[x] Estado exacto: completada; `xdoc-macros` resuelve el nombre real de la dependencia `xdoc` en el crate consumidor y el macro funciona con dependencias renombradas.
[x] Archivos tocados: `crates/xdoc-macros/Cargo.toml`, `crates/xdoc-macros/src/lib.rs`, `crates/xdoc-macros/src/codegen.rs`, `tests/compile.rs`, `docs/tasks/008a-macro-design-decisions.md`, `docs/tasks/018f-macro-crate-rename-compatibility.md`, `docs/worklogs.md`; `Cargo.lock` locales fueron generados por Cargo pero quedan ignorados y no se incluyen.
[x] Decisiones tomadas: usar `proc_macro_crate` como dependencia tecnica del proc-macro; mantener `extern crate self as xdoc` para uso interno; agregar un fixture cargo temporal bajo `target/compile-renamed-xdoc` que declara `xml_runtime = { package = "xdoc", path = ... }` y ejecuta `xml!`.
[x] Comandos ejecutados: `cargo check`; `cargo test --test compile`; `cargo fmt --all`; `cargo test xml_macro`; `cargo test --test compile`; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test xml_macro` ejecuto 13 tests filtrados; `cargo test --test compile` ejecuto 3 tests incluyendo dependencia renombrada; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml` ejecuto 11 tests; `cargo test` ejecuto 143 pruebas unitarias/doc-tests de `xdoc` y 3 pruebas de integracion.
[x] Siguiente paso recomendado: continuar con `018g - CI Workflow`.
### Tarea 018g - CI Workflow
[x] Tarea actual: `docs/tasks/018g-ci-workflow.md`.
[x] Estado exacto: completada; se agrego GitHub Actions para validar formato, check, clippy y tests de la crate principal y de `xdoc-macros`.
[x] Archivos tocados: `.github/workflows/ci.yml`, `examples/generate_xml.rs`, `src/component/mod.rs`, `src/security/mod.rs`, `src/transform/mod.rs`, `docs/tasks/018g-ci-workflow.md`, `docs/tasks/018-hardening-before-signature.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: clippy queda bloqueante con `-D warnings`; se corrigieron warnings pequenos para que el gate sea viable; el workflow no agrega servicios externos ni referencias a dominios.
[x] Comandos ejecutados: `cargo clippy --all-targets -- -D warnings`; `cargo clippy --manifest-path crates/xdoc-macros/Cargo.toml --all-targets -- -D warnings`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check --all-targets`; `cargo test`; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml`; `cargo check`.
[x] Verificacion: todos los comandos finales terminaron con codigo `0`; `cargo test` ejecuto 143 pruebas unitarias/doc-tests de `xdoc` y 3 pruebas de integracion; `cargo test --manifest-path crates/xdoc-macros/Cargo.toml` ejecuto 11 pruebas.
[x] Siguiente paso recomendado: continuar con `018h - Project Licensing And Lock Policy`.
### Tarea 018h - Project Licensing And Lock Policy
[x] Tarea actual: `docs/tasks/018h-project-licensing-and-lock-policy.md`.
[x] Estado exacto: completada; el repositorio tiene archivos fisicos para `MIT OR Apache-2.0` y politica explicita de lockfile.
[x] Archivos tocados: `LICENSE-MIT`, `LICENSE-APACHE`, `Cargo.lock`, `.gitignore`, `README.md`, `docs/tasks/018h-project-licensing-and-lock-policy.md`, `docs/tasks/018-hardening-before-signature.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: no se cambio la metadata `license = "MIT OR Apache-2.0"`; se versiona solo el `Cargo.lock` raiz porque el repo contiene el binario `xdoc` y el CI debe validar un grafo reproducible; locks anidados de crates auxiliares/fixtures siguen ignorados.
[x] Comandos ejecutados: `test -f LICENSE-MIT && test -f LICENSE-APACHE`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 143 pruebas unitarias/doc-tests de `xdoc` y 3 pruebas de integracion.
[x] Siguiente paso recomendado: continuar con `018i - Public Module Status Docs`.
### Tarea 018i - Public Module Status Docs
[x] Tarea actual: `docs/tasks/018i-public-module-status-docs.md`.
[x] Estado exacto: completada; README muestra estado por modulo y limites publicos del MVP.
[x] Archivos tocados: `README.md`, `docs/tasks/018i-public-module-status-docs.md`, `docs/tasks/018-hardening-before-signature.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `core` a `schema` se documentan como MVP implementado; `signature`, `testing` y `cli` quedan marcados como placeholders; XAdES BES/EPES se declara futuro y fuera del MVP actual.
[x] Comandos ejecutados: `rg -n "Estado|MVP|signature|testing|cli|XAdES" README.md`; `if rg -n "src/domains|xdoc-dian|xdoc-ubl" README.md src; then exit 1; else exit 0; fi`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: todos los comandos terminaron con codigo `0`; `cargo test` ejecuto 143 pruebas unitarias/doc-tests de `xdoc` y 3 pruebas de integracion.
[x] Siguiente paso recomendado: continuar con `018j - CLI Minimum Utility`.
### Tarea 018l - Crate Publication Name
[x] Tarea actual: `docs/tasks/018l-crate-publication-name.md`.
[x] Estado exacto: completada; el package publico queda como `xdoc-rs` y la crate importable sigue siendo `xdoc`.
[x] Archivos tocados: `Cargo.toml`, `Cargo.lock`, `README.md`, `crates/xdoc-macros/src/lib.rs`, `tests/compile.rs`, `docs/context.md`, `docs/instructions.md`, `docs/tasks/README.md`, `docs/tasks/018-hardening-before-signature.md`, `docs/tasks/018l-crate-publication-name.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: no se renombra el target `[lib]`; los usuarios pueden usar `xdoc = { package = "xdoc-rs", version = "0.1" }`; `xdoc-macros` busca `xdoc-rs` como package original con `proc_macro_crate`.
[x] Comandos ejecutados: `cargo check`; `cargo search xdoc-rs --limit 10`; `cargo search xdoc-macros --limit 10`; `cargo package --manifest-path crates/xdoc-macros/Cargo.toml --allow-dirty`; `cargo package --allow-dirty`; `cargo package --allow-dirty --no-verify`; `cargo test --test compile`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `cargo clippy --all-targets -- -D warnings`; `cargo clippy --manifest-path crates/xdoc-macros/Cargo.toml --all-targets -- -D warnings`.
[x] Verificacion: los comandos finales terminaron con codigo `0`; `cargo test --test compile` ejecuto 3 pruebas incluyendo alias externo `package = "xdoc-rs"`; `cargo test` ejecuto 143 pruebas unitarias/doc-tests de `xdoc` y 3 pruebas de integracion; clippy paso en ambas crates; `cargo package` de `xdoc-rs` aun falla hasta publicar primero `xdoc-macros` en crates.io.
[x] Siguiente paso recomendado: continuar con `018j - CLI Minimum Utility`.
### Tarea 018j - CLI Minimum Utility
[x] Tarea actual: `docs/tasks/018j-cli-minimum-utility.md`.
[x] Estado exacto: completada; el CLI vive en el crate separado `xdoc-cli` y expone el binario `xdoc` con comandos minimos.
[x] Archivos tocados: `Cargo.toml`, `Cargo.lock`, `.github/workflows/ci.yml`, `crates/xdoc-cli/Cargo.toml`, `crates/xdoc-cli/src/main.rs`, `tests/compile.rs`, `tests/fixtures/xml/simple.xml`, `tests/fixtures/xml/invalid.xml`, `README.md`, `docs/context.md`, `docs/instructions.md`, `docs/tasks/README.md`, `docs/tasks/018j-cli-minimum-utility.md`, `docs/tasks/018-hardening-before-signature.md`, `docs/worklogs.md`; se elimino el placeholder `src/bin/xdoc.rs`.
[x] Decisiones tomadas: se permite `xdoc-cli` como crate auxiliar fuera del motor; el motor `xdoc-rs` no depende del CLI; el binario conserva el nombre `xdoc`; el parsing de argumentos se mantiene manual para no agregar dependencias; `query` serializa nodos consultados usando solo API publica; los fixtures temporales de compile-test declaran `[workspace]` vacio para no heredar el workspace padre.
[x] Comandos ejecutados: `cargo search xdoc-cli --limit 10`; `cargo fmt --all`; `cargo check`; `cargo test -p xdoc-cli`; `cargo run -p xdoc-cli -- validate-wellformed tests/fixtures/xml/simple.xml`; `cargo run -p xdoc-cli -- compact tests/fixtures/xml/simple.xml`; `cargo run -p xdoc-cli -- format tests/fixtures/xml/simple.xml`; `cargo run -p xdoc-cli -- query tests/fixtures/xml/simple.xml "/Root/Item[@code='B']"`; `cargo run -p xdoc-cli -- validate-wellformed tests/fixtures/xml/invalid.xml`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `cargo clippy --workspace --all-targets -- -D warnings`; `cargo package -p xdoc-cli --allow-dirty`.
[x] Verificacion: `cargo search xdoc-cli` no encontro un package exacto `xdoc-cli`; los comandos finales de formato, check, test y clippy terminaron con codigo `0`; el comando sobre XML invalido devuelve error como se espera; `cargo package -p xdoc-cli --allow-dirty` falla hasta publicar primero `xdoc-rs` en crates.io.
[x] Siguiente paso recomendado: continuar con `018k - Advanced Testing Fixtures`.
### Tarea 012a - Signature Design Decisions
[x] Tarea actual: `docs/tasks/012a-signature-design-decisions.md`.
[x] Estado exacto: completada; se analizaron los planes XAdES locales y se definio ruta XMLDSig -> XAdES-BES -> XAdES-EPES.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012-signature-base.md`, `docs/tasks/012a-signature-design-decisions.md`, `docs/tasks/012b-signature-algorithms-digest-base64.md`, `docs/tasks/012c-signature-ids-canonicalization.md`, `docs/tasks/012d-xmldsig-enveloped.md`, `docs/tasks/012e-xades-bes.md`, `docs/tasks/012f-xades-epes-policy.md`, `docs/tasks/012g-xades-baseline-b-compatibility.md`, `docs/tasks/012h-xades-t-timestamp.md`, `docs/tasks/012i-xades-validation-data.md`, `docs/tasks/012j-xades-archive.md`, `docs/tasks/015-cli.md`, `docs/tasks/016-quality-gate.md`, `docs/tasks/018-hardening-before-signature.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `012a` queda como tarea de decisiones; las tareas ejecutables empiezan en `012b`; C14N 1.1 sin comentarios es el MVP; SHA-256 y RSA-SHA256 son defaults iniciales; IDs duplicados y referencias ambiguas son error; BES y EPES son prioridad despues de XMLDSig base; EPES modela politica explicita sin dominios hardcodeados.
[x] Comandos ejecutados: `sed` sobre `docs/context.md`, `docs/instructions.md`, `docs/tasks/README.md`, `docs/tasks/012a-signature-design-decisions.md`, `docs/tasks/012-signature-base.md`, `plan_ejecucion_xades_xdoc.md`, `plan_ejecucion_xades_xdoc_actualizado.md`, `plan_libreria_xml_generica_rust.md`; `rg -n "C14N|XMLDSig|XAdES|BES|EPES|SigningProvider|signature wrapping|SignedInfo|Reference|SignaturePolicyIdentifier" docs/tasks/012a-signature-design-decisions.md docs/tasks/README.md docs/worklogs.md`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: la documentacion de decisiones cubre canonicalizacion, digest, XMLDSig, BES, EPES, provider, verificacion y mitigaciones contra signature wrapping; los comandos finales terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con `012b - Signature Algorithms Digest Base64` cuando se decida iniciar implementacion de firma, o cerrar antes `018k - Advanced Testing Fixtures` si se prefiere terminar todo el hardening previo.
### Tarea 012b - Signature Algorithms Digest Base64
[x] Tarea actual: `docs/tasks/012b-signature-algorithms-digest-base64.md`.
[x] Estado exacto: completada; `src/signature/` expone enums de algoritmos, URIs XMLDSig/XMLENC, SHA-256 y base64 estandar.
[x] Archivos tocados: `Cargo.toml`, `Cargo.lock`, `README.md`, `src/signature/mod.rs`, `src/signature/algorithms.rs`, `src/signature/base64.rs`, `src/signature/digest.rs`, `docs/tasks/012b-signature-algorithms-digest-base64.md`, `docs/tasks/012-signature-base.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: se agregan `sha2 = "0.11.0"` y `base64 = "0.22.1"` al package runtime `xdoc-rs`; SHA-256 y RSA-SHA256 son defaults; SHA-1/RSA-SHA1 se modelan como algoritmos legados reconocibles por URI pero rechazados para generacion; todavia no se implementa canonicalizacion ni XMLDSig.
[x] Comandos ejecutados: `cargo search sha2 --limit 3`; `cargo search base64 --limit 3`; `cargo add -p xdoc-rs sha2@0.11.0 base64@0.22.1`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test signature_algorithms`; `cargo test signature_digest`; `cargo test signature_base64`.
[x] Verificacion: formato, check y tests filtrados terminaron con codigo `0`; SHA-256 se probo con el vector conocido de `abc`; base64 se probo con valores estandar; SHA-1/RSA-SHA1 devuelven `ErrorKind::Signature` para generacion.
[x] Siguiente paso recomendado: continuar con `012c - Signature IDs And Canonicalization`.
### Tarea 012c - Signature IDs And Canonicalization
[x] Tarea actual: `docs/tasks/012c-signature-ids-canonicalization.md`.
[x] Estado exacto: completada; `src/signature/` resuelve IDs firmables y canonicaliza documentos/nodos con C14N 1.1 sin comentarios.
[x] Archivos tocados: `README.md`, `src/signature/mod.rs`, `src/signature/ids.rs`, `src/signature/canonicalization.rs`, `tests/golden/signature/c14n_document.xml`, `docs/tasks/012c-signature-ids-canonicalization.md`, `docs/tasks/012-signature-base.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `IdAttributePolicy::Standard` reconoce `Id`, `ID` y `xml:id`; `find_element_by_id` valida unicidad antes de devolver un nodo para evitar referencias ambiguas; C14N 1.1 se implementa independiente del writer normal; comentarios se omiten; CDATA se canonicaliza como texto; `ExclusiveXml10` y C14N con comentarios devuelven error explicito por ahora.
[x] Comandos ejecutados: `cargo fmt --all -- --check`; `cargo test signature_ids`; `cargo test c14n`; `cargo test canonicalization`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: tests filtrados, formato, check y test global terminaron con codigo `0`; el golden test cubre exclusion de XML declaration, omision de comentarios, orden de namespaces/atributos y normalizacion de elementos vacios.
[x] Siguiente paso recomendado: continuar con `012d - XMLDSig Enveloped`.
### Tarea 012d - XMLDSig Enveloped
[x] Tarea actual: `docs/tasks/012d-xmldsig-enveloped.md`.
[x] Estado exacto: completada; `src/signature/` genera y verifica XMLDSig enveloped basico sobre XML simple.
[x] Archivos tocados: `README.md`, `src/signature/mod.rs`, `src/signature/canonicalization.rs`, `src/signature/ids.rs`, `src/signature/key.rs`, `src/signature/xmldsig.rs`, `docs/tasks/012d-xmldsig-enveloped.md`, `docs/tasks/012-signature-base.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: el provider incluido es deterministico y solo sirve para pruebas; `SigningProvider::verify` compara contra la firma producida por el provider hasta agregar backends criptograficos reales; `ds:KeyInfo/X509Data` se genera con certificado DER base64 pero no se usa aun para validacion de cadena; XMLDSig base no incluye XAdES.
[x] Comandos ejecutados: `cargo fmt --all -- --check`; `cargo check`; `cargo test xmldsig`; `cargo test signature_provider`; `cargo test verify`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: tests filtrados y test global terminaron con codigo `0`; la verificacion falla si se cambia contenido firmado o `SignatureValue`; transforms no soportados y referencias ambiguas producen error.
[x] Siguiente paso recomendado: continuar con `012e - XAdES BES`.
### Tarea 012e - XAdES BES
[x] Tarea actual: `docs/tasks/012e-xades-bes.md`.
[x] Estado exacto: completada; `src/signature/` genera y verifica XAdES-BES enveloped generico sobre la base XMLDSig existente.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012e-xades-bes.md`, `docs/worklogs.md`, `src/signature/mod.rs`, `src/signature/xmldsig.rs`, `src/signature/profiles.rs`, `src/signature/signer.rs`, `src/signature/verifier.rs`, `src/signature/xades.rs`, `tests/golden/signature/xades_bes.xml`.
[x] Decisiones tomadas: `XadesProfile::Bes` queda como primer perfil publico; `XadesConfig` envuelve `XmlDsigConfig` y usa `SigningCertificateV2` por defecto con modo clasico opcional; `SigningTime` se configura como string para no agregar dependencia temporal; la verificacion BES reutiliza XMLDSig, exige referencia `SignedProperties` con `Type` y valida el digest del certificado contra `KeyInfo` y el provider. RSA real, EPES, politicas, timestamps y validacion legal de certificados quedan fuera de esta tarea.
[x] Comandos ejecutados: `cargo test xades_bes -- --nocapture`; `cargo test xades_bes && cargo test signed_properties && cargo test signing_certificate`; `cargo fmt --all`; `cargo check`; `cargo test`; `cargo fmt --all -- --check`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `cargo clippy --workspace --all-targets -- -D warnings`.
[x] Verificacion: formato, check, tests filtrados, test global, anti-dominio y clippy terminaron con codigo `0`; los tests cubren golden BES, alteracion del documento, alteracion de `SignedProperties`, cambio de certificado y modo `SigningCertificate` clasico.
[x] Siguiente paso recomendado: continuar con `012f - XAdES EPES Policy`.
### Tarea 012f - XAdES EPES Policy
[x] Tarea actual: `docs/tasks/012f-xades-epes-policy.md`.
[x] Estado exacto: completada; `src/signature/` genera y verifica XAdES-EPES enveloped contra una politica explicita configurable.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012f-xades-epes-policy.md`, `docs/worklogs.md`, `src/signature/mod.rs`, `src/signature/policy.rs`, `src/signature/profiles.rs`, `src/signature/signer.rs`, `src/signature/verifier.rs`, `src/signature/xades.rs`, `tests/golden/signature/xades_epes.xml`.
[x] Decisiones tomadas: EPES se modela como `XadesProfile::Epes(SignaturePolicy)`; la politica se inserta en `SignedSignatureProperties` antes de calcular el digest de `SignedProperties`; `SignaturePolicyId` soporta URI y OID, `SignaturePolicyQualifier` soporta `SPURI` y `SPUserNotice`; el verifier EPES exige la politica esperada y reporta `signature_policy_valid`. No se agregaron politicas ni referencias de dominio.
[x] Comandos ejecutados: `cargo test xades_epes -- --nocapture`; `cargo test xades_epes`; `cargo test signature_policy`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `cargo clippy --workspace --all-targets -- -D warnings`.
[x] Verificacion: tests EPES y policy pasaron; el golden EPES es deterministico; la verificacion falla si se exige EPES sobre BES o si cambia identificador/hash de politica; formato, check, test global, anti-dominio y clippy terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con `012g - XAdES Baseline B Compatibility`.
### Tarea 012g - XAdES Baseline B Compatibility
[x] Tarea actual: `docs/tasks/012g-xades-baseline-b-compatibility.md`.
[x] Estado exacto: completada; `src/signature/` expone XAdES Baseline-B/B-B como perfil moderno adicional.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012g-xades-baseline-b-compatibility.md`, `docs/worklogs.md`, `src/signature/mod.rs`, `src/signature/profiles.rs`, `src/signature/signer.rs`, `src/signature/verifier.rs`, `src/signature/xades.rs`, `tests/golden/signature/xades_baseline_b.xml`.
[x] Decisiones tomadas: Baseline-B se modela como `XadesProfile::BaselineB { policy: Option<SignaturePolicy> }`; conserva `XadesProfile::Epes` como API explicita; siempre emite `SigningCertificateV2`, rechaza `SigningCertificate` clasico en verificacion, requiere `ds:KeyInfo/ds:X509Data` y permite politica opcional dentro de `SignedProperties`.
[x] Comandos ejecutados: `cargo test xades_baseline_b -- --nocapture`; `cargo test xades_baseline_b`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `cargo clippy --workspace --all-targets -- -D warnings`.
[x] Verificacion: el golden Baseline-B es deterministico; los tests cubren firma/verificacion, politica opcional, rechazo de certificado clasico y soporte desde `XadesSigner`/`XadesVerifier`; formato, check, test global, anti-dominio y clippy terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con `012h - XAdES T Timestamp`.
### Tarea 012h - XAdES T Timestamp
[x] Tarea actual: `docs/tasks/012h-xades-t-timestamp.md`.
[x] Estado exacto: completada; `src/signature/` puede agregar y verificar un `xades:SignatureTimeStamp` opcional como unsigned property sobre firmas XAdES existentes.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012h-xades-t-timestamp.md`, `docs/worklogs.md`, `src/signature/mod.rs`, `src/signature/timestamp.rs`.
[x] Decisiones tomadas: se modela `TimestampAuthorityClient` como abstraccion sin red; el provider incluido es deterministico y solo para tests; el message imprint se calcula con SHA-256 sobre `ds:SignatureValue` canonicalizado; el timestamp se inserta bajo `xades:UnsignedProperties/xades:UnsignedSignatureProperties/xades:SignatureTimeStamp` y no modifica las referencias firmadas.
[x] Comandos ejecutados: `cargo test xades_timestamp -- --nocapture`; `cargo test xades_timestamp`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `cargo clippy --workspace --all-targets -- -D warnings`.
[x] Verificacion: los tests cubren insercion de timestamp, reporte de ausencia, rechazo de duplicados y token invalido si cambia `SignatureValue`; formato, check, test global, anti-dominio y clippy terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con `012i - XAdES Validation Data`.
### Tarea 012k - Signature Production Interoperability Gap
[x] Tarea actual: `docs/tasks/012k-signature-production-interoperability-gap.md`.
[x] Estado exacto: completada; se documentaron brechas genericas para que capas externas puedan configurar firmas XML/XAdES productivas estrictas sin convertir el motor en dominio.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/016-quality-gate.md`, `docs/tasks/012k-signature-production-interoperability-gap.md`, `docs/tasks/012l-signature-real-crypto-providers.md`, `docs/tasks/012m-signature-c14n10-compatibility.md`, `docs/tasks/012n-xmldsig-configurable-references.md`, `docs/tasks/012o-xades-certificate-details-chain.md`, `docs/tasks/012p-xades-signed-properties-extensions.md`, `docs/tasks/012q-signature-placement-api.md`, `docs/tasks/012r-signature-validation-profile.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `firma_digital_documento_dian.md` se uso solo como referencia externa de brechas; las tareas nuevas describen providers criptograficos reales, C14N 1.0, referencias configurables, datos completos de certificado, extensiones XAdES tipadas, ubicacion configurable de firma y perfiles de validacion. No se agrega modulo de dominio ni reglas hardcodeadas.
[x] Comandos ejecutados: `rg -n "012l|012m|012n|012o|012p|012q|012r" docs/tasks/README.md docs/tasks`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`.
[x] Verificacion: la documentacion de backlog existe y las tareas nuevas quedan enlazadas desde el indice; los comandos finales terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con `012l - Signature Real Crypto Providers` o `012m - Signature C14N 1.0 Compatibility`, segun se priorice firma real o compatibilidad de canonicalizacion.
### Tarea 012m - Signature C14N 1.0 Compatibility
[x] Tarea actual: `docs/tasks/012m-signature-c14n10-compatibility.md`.
[x] Estado exacto: completada; `src/signature/` reconoce y ejecuta Canonical XML 1.0 sin comentarios con URI W3C, seleccionable desde configuracion XMLDSig/XAdES.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012m-signature-c14n10-compatibility.md`, `docs/worklogs.md`, `src/signature/algorithms.rs`, `src/signature/canonicalization.rs`, `src/signature/xmldsig.rs`, `src/signature/xades.rs`, `tests/golden/signature/c14n10_document.xml`.
[x] Decisiones tomadas: C14N 1.0 comparte el writer interno inclusivo sin comentarios con C14N 1.1 para la superficie que modela hoy el arbol; la seleccion se hace por `CanonicalizationAlgorithm::CanonicalXml10` y `XmlDsigConfig::with_canonicalization`; XAdES lo hereda por `XadesConfig::with_xmldsig_config`; `ExclusiveXml10` sigue rechazado con error explicito hasta que haya fixtures interoperables.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo test c14n10`; `cargo test canonicalization`; `cargo test xmldsig_can_select_c14n10_by_config`; `cargo test xades_bes_can_select_c14n10_from_xmldsig_config`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: tests focalizados y suite completa terminaron con codigo `0`; no se agregaron referencias de dominio en `src/signature`.
[x] Siguiente paso recomendado: continuar con `012l - Signature Real Crypto Providers` o `012n - XMLDSig Configurable References`.
### Tarea 012n - XMLDSig Configurable References
[x] Tarea actual: `docs/tasks/012n-xmldsig-configurable-references.md`.
[x] Estado exacto: completada; XMLDSig puede generar y verificar referencias configurables a `#Id`, documento completo `URI=""` y `ds:KeyInfo` por `Id`.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012n-xmldsig-configurable-references.md`, `docs/worklogs.md`, `src/signature/mod.rs`, `src/signature/xmldsig.rs`.
[x] Decisiones tomadas: se agregan `XmlDsigReferenceConfig` y `XmlDsigReferenceTarget`; los transforms por referencia usan defaults seguros segun objetivo y heredan la canonicalizacion del `XmlDsigConfig`; las referencias de documento requieren `enveloped-signature`; `KeyInfo` recibe `Id` solo cuando se referencia y se digiere con una representacion temporal identica para conservar el orden XMLDSig de salida.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo test xmldsig_references`; `cargo test key_info_reference`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: los tests cubren `URI=""`, referencia a `KeyInfo`, alteracion de `KeyInfo`, rechazo de IDs duplicados y rechazo de referencia documental sin transform enveloped; la suite completa termino con codigo `0`.
[x] Siguiente paso recomendado: continuar con `012l - Signature Real Crypto Providers` o `012q - Signature Placement API`.
### Tarea 012q - Signature Placement API
[x] Tarea actual: `docs/tasks/012q-signature-placement-api.md`.
[x] Estado exacto: completada; `ds:Signature` puede insertarse bajo root, bajo un `NodeId` explicito o bajo el unico nodo seleccionado por una query segura.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012q-signature-placement-api.md`, `docs/worklogs.md`, `src/signature/mod.rs`, `src/signature/xmldsig.rs`, `src/signature/xades.rs`.
[x] Decisiones tomadas: `SignaturePlacement` vive en XMLDSig y se configura desde `XmlDsigConfig`; el default conserva la insercion bajo root; XAdES reutiliza la misma configuracion; las queries usan el motor `query` con `NamespaceContext` opcional y fallan si no encuentran nodo, si son ambiguas o si seleccionan texto/atributo; no se agregan rutas ni nombres de dominio.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo test signature_placement`; `cargo test xades_bes_can_place_signature_by_query`; `cargo test xmldsig`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: tests focalizados y suite completa terminaron con codigo `0`; los tests cubren ubicacion por `NodeId`, ubicacion por query, rechazo de query ambigua y firma XAdES en contenedor `Extension` generico.
[x] Siguiente paso recomendado: continuar con `012l - Signature Real Crypto Providers` o `012i - XAdES Validation Data`.
### Tarea 012i - XAdES Validation Data
[x] Tarea actual: `docs/tasks/012i-xades-validation-data.md`.
[x] Estado exacto: completada; `src/signature/` puede agregar y reportar validation data XAdES como unsigned properties para una base LT generica.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012i-xades-validation-data.md`, `docs/worklogs.md`, `src/signature/mod.rs`, `src/signature/validation_data.rs`.
[x] Decisiones tomadas: `XadesValidationDataProvider` expone certificados, OCSP y CRL como bytes opacos; `StaticValidationDataProvider` cubre tests y uso local sin red; `add_xades_validation_data` inserta `CertificateValues` y `RevocationValues`, deduplica material y rechaza insercion duplicada; `verify_xades_validation_data` reporta presencia, conteos y material faltante sin validar confianza legal, autoridades ni dominios.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo test xades_validation_data`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: tests focalizados cubren insercion de certificados/revocacion, reporte de faltantes, rechazo de duplicados y deduplicacion de material; suite completa y chequeo anti-dominio terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con `012l - Signature Real Crypto Providers` o `012j - XAdES Archive`.
### Tarea 012j - XAdES Archive
[x] Tarea actual: `docs/tasks/012j-xades-archive.md`.
[x] Estado exacto: completada; `src/signature/` puede agregar, renovar y verificar `xades:ArchiveTimeStamp` como base generica para XAdES-A/Baseline-LTA.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012j-xades-archive.md`, `docs/worklogs.md`, `src/signature/mod.rs`, `src/signature/archive.rs`.
[x] Decisiones tomadas: `XadesArchiveConfig` reutiliza `TimestampAuthorityClient`; agregar archive timestamp requiere `SignatureTimeStamp` y validation data existentes; la renovacion se modela como multiples `ArchiveTimeStamp` sobre el material preservado excluyendo archive timestamps existentes; la verificacion reporta inputs de preservacion, conteo, estructura y tokens validos sin red obligatoria ni autoridad hardcodeada.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo test xades_archive`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: tests focalizados cubren agregado de archive timestamp sin romper BES, re-timestamping, reporte de faltantes y rechazo cuando falta validation data; suite completa y chequeo anti-dominio terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con `012l - Signature Real Crypto Providers` o `012o - XAdES Certificate Details And Chain`.
### Tarea 012l - Signature Real Crypto Providers
[x] Tarea actual: `docs/tasks/012l-signature-real-crypto-providers.md`.
[x] Estado exacto: completada; `src/signature/` expone `RsaSha256SigningProvider` para firmar y verificar `SignedInfo` canonicalizado con RSA-SHA256 real.
[x] Archivos tocados: `Cargo.toml`, `Cargo.lock`, `README.md`, `docs/tasks/README.md`, `docs/tasks/012l-signature-real-crypto-providers.md`, `docs/worklogs.md`, `src/signature/key.rs`, `src/signature/mod.rs`.
[x] Decisiones tomadas: se usan crates estables compatibles con publicacion (`rsa` 0.9.x, `sha2` 0.10.x, `signature` 2.x) y se evita la linea `rsa` 0.10 porque sigue en release candidate; el provider acepta llaves RSA PKCS#8/PKCS#1 en PEM o DER desde memoria, conserva el certificado DER como bytes opacos y verifica con clave publica RSA derivada o entregada explicitamente; PKCS#12/PFX y extraccion de clave publica desde certificado X.509 quedan para tareas posteriores de credenciales/cadena; no hay lectura implicita de archivos, red ni secretos.
[x] Comandos ejecutados: `cargo search rsa --limit 5`; `cargo search signature --limit 5`; `cargo search x509-cert --limit 5`; `cargo info rsa@0.9.8`; `cargo info sha2@0.10.9`; `cargo info signature@2.2.0`; `cargo rm --package xdoc-rs rand_core`; `cargo add --package xdoc-rs rsa@0.9.10 --features sha2`; `cargo add --package xdoc-rs sha2@0.10.9`; `cargo add --package xdoc-rs signature@2.2.0`; `cargo check`; `cargo test real_crypto_provider`; `cargo fmt --all -- --check`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: formato, check, suite completa y anti-dominio terminaron con codigo `0`; el filtro `real_crypto_provider` paso con 5 tests, incluyendo firma/verificacion RSA-SHA256 de bytes y flujo XMLDSig enveloped completo.
[x] Siguiente paso recomendado: continuar con `012o - XAdES Certificate Details And Chain`.
### Tarea 012o - XAdES Certificate Details And Chain
[x] Tarea actual: `docs/tasks/012o-xades-certificate-details-chain.md`.
[x] Estado exacto: completada; XAdES puede emitir y verificar issuer/serial y cadena de certificados como metadatos genericos entregados por el `SigningProvider`.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012o-xades-certificate-details-chain.md`, `docs/worklogs.md`, `src/signature/key.rs`, `src/signature/mod.rs`, `src/signature/xades.rs`.
[x] Decisiones tomadas: `CertificateDetails` modela DER, issuer y serial sin validar confianza legal; `SigningProvider` mantiene defaults compatibles y expone `certificate_details`/`certificate_chain_details`; `XadesConfig::with_certificate_chain(true)` controla si se emiten certificados adicionales; la verificacion compara digest, issuer y serial contra los datos del provider, no contra autoridades, listas de confianza ni dominios.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo test signing_certificate_details`; `cargo test certificate_chain`; `cargo check`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: tests filtrados, formato, check, suite completa y anti-dominio terminaron con codigo `0`; la suite completa cubrio 225 tests unitarios del runtime mas compile tests/doc tests.
[x] Siguiente paso recomendado: continuar con `012p - XAdES Signed Properties Extensions`.
### Tarea 012p - XAdES Signed Properties Extensions
[x] Tarea actual: `docs/tasks/012p-xades-signed-properties-extensions.md`.
[x] Estado exacto: completada; XAdES permite descripcion de politica, `SPUserNotice` y `SignerRole`/claimed roles como signed properties tipadas.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012p-xades-signed-properties-extensions.md`, `docs/worklogs.md`, `src/signature/mod.rs`, `src/signature/policy.rs`, `src/signature/xades.rs`.
[x] Decisiones tomadas: la descripcion vive en `SignaturePolicy` y se emite como `xades:Description` dentro de `SigPolicyId`; `SignerRole` modela solo claimed roles genericos y se configura desde `XadesConfig`; no se acepta XML raw ni se hardcodean roles; todas las extensiones se insertan dentro de `SignedSignatureProperties`, por lo que quedan cubiertas por la referencia a `SignedProperties`.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo test xades_signed_properties_extensions`; `cargo test signer_role`; `cargo check`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: tests filtrados, formato, check, suite completa y anti-dominio terminaron con codigo `0`; la suite completa cubrio 231 tests unitarios del runtime mas compile tests/doc tests.
[x] Siguiente paso recomendado: continuar con `012r - Signature Validation Profile`.
### Tarea 012r - Signature Validation Profile
[x] Tarea actual: `docs/tasks/012r-signature-validation-profile.md`.
[x] Estado exacto: completada; `src/signature/` expone `SignatureValidationProfile` para validar requisitos estrictos genericos sobre XMLDSig/XAdES.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012r-signature-validation-profile.md`, `docs/worklogs.md`, `src/signature/mod.rs`, `src/signature/validation_profile.rs`.
[x] Decisiones tomadas: el perfil se modela por parametros, no por perfiles de dominio; puede exigir referencias de documento, `KeyInfo` y `SignedProperties`, algoritmos permitidos, nivel XMLDSig/XAdES esperado, politica, ubicacion de `ds:Signature`, cadena y revocacion; T/LT/LTA se validan contra estructura/material ya presente sin red ni cliente externo por defecto; el reporte clasifica errores criptograficos, estructura faltante, material externo faltante, politica, algoritmos y ubicacion.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo test signature_validation_profile`; `cargo check`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`.
[x] Verificacion: tests filtrados, formato, check, suite completa y anti-dominio terminaron con codigo `0`; la suite completa cubrio 237 tests unitarios del runtime mas compile tests/doc tests.
[x] Siguiente paso recomendado: continuar con cierre de `012 - Signature Base` o revisar `013 - Security Policies`.
### Ejemplo DIAN-like XAdES-EPES
[x] Tarea actual: ejemplo de firma electronica DIAN-like solicitado por el usuario, usando `firma_digital_documento_dian.md` como referencia externa historica y sin mover reglas de dominio al motor.
[x] Estado exacto: completado; se agrego un ejemplo ejecutable que construye una factura UBL minima con `xml!`, inserta `ds:Signature` en `ext:ExtensionContent`, firma XAdES-EPES con RSA-SHA256 real y valida el resultado con un perfil parametrico.
[x] Archivos tocados: `docs/worklogs.md`, `examples/dian_signature.rs`, `src/signature/xades.rs`, `src/signature/xmldsig.rs`.
[x] Decisiones tomadas: XAdES reutiliza ahora las referencias configurables de XMLDSig y agrega encima la referencia obligatoria a `SignedProperties`; el ejemplo usa `URI=""`, referencia a `KeyInfo`, C14N 1.0, `SigningCertificate` clasico, `SignerRole` y politica por parametros; el certificado/llave son autofirmados de demo y el hash de politica es un placeholder que debe reemplazarse por el digest real del PDF oficial.
[x] Comandos ejecutados: `cargo check --example dian_signature`; `openssl req -x509 ...`; `cargo run --example dian_signature -- target/dian-signature-example.xml`; `rg -n "<ext:ExtensionContent|<ds:Reference|<ds:KeyInfo|<xades:SignedProperties|<xades:SigningCertificate|<xades:SignerRole|<xades:SignaturePolicyIdentifier" target/dian-signature-example.xml`; `rg -n "DIAN|UBL|Factura|factura|Electronica|dian" src/signature src/core src/writer src/builder src/component src/parser src/macros src/query src/transform src/schema src/security src/testing src/bin || true`; `cargo test signature::xades::tests::xades_bes_can_sign_whole_document_and_key_info_references`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `cargo run --example dian_signature -- target/dian-signature-example.xml`.
[x] Verificacion: formato, check, suite completa y ejemplo ejecutable terminaron con codigo `0`; el ejemplo genero `target/dian-signature-example.xml` y valido `signature valid: true`; la salida contiene `URI=""`, `KeyInfo` con `Id`, referencia `SignedProperties`, `SigningCertificate`, `SignaturePolicyIdentifier` y `SignerRole`; no hay referencias DIAN/UBL en los modulos del motor bajo `src/`.
[x] Siguiente paso recomendado: continuar con tareas de credenciales/certificados reales, validacion de cadena/confianza y extraccion X.509/PKCS#12 antes de aspirar a interoperabilidad DIAN real.
### Ejemplo DIAN-like con Credenciales Externas y Flujo Completo
[x] Tarea actual: ampliar `examples/dian_signature.rs` para usar certificados externos reales y ejecutar una prueba completa de las funcionalidades de firma ya implementadas.
[x] Estado exacto: completado; el ejemplo acepta llave privada y certificado PEM/DER por CLI, issuer/serial, cadena de certificados, bytes de politica y material OCSP/CRL; no conserva llaves privadas ni certificados embebidos.
[x] Archivos tocados: `docs/worklogs.md`, `examples/dian_signature.rs`.
[x] Decisiones tomadas: no se commitean certificados privados reales ni fixtures con llave; el ejemplo prueba XAdES-EPES, verificacion EPES, perfil estricto, `SignatureTimeStamp`, `CertificateValues`, `RevocationValues`, `ArchiveTimeStamp` y perfil LTA-like generico; el TSA sigue siendo deterministico porque el motor aun no incluye cliente RFC3161 real; OCSP/CRL son bytes opacos entregados por parametro o placeholder de demo si no se suministran.
[x] Comandos ejecutados: `cargo check --example dian_signature`; `cargo run --example dian_signature -- target/dian-signature-example.xml`; `openssl req -x509 ...`; `cargo run --example dian_signature -- target/dian-signature-external.xml --private-key /tmp/.../key.pem --certificate /tmp/.../cert.pem --issuer-name ... --serial-number ... --policy-bytes /tmp/.../policy.pdf --ocsp /tmp/.../ocsp.der`; `rg -n "<ds:Reference|<ds:KeyInfo|<xades:SigningCertificate|<xades:SignaturePolicyIdentifier|<xades:SignatureTimeStamp|<xades:CertificateValues|<xades:RevocationValues|<xades:ArchiveTimeStamp" target/dian-signature-external.xml`; `rg -n "DIAN|UBL|Factura|factura|Electronica|dian" src/signature src/core src/writer src/builder src/component src/parser src/macros src/query src/transform src/schema src/security src/testing src/bin || true`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `cargo run --example dian_signature -- target/dian-signature-example.xml`; busqueda local para confirmar que el ejemplo no conserva credenciales embebidas; `cargo check --example dian_signature`; `cargo run --example dian_signature -- target/dian-signature-external.xml --private-key /tmp/.../key.pem --certificate /tmp/.../cert.pem --issuer-name ... --serial-number ... --policy-bytes /tmp/.../policy.pdf --ocsp /tmp/.../ocsp.der`.
[x] Verificacion: formato, check, suite completa y ejemplo final terminaron con codigo `0`; despues de remover las credenciales embebidas, el ejemplo paso con un certificado X.509 externo generado en `/tmp` y valido firma, timestamp, validation data y archive timestamp; la salida externa contiene referencias XMLDSig, `KeyInfo`, `SigningCertificate`, politica, timestamp, valores de validacion y archive timestamp; no hay referencias de dominio en `src/`.
[x] Siguiente paso recomendado: implementar carga PKCS#12/PFX y/o cliente RFC3161 real como tareas separadas antes de intentar interoperabilidad productiva.
### Tarea 012s - PKCS12 PFX Credentials
[x] Tarea actual: `docs/tasks/012s-pkcs12-pfx-credentials.md`.
[x] Estado exacto: completada; `src/signature/` puede extraer credenciales desde `.pfx`/`.p12` entregados como DER en memoria y usarlas con el provider RSA-SHA256 real.
[x] Archivos tocados: `Cargo.toml`, `Cargo.lock`, `README.md`, `docs/tasks/README.md`, `docs/tasks/012s-pkcs12-pfx-credentials.md`, `docs/worklogs.md`, `examples/dian_signature.rs`, `src/signature/key.rs`, `src/signature/mod.rs`.
[x] Decisiones tomadas: se usa `openssl` 0.10.x porque es estable, publicable y soporta PFX habituales; se evita una dependencia PKCS#12 pre-release en la ruta criptografica; `Pkcs12Credential` expone llave privada, certificado firmante y cadena como DER sin validar confianza legal, revocacion ni politicas; el ejemplo DIAN-like acepta `--pfx`/`--p12` con password explicita y mantiene PEM/DER como alternativa.
[x] Comandos ejecutados: `cargo search p12 --limit 5`; `cargo search pkcs12 --limit 5`; `cargo add --package xdoc-rs p12@0.6.3`; prueba local de PFX con `p12` y OpenSSL; `cargo rm --package xdoc-rs p12`; `cargo add --package xdoc-rs openssl@0.10.80`; `cargo test pkcs12`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check`; `cargo check --example dian_signature`; `cargo test`; `cargo run --example dian_signature -- target/dian-signature-pfx.xml --pfx /tmp/.../credential.pfx --pfx-password secret --issuer-name ... --serial-number ... --policy-bytes /tmp/.../policy.pdf --ocsp /tmp/.../ocsp.der`; `rg -n "<ds:Reference|<ds:KeyInfo|<xades:SigningCertificate|<xades:SignaturePolicyIdentifier|<xades:SignatureTimeStamp|<xades:CertificateValues|<xades:RevocationValues|<xades:ArchiveTimeStamp" target/dian-signature-pfx.xml`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `git diff --check`.
[x] Verificacion: formato, check, check del ejemplo, suite completa, prueba funcional con `.pfx` generado localmente, chequeo de estructura XAdES en la salida y anti-dominio terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con TSA RFC 3161 real o validacion de confianza/cadena como tareas separadas, sin mover reglas de dominio al motor.
### Ajuste ejemplo DIAN-like PFX
[x] Tarea actual: refinamiento de `docs/tasks/012s-pkcs12-pfx-credentials.md` solicitado por el usuario.
[x] Estado exacto: completado; el ejemplo deja de ser un flujo CLI y pasa a usar `ExampleConfig` con `pfx_path` y `pfx_password` dentro del codigo.
[x] Archivos tocados: `docs/tasks/012s-pkcs12-pfx-credentials.md`, `docs/worklogs.md`, `examples/dian_signature.rs`.
[x] Decisiones tomadas: el ejemplo genera un `.pfx` autofirmado de demo en `target/xdoc-demo-signing.pfx` si no existe; si el archivo existe, se usa la ruta configurada sin sobrescribirlo.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check --example dian_signature`; `rm -f target/xdoc-demo-signing.pfx target/dian-signature-example.xml && cargo run --example dian_signature`; `cargo check`; `cargo test`; `rg -n "<ds:Reference|<ds:KeyInfo|<xades:SigningCertificate|<xades:SignaturePolicyIdentifier|<xades:SignatureTimeStamp|<xades:CertificateValues|<xades:RevocationValues|<xades:ArchiveTimeStamp" target/dian-signature-example.xml`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `git diff --check`.
[x] Verificacion: formato, check del ejemplo, ejecucion sin argumentos con PFX autofirmado generado por el propio ejemplo, check general, suite completa, estructura XAdES y anti-dominio terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con TSA RFC 3161 real o validacion de confianza/cadena como tareas separadas.
### Tarea 012t - Signature Ergonomic API
[x] Tarea actual: `docs/tasks/012t-signature-ergonomic-api.md`.
[x] Estado exacto: completada; `XadesSigner` puede orquestar firma XAdES, validacion inicial, timestamp, validation data, archive timestamp y validacion final desde una configuracion generica.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012t-signature-ergonomic-api.md`, `docs/worklogs.md`, `examples/dian_signature.rs`, `src/signature/archive.rs`, `src/signature/mod.rs`, `src/signature/signer.rs`, `src/signature/timestamp.rs`, `src/signature/validation_data.rs`.
[x] Decisiones tomadas: se extendio `XadesSigner` en lugar de crear una abstraccion paralela; `XadesSigningOptions` recibe clientes TSA, provider de validation data y perfiles de validacion como parametros; `XadesSignedDocument` devuelve el documento y `XadesSigningReport` con reportes estructurados; las funciones de bajo nivel siguen disponibles y ahora aceptan trait objects para integrarse con la API ergonomica.
[x] Comandos ejecutados: `cargo check`; `cargo fmt --all`; `cargo fmt --all -- --check`; `cargo check --example dian_signature`; `cargo test signer_options`; `rm -f target/xdoc-demo-signing.pfx target/dian-signature-example.xml && cargo run --example dian_signature`; `cargo test`; `rg -n "<ds:Reference|<ds:KeyInfo|<xades:SigningCertificate|<xades:SignaturePolicyIdentifier|<xades:SignatureTimeStamp|<xades:CertificateValues|<xades:RevocationValues|<xades:ArchiveTimeStamp" target/dian-signature-example.xml`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `git diff --check`.
[x] Verificacion: formato, check general, check del ejemplo, tests focalizados, suite completa, ejemplo sin argumentos con PFX autofirmado, estructura XAdES, anti-dominio y whitespace terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con TSA RFC 3161 real o validacion de confianza/cadena como tareas separadas.
### Tarea 012u - Signature Credential Ergonomics
[x] Tarea actual: `docs/tasks/012u-signature-credential-ergonomics.md`.
[x] Estado exacto: completada; `src/signature/` expone `Pkcs12SigningCredentials` para cargar `.pfx`/`.p12` por ruta/password y usarlo directamente como `SigningProvider`.
[x] Archivos tocados: `README.md`, `docs/tasks/README.md`, `docs/tasks/012u-signature-credential-ergonomics.md`, `docs/worklogs.md`, `examples/dian_signature.rs`, `src/signature/key.rs`, `src/signature/mod.rs`, `src/signature/validation_data.rs`.
[x] Decisiones tomadas: la lectura de archivos sigue siendo explicita por ruta; `Pkcs12SigningCredentials` conserva certificado firmante, issuer/serial y cadena adicional, y genera un `StaticValidationDataProvider` inicial; `StaticValidationDataProvider` agrega helpers de lectura explicita para OCSP/CRL; las APIs de bajo nivel se mantienen.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo check --example dian_signature`; `cargo fmt --all -- --check`; `cargo test pkcs12_signing_credentials`; `cargo test static_validation_data_provider_can_read_ocsp_and_crl_files`; `cargo check`; `cargo test`; `rm -f target/xdoc-demo-signing.pfx target/dian-signature-example.xml && cargo run --example dian_signature`; `rg -n "<ds:Reference|<ds:KeyInfo|<xades:SigningCertificate|<xades:SignaturePolicyIdentifier|<xades:SignatureTimeStamp|<xades:CertificateValues|<xades:RevocationValues|<xades:ArchiveTimeStamp" target/dian-signature-example.xml`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `git diff --check`.
[x] Verificacion: formato, check general, check del ejemplo, tests focalizados, suite completa, ejemplo sin argumentos con PFX autofirmado, estructura XAdES, anti-dominio y whitespace terminaron con codigo `0`.
[x] Siguiente paso recomendado: continuar con TSA RFC 3161 real o validacion de confianza/cadena como tareas separadas.
### Tarea 012v - XMLSec Signature Interoperability
[x] Tarea actual: `docs/tasks/012v-xmlsec-signature-interoperability.md`.
[x] Estado exacto: completada; la firma XAdES del ejemplo verifica externamente con `xmlsec1` cuando se le entrega el certificado confiable del PFX demo.
[x] Archivos tocados: `docs/tasks/README.md`, `docs/tasks/012v-xmlsec-signature-interoperability.md`, `docs/worklogs.md`, `examples/dian_signature.rs`, `src/signature/canonicalization.rs`, `src/signature/xades.rs`, `src/signature/xmldsig.rs`, `tests/golden/signature/xades_bes.xml`, `tests/golden/signature/xades_epes.xml`, `tests/golden/signature/xades_baseline_b.xml`.
[x] Decisiones tomadas: `xmlsec1 --verify` sin certificado falla con `KEY-NOT-FOUND` para el certificado autofirmado del demo, lo cual es esperado; la ruta verificable es exportar el certificado PEM y usar `--trusted-pem`. La canonicalizacion inclusiva ahora omite redeclaraciones redundantes, incluye namespaces heredados al canonicalizar subarboles y calcula referencias a `KeyInfo`/`SignedProperties` sobre nodos reales en su contexto final.
[x] Comandos ejecutados: `cargo run --example dian_signature`; `xmlsec1 --verify target/dian-signature-example.xml`; `openssl pkcs12 -in target/xdoc-demo-signing.pfx -passin pass:xdoc-demo-password -clcerts -nokeys -out target/xdoc-demo-signing-cert.pem`; `xmlsec1 --verify --trusted-pem target/xdoc-demo-signing-cert.pem target/dian-signature-example.xml`; `xmlsec1 --verify --verbose --store-references --trusted-pem target/xdoc-demo-signing-cert.pem target/dian-signature-example.xml`; `cargo test c14n -- --nocapture`; `cargo test signature::xmldsig -- --nocapture`; `cargo test signature::xades -- --nocapture`; `cargo fmt --all -- --check`; `cargo check`; `cargo check --example dian_signature`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `git diff --check`.
[x] Verificacion: formato, check general, check del ejemplo, suite completa, pruebas focalizadas de C14N/XMLDSig/XAdES, anti-dominio y whitespace terminaron con codigo `0`; `xmlsec1 --verify --trusted-pem target/xdoc-demo-signing-cert.pem target/dian-signature-example.xml` termino con `Verification status: OK`; el comando sin certificado conserva `KEY-NOT-FOUND`.
[x] Siguiente paso recomendado: continuar con cierre de `012 - Signature Base` o validacion de confianza/cadena.
### Tarea 012w - XAdES SigningTime Certificate Validity
[x] Tarea actual: `docs/tasks/012w-xades-signingtime-certificate-validity.md`.
[x] Estado exacto: completada; `xades:SigningTime` se resuelve antes de crear `SignedProperties` y los providers RSA/PFX reales validan el instante contra `NotBefore`/`NotAfter`.
[x] Archivos tocados: `docs/tasks/README.md`, `docs/tasks/012w-xades-signingtime-certificate-validity.md`, `docs/worklogs.md`, `examples/dian_signature.rs`, `src/signature/key.rs`, `src/signature/mod.rs`, `src/signature/xades.rs`.
[x] Decisiones tomadas: `XadesConfig::new()` usa el reloj del sistema por defecto; `with_signing_time` queda como XML fijo explicito para tests y usos controlados; `with_signing_time_unix_timestamp` permite tests deterministas con validacion de vigencia. La validacion X.509 vive en providers reales; el provider deterministico mantiene no-op para no bloquear fixtures no criptograficos. El tiempo se resuelve antes de calcular digest de `SignedProperties`, poblar `SignedInfo` y producir `SignatureValue`.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo test signing_time -- --nocapture`; `cargo test pkcs12 -- --nocapture`; `cargo run --example dian_signature`; `rg -n "<xades:SigningTime>" target/dian-signature-example.xml`; `openssl x509 -in target/xdoc-demo-signing-cert.pem -noout -dates`; `xmlsec1 --verify --trusted-pem target/xdoc-demo-signing-cert.pem target/dian-signature-example.xml`; `cargo fmt --all -- --check`; `cargo check`; `cargo check --example dian_signature`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `git diff --check`.
[x] Verificacion: formato, check general, check del ejemplo, suite completa, tests focalizados de `SigningTime`/PFX, anti-dominio y whitespace terminaron con codigo `0`; el ejemplo genero `SigningTime=2026-06-12T14:08:36Z` con certificado `notBefore=Jun 12 13:24:56 2026 GMT` y `notAfter=Jun 12 13:24:56 2027 GMT`; `xmlsec1` termino con `Verification status: OK`.
[x] Siguiente paso recomendado: continuar con cierre de `012 - Signature Base` o validacion de confianza/cadena.
### Tarea 012x - XAdES Policy Document Digest
[x] Tarea actual: `docs/tasks/012x-xades-policy-document-digest.md`.
[x] Estado exacto: completada; `xades:SigPolicyHash` del ejemplo se calcula desde los bytes reales de `politicadefirmav2.pdf` local y el motor expone APIs genericas para crear politicas desde bytes o archivos.
[x] Archivos tocados: `docs/tasks/README.md`, `docs/tasks/012x-xades-policy-document-digest.md`, `docs/worklogs.md`, `examples/dian_signature.rs`, `src/signature/algorithms.rs`, `src/signature/digest.rs`, `src/signature/policy.rs`.
[x] Decisiones tomadas: el motor no descarga URLs ni conoce politicas de dominio; la URL queda como `SignaturePolicyId`/`SPURI` entregada por el ejemplo, mientras los bytes de politica entran por archivo local. Se agrego SHA-512 como digest generico porque `SigPolicyHash` debe corresponder al algoritmo declarado. El PDF `politicadefirmav2.pdf` y `firma_digital_documento_dian.md` quedan fuera del commit como material externo sin seguimiento.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo check`; `cargo check --example dian_signature`; `cargo run --example dian_signature`; `xmlsec1 --verify --trusted-pem target/xdoc-demo-signing-cert.pem target/dian-signature-example.xml`; script Python para comparar `xades:SigPolicyHash` con `Base64(SHA256(politicadefirmav2.pdf))`; `if rg -n "UnsignedProperties|SignatureTimeStamp|RevocationValues|ArchiveTimeStamp" target/dian-signature-example.xml; then exit 1; else exit 0; fi`; `cargo fmt --all -- --check`; `cargo check`; `cargo check --example dian_signature`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `git diff --check`.
[x] Verificacion: formato, check general, check del ejemplo, suite completa, anti-dominio y whitespace terminaron con codigo `0`; el ejemplo valido con `xmlsec1`, no emitio `xades:UnsignedProperties`, y el hash de politica emitido fue `dMoMvtcG5aIzgYo0tIsSQeVJBDnUnfSOfBpxXrmor0Y=`, igual a `Base64(SHA256(politicadefirmav2.pdf))`.
[x] Siguiente paso recomendado: continuar con cierre de `012 - Signature Base` o abrir una tarea posterior para TSA/OCSP reales antes de volver a emitir propiedades unsigned.
### Tarea 012y - PKCS12 X509 Metadata Example Config
[x] Tarea actual: `docs/tasks/012y-pkcs12-x509-metadata-example-config.md`.
[x] Estado exacto: completada; las credenciales PFX extraen issuer y serial desde X.509 automaticamente y el ejemplo puede probar un PFX externo por variables de entorno sin constantes manuales de issuer/serial.
[x] Archivos tocados: `docs/tasks/README.md`, `docs/tasks/012y-pkcs12-x509-metadata-example-config.md`, `docs/worklogs.md`, `examples/dian_signature.rs`, `src/signature/key.rs`.
[x] Decisiones tomadas: `with_issuer_serial` se conserva como override explicito, pero el camino normal de `Pkcs12SigningCredentials::from_file/from_der` usa issuer y serial decimal extraidos del certificado. El ejemplo acepta `XDOC_EXAMPLE_PFX`, `XDOC_EXAMPLE_PFX_PASSWORD` y `XDOC_EXAMPLE_POLICY_DOCUMENT`; el PFX externo local y su password no se versionan. La escritura del PEM de verificacion se movio despues de firmar exitosamente para que un fallo por vigencia no deje certificado y XML desincronizados.
[x] Comandos ejecutados: `env PFX_PASSWORD=... openssl pkcs12 -in Certificado.pfx -passin env:PFX_PASSWORD -info -noout`; `openssl x509 -in target/user-cert.pem -noout -subject -issuer -serial -dates`; `cargo fmt --all`; `cargo check`; `cargo check --example dian_signature`; `cargo test pkcs12 -- --nocapture`; `cargo run --example dian_signature`; `env XDOC_EXAMPLE_PFX=Certificado.pfx XDOC_EXAMPLE_PFX_PASSWORD=... cargo run --example dian_signature`; `xmlsec1 --verify --trusted-pem target/xdoc-demo-signing-cert.pem target/dian-signature-example.xml`; `cargo fmt --all -- --check`; `cargo check`; `cargo check --example dian_signature`; `cargo test`; `if rg -n "DEMO_ISSUER_NAME|DEMO_SERIAL_NUMBER|with_issuer_serial" examples/dian_signature.rs; then exit 1; else exit 0; fi`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `git diff --check`.
[x] Verificacion: formato, check general, check del ejemplo, suite completa, tests focalizados PFX, anti-dominio y whitespace terminaron con codigo `0`; el ejemplo demo genero XML verificable con `xmlsec1`; el PFX externo `Certificado.pfx` cargo correctamente pero fallo antes de firmar por `XAdES SigningTime is after certificate NotAfter` porque el certificado expiro el `2025-12-23`.
[x] Siguiente paso recomendado: probar de nuevo con un PFX vigente o abrir la tarea de validacion de cadena/confianza si se necesita mayor compatibilidad DSS.
### Tarea 012z - Local CA Signing Demo PFX
[x] Tarea actual: `docs/tasks/012z-local-ca-signing-demo-pfx.md`.
[x] Estado exacto: completada; el ejemplo por defecto genera un PFX con Root CA local y certificado leaf de firma, en vez de un certificado autofirmado directo.
[x] Archivos tocados: `docs/tasks/README.md`, `docs/tasks/012z-local-ca-signing-demo-pfx.md`, `docs/worklogs.md`, `examples/dian_signature.rs`.
[x] Decisiones tomadas: la Root CA demo usa `basicConstraints=CA:TRUE`, `Certificate Sign` y `CRL Sign`; el leaf usa `basicConstraints=CA:FALSE`, `Digital Signature` y `Non Repudiation`. El PFX incluye la CA como cadena y el ejemplo exporta PEM de leaf y PEM de trust anchor. Los artefactos generados siguen en `target/` y no se versionan; `Certificado.pfx`, `politicadefirmav2.pdf` y `firma_digital_documento_dian.md` siguen como material local sin seguimiento.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo check --example dian_signature`; `rm -f target/xdoc-demo-signing.pfx target/xdoc-demo-signing-cert.pem target/xdoc-demo-root-ca.pem target/dian-signature-example.xml && cargo run --example dian_signature`; `env PFX_PASSWORD=xdoc-demo-password openssl pkcs12 -in target/xdoc-demo-signing.pfx -passin env:PFX_PASSWORD -info -noout`; `openssl x509 -in target/xdoc-demo-signing-cert.pem -noout -subject -issuer -serial -dates -ext basicConstraints`; `openssl x509 -in target/xdoc-demo-root-ca.pem -noout -subject -issuer -serial -dates -ext basicConstraints`; `xmlsec1 --verify --trusted-pem target/xdoc-demo-root-ca.pem target/dian-signature-example.xml`; `openssl x509 -in target/xdoc-demo-signing-cert.pem -noout -ext keyUsage`; `openssl x509 -in target/xdoc-demo-root-ca.pem -noout -ext keyUsage`; script Python para confirmar `xades_cert_count=2`; `env XDOC_EXAMPLE_PFX=Certificado.pfx XDOC_EXAMPLE_PFX_PASSWORD=<redacted> cargo run --example dian_signature`; `cargo fmt --all -- --check`; `cargo check`; `cargo check --example dian_signature`; `cargo test`; `if rg -n "DIAN|UBL|SOAP|facturacion" src/signature; then exit 1; else exit 0; fi`; `git diff --check`.
[x] Verificacion: formato, check general, check del ejemplo, suite completa, anti-dominio y whitespace terminaron con codigo `0`; `xmlsec1` verifico la firma usando `target/xdoc-demo-root-ca.pem` como trust anchor; el PFX demo contiene dos certificate bags; el XML XAdES emitio dos `xades:Cert`; el PFX externo vencido siguio fallando por `NotAfter`, como corresponde.
[x] Siguiente paso recomendado: continuar con validacion de cadena/confianza generica o TSA/OCSP reales antes de aspirar a Baseline LT/LTA interoperable.
### Tarea 012 - Signature Base
[x] Tarea actual: `docs/tasks/012-signature-base.md`.
[x] Estado exacto: completada; el agregador XMLDSig base queda cerrado con canonicalizacion, digest, provider de firma, firma enveloped y verificacion basica funcionando sin acoplamiento de dominio.
[x] Archivos tocados: `docs/tasks/README.md`, `docs/tasks/012-signature-base.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: `012` se cierra como agregador de XMLDSig base; XAdES BES/EPES y politica de firma permanecen documentadas y verificadas en tareas separadas (`012e+`) para no mezclar responsabilidades del cierre XMLDSig.
[x] Comandos ejecutados: `cargo test signature`; `cargo test c14n`; `cargo test digest`; `cargo test xmldsig`; `cargo test verify`; `if rg -n "DIAN|UBL|SOAP" src/signature; then exit 1; else exit 0; fi`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `git diff --check`.
[x] Verificacion: filtros de firma, canonicalizacion, digest, XMLDSig y verificacion, formato, check general, suite completa y whitespace terminaron con codigo `0`; la busqueda anti-dominio no encontro acoplamiento en `src/signature`.
[x] Siguiente paso recomendado: continuar con `014 - Testing Infrastructure` o con validacion de cadena/confianza generica si se prioriza interoperabilidad de firma.
### Tarea 014 - Testing Infrastructure
[x] Tarea actual: `docs/tasks/014-testing-infrastructure.md`.
[x] Estado exacto: completada; `src/testing/` contiene helpers genericos para fixtures, goldens con diff legible y roundtrip parser/writer; `tests/support/` expone wrappers de integracion y la suite cubre fixtures validos/invalidos, roundtrip y property tests de escaping.
[x] Archivos tocados: `Cargo.toml`, `Cargo.lock`, `.gitignore`, `README.md`, `src/testing/mod.rs`, `src/writer/mod.rs`, `src/parser/mod.rs`, `tests/support/mod.rs`, `tests/testing_infrastructure.rs`, `tests/README.md`, `tests/fixtures/xml/*.xml`, `fuzz/README.md`, `fuzz/fuzz_targets/parser.rs`, `docs/tasks/014-testing-infrastructure.md`, `docs/tasks/README.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: se agrego `proptest` solo como `dev-dependency` con `default-features = false` y `features = ["std"]` para evitar dependencias de fork/tempfile; el fuzz target queda preparado fuera del workspace para no crear crates nuevas del motor; los fixtures siguen siendo genericos y sin dominios.
[x] Ajuste encontrado durante verificacion: el roundtrip de processing instructions acumulaba espacios porque el parser conservaba el separador antes del contenido; se normalizo solo ese separador sintactico y se agrego test de roundtrip.
[x] Comandos ejecutados: `cargo add proptest --dev --package xdoc-rs`; `cargo test testing` (fallo inicial por estrategia `char` de `proptest` y luego por PI/texto vacio); `cargo test golden` (fallo inicial por el mismo error de compilacion); `cargo test roundtrip` (fallo inicial por el mismo error de compilacion); `cargo fmt --all`; `cargo test testing`; `cargo test golden`; `cargo test roundtrip`; `cargo tree -p xdoc-rs -i proptest`; `rg -n "wasip3|libfuzzer|rusty-fork|tempfile|proptest" Cargo.lock Cargo.toml`; `cargo fmt --all -- --check`; `if rg -n "DIAN|UBL|SOAP|facturacion|Factura|dian" src/testing tests fuzz; then exit 1; else exit 0; fi`; `git diff --check`; `cargo check`; `cargo test`.
[x] Verificacion: los filtros `testing`, `golden` y `roundtrip`, formato, whitespace, check general y suite completa terminaron con codigo `0`; `cargo tree` confirma que `proptest` solo cuelga como dev-dependency de `xdoc-rs`; la busqueda de dependencias no encontro `wasip3`, `libfuzzer`, `rusty-fork` ni `tempfile` en `Cargo.lock`; la busqueda anti-dominio no encontro acoplamiento en la nueva infraestructura.
[x] Siguiente paso recomendado: continuar con `015 - CLI` o, si se quiere cerrar hardening transversal primero, ejecutar `018k - Advanced Testing Fixtures`.
### Tarea 015 - CLI
[x] Tarea actual: `docs/tasks/015-cli.md`.
[x] Estado exacto: completada; el binario `xdoc` vive en `crates/xdoc-cli` y soporta `format`, `compact`, `parse`, `query`, `validate`, `canonicalize`, `validate-wellformed` y `--help`.
[x] Archivos tocados: `crates/xdoc-cli/src/main.rs`, `tests/fixtures/contracts/simple-list.toml`, `tests/README.md`, `README.md`, `docs/tasks/015-cli.md`, `docs/tasks/README.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: se mantiene `xdoc-cli` como package auxiliar permitido para publicacion independiente; no se crea `src/bin/xdoc.rs`; el contrato de `validate` usa un TOML minimo parseado manualmente para no agregar dependencias CLI, y se traduce a `XmlContract`; `canonicalize` usa la API generica de `src/signature/`.
[x] Comandos ejecutados: `cargo fmt --all`; `cargo test -p xdoc-cli`; `cargo run -p xdoc-cli -- --help`; `cargo run -p xdoc-cli -- format tests/fixtures/xml/simple.xml`; `cargo run -p xdoc-cli -- query tests/fixtures/xml/simple.xml "/Root/Item[@code='B']/text()"`; `cargo run -p xdoc-cli -- validate tests/fixtures/xml/simple.xml tests/fixtures/contracts/simple-list.toml`; `cargo run -p xdoc-cli -- parse tests/fixtures/xml/simple.xml`; `cargo run -p xdoc-cli -- canonicalize tests/fixtures/xml/simple.xml`; `cargo run -p xdoc-cli -- parse tests/fixtures/xml/mismatched_tags.xml; test $? -ne 0`; `cargo fmt --all -- --check`; `cargo check`; `cargo test -p xdoc-cli`; `if rg -n "DIAN|UBL|SOAP|facturacion|Factura|dian" crates/xdoc-cli tests/fixtures/contracts; then exit 1; else exit 0; fi`; `git diff --check`; `cargo test`; `cargo clippy --workspace --all-targets -- -D warnings`; `cargo clippy -p xdoc-cli --all-targets -- -D warnings`.
[x] Verificacion: tests unitarios del CLI, comandos manuales, formato, check general, suite completa, whitespace y anti-dominio terminaron con codigo `0`; el caso XML invalido produjo error legible y exit code distinto de cero. Los comandos de clippy fallaron por lints existentes fuera del CLI en `src/signature/profiles.rs`, `src/signature/signer.rs` y `src/signature/validation_profile.rs`; no se corrigieron en esta tarea para no mezclar alcance.
[x] Siguiente paso recomendado: continuar con `016 - Quality Gate`.
### Documentacion detallada de libreria
[x] Tarea actual: documentacion solicitada por el usuario para separar la libreria por archivo y por feature.
[x] Estado exacto: completada; se agrego un hub de documentacion de la libreria, una guia por feature, una guia por archivo y una pagina dedicada a firma/canonicalizacion/XMLDSig/XAdES.
[x] Archivos tocados: `README.md`, `docs/library/README.md`, `docs/library/features.md`, `docs/library/files.md`, `docs/library/signature.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: en esta documentacion `feature` significa area funcional de la libreria, no `Cargo.toml [features]`; la documentacion mantiene el alcance del motor generico y ubica cualquier ejemplo de interoperabilidad de firma fuera de `src/`; firma se documenta aparte porque sus limites, invariantes y dependencias criptograficas son mas delicados.
[x] Comandos ejecutados: `git status --short`; `sed -n '1,220p' docs/context.md`; `sed -n '1,260p' docs/instructions.md`; `sed -n '1,260p' docs/tasks/README.md`; `rg --files src crates examples tests fuzz docs | sort`; `rg -n "^pub (struct|enum|trait|type|const|fn)|^ pub fn|^ pub const fn|^impl .* \\{|^pub use" src crates/xdoc-macros/src crates/xdoc-cli/src/main.rs`; `sed -n '1,260p' examples/generate_xml.rs`; `sed -n '1,220p' tests/compile/pass/xml_macro_pass.rs`; `rg -n "SignaturePolicy::from_file|with_digest_algorithm|strings\\(\\)" docs/library README.md`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `git diff --check`; `git status --short`.
[x] Verificacion: formato, check general, suite completa y whitespace terminaron con codigo `0`; `cargo test` paso con 260 tests unitarios del runtime, 11 del CLI, 11 de `xdoc-macros`, compile tests y tests de infraestructura. Durante `cargo test` aparecio un warning preexistente de OpenSSL en `src/signature/key.rs` por `Asn1StringRef::as_utf8`, sin fallo de suite.
[x] Siguiente paso recomendado: continuar con `016 - Quality Gate`, donde conviene decidir si se corrigen los warnings/lints conocidos antes de cerrar el motor para publicacion.
### Ajuste documentacion por feature como archivos separados
[x] Tarea actual: correccion de estructura documental solicitada por el usuario; cada feature debe representarse en un archivo propio.
[x] Estado exacto: completada; `docs/library/features.md` queda como indice y cada feature tiene su Markdown dedicado.
[x] Archivos tocados: `docs/library/README.md`, `docs/library/features.md`, `docs/library/core.md`, `docs/library/builder.md`, `docs/library/component.md`, `docs/library/macros.md`, `docs/library/writer.md`, `docs/library/parser.md`, `docs/library/query.md`, `docs/library/transform.md`, `docs/library/schema.md`, `docs/library/security.md`, `docs/library/signature.md`, `docs/library/testing.md`, `docs/library/cli.md`, `docs/library/files.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: se conserva `features.md` como tabla de contenido para no romper el enlace existente del README; `signature.md` queda como el archivo propio de la feature Signature por su detalle especial.
[x] Comandos ejecutados: `git status --short`; `sed -n '1,220p' docs/context.md`; `sed -n '1,220p' docs/instructions.md`; `sed -n '1,220p' docs/tasks/README.md`; `find docs/library -maxdepth 1 -type f -printf '%f\n' | sort`; `rg -n "\\[[^\\]]+\\]\\([^\\)]+\\.md\\)" docs/library README.md`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `git diff --check`.
[x] Verificacion: formato, check general, suite completa y whitespace terminaron con codigo `0`; `cargo test` paso con 260 tests unitarios del runtime, 11 del CLI, 11 de `xdoc-macros`, compile tests y tests de infraestructura. Se mantiene el warning preexistente de OpenSSL en `src/signature/key.rs` por `Asn1StringRef::as_utf8`.
[x] Siguiente paso recomendado: continuar con `016 - Quality Gate`, incluyendo la limpieza de warnings/lints conocidos si se decide cerrar el motor para publicacion.
### Ampliacion de documentacion para usuario final
[x] Tarea actual: convertir la documentacion por feature en guias de aprendizaje para usuarios finales.
[x] Estado exacto: completada; la documentacion ahora explica que problema resuelve cada feature, como empezar, ejemplos progresivos, patrones recomendados, errores comunes y siguientes lecturas.
[x] Archivos tocados: `docs/library/README.md`, `docs/library/features.md`, `docs/library/core.md`, `docs/library/builder.md`, `docs/library/component.md`, `docs/library/macros.md`, `docs/library/writer.md`, `docs/library/parser.md`, `docs/library/query.md`, `docs/library/transform.md`, `docs/library/schema.md`, `docs/library/security.md`, `docs/library/signature.md`, `docs/library/testing.md`, `docs/library/cli.md`, `docs/library/files.md`, `docs/worklogs.md`.
[x] Decisiones tomadas: se mantiene un archivo por feature, pero cada archivo pasa de referencia corta a guia practica; firma conserva detalle tecnico y agrega flujo de uso con PFX, EPES, placement, SigningTime y verificacion; los ejemplos siguen siendo genericos y sin reglas de dominio en el motor.
[x] Comandos ejecutados: `git status --short`; `sed -n '1,220p' docs/context.md`; `sed -n '1,220p' docs/instructions.md`; `sed -n '1,220p' docs/tasks/README.md`; `rg -n 'Template::element\\(\"[^\"]*:[^\"]*\"|with_digest_algorithm|vec!\\[\"one\"\\.to_owned\\(\\)\\]|assert_document_matches_golden\\(|SignaturePolicy::from_file\\(' docs/library`; `rg -n "\\[[^\\]]+\\]\\([^\\)]+\\.md\\)" docs/library README.md`; `cargo fmt --all -- --check`; `cargo check`; `cargo test`; `git diff --check`.
[x] Verificacion: formato, check general, suite completa y whitespace terminaron con codigo `0`; `cargo test` paso con 260 tests unitarios del runtime, 11 del CLI, 11 de `xdoc-macros`, compile tests y tests de infraestructura. Se mantiene el warning preexistente de OpenSSL en `src/signature/key.rs` por `Asn1StringRef::as_utf8`.
[x] Siguiente paso recomendado: continuar con `016 - Quality Gate`; ahi conviene resolver el warning de OpenSSL y los lints conocidos antes de publicacion.