xdoc-rs 0.1.0

Declarative XML engine for Rust
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
# 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.