fenolite 0.0.1.dev0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1636) hide show
  1. fenolite-0.2.0/.gitignore +35 -0
  2. fenolite-0.2.0/CHANGELOG.md +139 -0
  3. fenolite-0.2.0/CONTRIBUTING.md +64 -0
  4. fenolite-0.2.0/LEGAL-ANNEX.md +75 -0
  5. fenolite-0.2.0/LEGAL.md +48 -0
  6. fenolite-0.2.0/PKG-INFO +176 -0
  7. fenolite-0.2.0/README.md +131 -0
  8. fenolite-0.2.0/docs/adr/0002-kicad-file-backend.md +58 -0
  9. fenolite-0.2.0/docs/adr/0003-clean-room-and-provenance.md +51 -0
  10. fenolite-0.2.0/docs/adr/0005-sheet-templates.md +59 -0
  11. fenolite-0.2.0/docs/adr/0006-specctra-and-freerouting.md +72 -0
  12. fenolite-0.2.0/docs/adr/README.md +43 -0
  13. fenolite-0.2.0/docs/altium.md +964 -0
  14. fenolite-0.2.0/docs/analyses.md +218 -0
  15. fenolite-0.2.0/docs/assembly.md +320 -0
  16. fenolite-0.2.0/docs/catalog/README.md +95 -0
  17. fenolite-0.2.0/docs/catalog/coverage.md +118 -0
  18. fenolite-0.2.0/docs/catalog/previews/c0076-all-49-symbols-page1.svg +403 -0
  19. fenolite-0.2.0/docs/catalog/previews/c0076-all-49-symbols-page2.svg +478 -0
  20. fenolite-0.2.0/docs/catalog/previews/c0076-all-49-symbols-page3.svg +259 -0
  21. fenolite-0.2.0/docs/catalog/previews/c0076-all-49-symbols.svg +1134 -0
  22. fenolite-0.2.0/docs/catalog/previews/c0076-current-gallery-page1.svg +227 -0
  23. fenolite-0.2.0/docs/catalog/previews/c0076-current-gallery-page2.svg +186 -0
  24. fenolite-0.2.0/docs/catalog/previews/c0076-current-gallery-page3.svg +534 -0
  25. fenolite-0.2.0/docs/catalog/previews/c0076-current-gallery-page4.svg +304 -0
  26. fenolite-0.2.0/docs/catalog/previews/c0076-current-gallery-page5.svg +299 -0
  27. fenolite-0.2.0/docs/catalog/previews/c0076-current-gallery.svg +1538 -0
  28. fenolite-0.2.0/docs/catalog/previews/c0076-final-eight.svg +64 -0
  29. fenolite-0.2.0/docs/catalog/previews/c0076-final-three-discretes.svg +24 -0
  30. fenolite-0.2.0/docs/catalog/previews/c0076-first-seven.svg +75 -0
  31. fenolite-0.2.0/docs/catalog/previews/c0076-five-qfn.svg +173 -0
  32. fenolite-0.2.0/docs/catalog/previews/c0076-five-soic.svg +125 -0
  33. fenolite-0.2.0/docs/catalog/previews/c0076-new-20-symbols-page1.svg +178 -0
  34. fenolite-0.2.0/docs/catalog/previews/c0076-new-20-symbols-page2.svg +364 -0
  35. fenolite-0.2.0/docs/catalog/previews/c0076-new-20-symbols.svg +539 -0
  36. fenolite-0.2.0/docs/catalog/previews/c0076-next-seven.svg +51 -0
  37. fenolite-0.2.0/docs/catalog/previews/c0076-nine-small-outline.svg +183 -0
  38. fenolite-0.2.0/docs/catalog/previews/c0076-seven-dip.svg +134 -0
  39. fenolite-0.2.0/docs/catalog/previews/c0076-seven-more-ic.svg +383 -0
  40. fenolite-0.2.0/docs/catalog/previews/c0076-seven-passives.svg +49 -0
  41. fenolite-0.2.0/docs/catalog/previews/c0076-six-discretes.svg +46 -0
  42. fenolite-0.2.0/docs/catalog/previews/c0076-three-compact-sot.svg +27 -0
  43. fenolite-0.2.0/docs/catalog/previews/c0076-twelve-connectors.svg +130 -0
  44. fenolite-0.2.0/docs/catalog/sources.md +205 -0
  45. fenolite-0.2.0/docs/catalog/target-100-footprints.md +148 -0
  46. fenolite-0.2.0/docs/catalog/target-20-symbols.md +42 -0
  47. fenolite-0.2.0/docs/cli-contract.md +1723 -0
  48. fenolite-0.2.0/docs/copper.md +257 -0
  49. fenolite-0.2.0/docs/design-model.md +331 -0
  50. fenolite-0.2.0/docs/dsl.md +827 -0
  51. fenolite-0.2.0/docs/equivalence.md +168 -0
  52. fenolite-0.2.0/docs/evidence/README.md +35 -0
  53. fenolite-0.2.0/docs/evidence/altium-pcb-read.md +109 -0
  54. fenolite-0.2.0/docs/evidence/altium-pcb.md +419 -0
  55. fenolite-0.2.0/docs/evidence/altium-project-read.md +127 -0
  56. fenolite-0.2.0/docs/evidence/altium-read-schematic.md +336 -0
  57. fenolite-0.2.0/docs/evidence/altium-roundtrip.md +272 -0
  58. fenolite-0.2.0/docs/evidence/altium-schematic.md +697 -0
  59. fenolite-0.2.0/docs/evidence/board-analyses.md +57 -0
  60. fenolite-0.2.0/docs/evidence/copper-check.md +86 -0
  61. fenolite-0.2.0/docs/evidence/equivalence-triangle.md +176 -0
  62. fenolite-0.2.0/docs/evidence/kicad/probes/10.0.6.json +552 -0
  63. fenolite-0.2.0/docs/evidence/kicad/probes/9.0.9.json +465 -0
  64. fenolite-0.2.0/docs/evidence/kicad/token-fuzz/10.0.6.json +2017 -0
  65. fenolite-0.2.0/docs/evidence/kicad/token-fuzz/9.0.9.json +1931 -0
  66. fenolite-0.2.0/docs/evidence/kicad-board-read.md +139 -0
  67. fenolite-0.2.0/docs/evidence/kicad-check.md +322 -0
  68. fenolite-0.2.0/docs/evidence/kicad-export.md +46 -0
  69. fenolite-0.2.0/docs/evidence/kicad-fill.md +24 -0
  70. fenolite-0.2.0/docs/evidence/kicad-fmt-identity.md +80 -0
  71. fenolite-0.2.0/docs/evidence/kicad-frame.md +99 -0
  72. fenolite-0.2.0/docs/evidence/kicad-libs.md +141 -0
  73. fenolite-0.2.0/docs/evidence/kicad-project.md +31 -0
  74. fenolite-0.2.0/docs/evidence/kicad-rt2.md +85 -0
  75. fenolite-0.2.0/docs/evidence/kicad-schematic.md +411 -0
  76. fenolite-0.2.0/docs/evidence/matrix.md +341 -0
  77. fenolite-0.2.0/docs/evidence/residue-history.md +12 -0
  78. fenolite-0.2.0/docs/evidence/routing/freerouting-2.4.1.json +36 -0
  79. fenolite-0.2.0/docs/evidence/routing.md +98 -0
  80. fenolite-0.2.0/docs/evidence/sources.md +312 -0
  81. fenolite-0.2.0/docs/exports.md +272 -0
  82. fenolite-0.2.0/docs/formats/README.md +12 -0
  83. fenolite-0.2.0/docs/formats/altium/compound-file.md +189 -0
  84. fenolite-0.2.0/docs/formats/altium/connectivity.md +130 -0
  85. fenolite-0.2.0/docs/formats/altium/import.md +144 -0
  86. fenolite-0.2.0/docs/formats/altium/output-job.md +36 -0
  87. fenolite-0.2.0/docs/formats/altium/pcb-bodies.md +50 -0
  88. fenolite-0.2.0/docs/formats/altium/pcb-copper.md +194 -0
  89. fenolite-0.2.0/docs/formats/altium/pcb-document.md +173 -0
  90. fenolite-0.2.0/docs/formats/altium/pcb-library.md +126 -0
  91. fenolite-0.2.0/docs/formats/altium/pcb-read.md +292 -0
  92. fenolite-0.2.0/docs/formats/altium/pcb-records.md +115 -0
  93. fenolite-0.2.0/docs/formats/altium/project.md +178 -0
  94. fenolite-0.2.0/docs/formats/altium/rule-file.md +164 -0
  95. fenolite-0.2.0/docs/formats/altium/schematic-ascii.md +303 -0
  96. fenolite-0.2.0/docs/formats/altium/schematic-binary.md +137 -0
  97. fenolite-0.2.0/docs/formats/altium/schematic-library.md +299 -0
  98. fenolite-0.2.0/docs/formats/altium/schematic-records.md +892 -0
  99. fenolite-0.2.0/docs/formats/altium/sheet-template.md +149 -0
  100. fenolite-0.2.0/docs/formats/altium/stackup-file.md +32 -0
  101. fenolite-0.2.0/docs/formats/kicad/board.md +508 -0
  102. fenolite-0.2.0/docs/formats/kicad/cli.md +152 -0
  103. fenolite-0.2.0/docs/formats/kicad/copper.md +121 -0
  104. fenolite-0.2.0/docs/formats/kicad/corpus.md +122 -0
  105. fenolite-0.2.0/docs/formats/kicad/drc.md +171 -0
  106. fenolite-0.2.0/docs/formats/kicad/erc.md +63 -0
  107. fenolite-0.2.0/docs/formats/kicad/frame.md +48 -0
  108. fenolite-0.2.0/docs/formats/kicad/geometry.md +49 -0
  109. fenolite-0.2.0/docs/formats/kicad/gerber.md +26 -0
  110. fenolite-0.2.0/docs/formats/kicad/libraries.md +535 -0
  111. fenolite-0.2.0/docs/formats/kicad/project.md +187 -0
  112. fenolite-0.2.0/docs/formats/kicad/rules.md +243 -0
  113. fenolite-0.2.0/docs/formats/kicad/schematic.md +118 -0
  114. fenolite-0.2.0/docs/formats/kicad/sexpr.md +53 -0
  115. fenolite-0.2.0/docs/formats/kicad/tokens.md +338 -0
  116. fenolite-0.2.0/docs/formats/kicad/versions.md +116 -0
  117. fenolite-0.2.0/docs/formats/kicad/worksheet.md +80 -0
  118. fenolite-0.2.0/docs/formats/sheets.md +62 -0
  119. fenolite-0.2.0/docs/formats/specctra/dsn.md +108 -0
  120. fenolite-0.2.0/docs/formats/specctra/ses.md +41 -0
  121. fenolite-0.2.0/docs/formats/units.md +64 -0
  122. fenolite-0.2.0/docs/geometry.md +351 -0
  123. fenolite-0.2.0/docs/hypotheses.md +858 -0
  124. fenolite-0.2.0/docs/lens.md +452 -0
  125. fenolite-0.2.0/docs/placement.md +110 -0
  126. fenolite-0.2.0/docs/provenance.md +81 -0
  127. fenolite-0.2.0/docs/release/v0.1.md +121 -0
  128. fenolite-0.2.0/docs/release/v0.2.md +224 -0
  129. fenolite-0.2.0/docs/roadmap.md +523 -0
  130. fenolite-0.2.0/docs/routing.md +81 -0
  131. fenolite-0.2.0/docs/schematic.md +238 -0
  132. fenolite-0.2.0/docs/sheet-templates.md +149 -0
  133. fenolite-0.2.0/examples/README.md +16 -0
  134. fenolite-0.2.0/examples/altium_hier/design.py +51 -0
  135. fenolite-0.2.0/examples/altium_hier/partial.py +54 -0
  136. fenolite-0.2.0/examples/altium_hier_board/design.py +39 -0
  137. fenolite-0.2.0/examples/altium_hier_board/fp-lib-table +4 -0
  138. fenolite-0.2.0/examples/altium_hier_board/sym-lib-table +4 -0
  139. fenolite-0.2.0/examples/altium_kicad/FenoliteDemo.kicad_sym +686 -0
  140. fenolite-0.2.0/examples/altium_kicad/design.py +33 -0
  141. fenolite-0.2.0/examples/altium_kicad/no_connect.py +30 -0
  142. fenolite-0.2.0/examples/altium_kicad/sym-lib-table +4 -0
  143. fenolite-0.2.0/examples/altium_sample/design.py +42 -0
  144. fenolite-0.2.0/examples/blink_2layer/design.py +33 -0
  145. fenolite-0.2.0/examples/blink_2layer/fp-lib-table +4 -0
  146. fenolite-0.2.0/examples/blink_2layer/sym-lib-table +4 -0
  147. fenolite-0.2.0/examples/blink_official/design.py +34 -0
  148. fenolite-0.2.0/examples/blink_routed/design.py +62 -0
  149. fenolite-0.2.0/examples/blink_routed/fp-lib-table +4 -0
  150. fenolite-0.2.0/examples/blink_routed/sym-lib-table +4 -0
  151. fenolite-0.2.0/examples/board_40parts/design.py +68 -0
  152. fenolite-0.2.0/examples/board_40parts/fp-lib-table +4 -0
  153. fenolite-0.2.0/examples/board_40parts/sym-lib-table +4 -0
  154. fenolite-0.2.0/pyproject.toml +115 -0
  155. fenolite-0.2.0/schemas/fenolite.artifacts.v0.json +281 -0
  156. fenolite-0.2.0/schemas/fenolite.envelope.v0.json +240 -0
  157. fenolite-0.2.0/schemas/fenolite.model.v0/board.json +1653 -0
  158. fenolite-0.2.0/schemas/fenolite.model.v0/circuit.json +616 -0
  159. fenolite-0.2.0/schemas/fenolite.model.v0/drawing_sheet.json +428 -0
  160. fenolite-0.2.0/schemas/fenolite.model.v0/library.json +863 -0
  161. fenolite-0.2.0/schemas/fenolite.model.v0/rules.json +292 -0
  162. fenolite-0.2.0/schemas/fenolite.model.v0/schematic.json +952 -0
  163. fenolite-0.2.0/src/fenolite/__init__.py +7 -0
  164. fenolite-0.2.0/src/fenolite/analysis/PROVENANCE.md +15 -0
  165. fenolite-0.2.0/src/fenolite/analysis/__init__.py +19 -0
  166. fenolite-0.2.0/src/fenolite/analysis/boundary.py +133 -0
  167. fenolite-0.2.0/src/fenolite/analysis/codes.py +44 -0
  168. fenolite-0.2.0/src/fenolite/analysis/copper.py +172 -0
  169. fenolite-0.2.0/src/fenolite/analysis/current.py +290 -0
  170. fenolite-0.2.0/src/fenolite/analysis/distance.py +391 -0
  171. fenolite-0.2.0/src/fenolite/analysis/report.py +140 -0
  172. fenolite-0.2.0/src/fenolite/analysis/requirements.py +246 -0
  173. fenolite-0.2.0/src/fenolite/analysis/surface.py +648 -0
  174. fenolite-0.2.0/src/fenolite/analysis/views.py +537 -0
  175. fenolite-0.2.0/src/fenolite/backends/__init__.py +3 -0
  176. fenolite-0.2.0/src/fenolite/backends/altium/PROVENANCE.md +89 -0
  177. fenolite-0.2.0/src/fenolite/backends/altium/__init__.py +18 -0
  178. fenolite-0.2.0/src/fenolite/backends/altium/adapter/__init__.py +59 -0
  179. fenolite-0.2.0/src/fenolite/backends/altium/adapter/board.py +472 -0
  180. fenolite-0.2.0/src/fenolite/backends/altium/adapter/bodies.py +62 -0
  181. fenolite-0.2.0/src/fenolite/backends/altium/adapter/circuit.py +207 -0
  182. fenolite-0.2.0/src/fenolite/backends/altium/adapter/codes.py +115 -0
  183. fenolite-0.2.0/src/fenolite/backends/altium/adapter/connectivity.py +368 -0
  184. fenolite-0.2.0/src/fenolite/backends/altium/adapter/context.py +43 -0
  185. fenolite-0.2.0/src/fenolite/backends/altium/adapter/copper.py +699 -0
  186. fenolite-0.2.0/src/fenolite/backends/altium/adapter/evidence.py +12 -0
  187. fenolite-0.2.0/src/fenolite/backends/altium/adapter/ids.py +153 -0
  188. fenolite-0.2.0/src/fenolite/backends/altium/adapter/layers.py +252 -0
  189. fenolite-0.2.0/src/fenolite/backends/altium/adapter/library.py +241 -0
  190. fenolite-0.2.0/src/fenolite/backends/altium/adapter/netlist.py +910 -0
  191. fenolite-0.2.0/src/fenolite/backends/altium/adapter/pads.py +275 -0
  192. fenolite-0.2.0/src/fenolite/backends/altium/adapter/parts.py +184 -0
  193. fenolite-0.2.0/src/fenolite/backends/altium/adapter/pins.py +58 -0
  194. fenolite-0.2.0/src/fenolite/backends/altium/adapter/project.py +251 -0
  195. fenolite-0.2.0/src/fenolite/backends/altium/adapter/rules.py +98 -0
  196. fenolite-0.2.0/src/fenolite/backends/altium/adapter/units.py +130 -0
  197. fenolite-0.2.0/src/fenolite/backends/altium/altsym.py +331 -0
  198. fenolite-0.2.0/src/fenolite/backends/altium/ascii.py +113 -0
  199. fenolite-0.2.0/src/fenolite/backends/altium/backend.py +331 -0
  200. fenolite-0.2.0/src/fenolite/backends/altium/binary.py +109 -0
  201. fenolite-0.2.0/src/fenolite/backends/altium/cfb.py +345 -0
  202. fenolite-0.2.0/src/fenolite/backends/altium/claims.py +95 -0
  203. fenolite-0.2.0/src/fenolite/backends/altium/docboard.py +454 -0
  204. fenolite-0.2.0/src/fenolite/backends/altium/docset.py +164 -0
  205. fenolite-0.2.0/src/fenolite/backends/altium/hierarchy.py +345 -0
  206. fenolite-0.2.0/src/fenolite/backends/altium/import_evidence.py +50 -0
  207. fenolite-0.2.0/src/fenolite/backends/altium/layout.py +739 -0
  208. fenolite-0.2.0/src/fenolite/backends/altium/libboard.py +748 -0
  209. fenolite-0.2.0/src/fenolite/backends/altium/pcbdoc.py +1051 -0
  210. fenolite-0.2.0/src/fenolite/backends/altium/pcblib.py +466 -0
  211. fenolite-0.2.0/src/fenolite/backends/altium/pcbrecords.py +480 -0
  212. fenolite-0.2.0/src/fenolite/backends/altium/prjpcb.py +104 -0
  213. fenolite-0.2.0/src/fenolite/backends/altium/project.py +485 -0
  214. fenolite-0.2.0/src/fenolite/backends/altium/read/__init__.py +3 -0
  215. fenolite-0.2.0/src/fenolite/backends/altium/read/bodies.py +202 -0
  216. fenolite-0.2.0/src/fenolite/backends/altium/read/cfb.py +983 -0
  217. fenolite-0.2.0/src/fenolite/backends/altium/read/ini.py +141 -0
  218. fenolite-0.2.0/src/fenolite/backends/altium/read/outjob.py +157 -0
  219. fenolite-0.2.0/src/fenolite/backends/altium/read/pcb.py +700 -0
  220. fenolite-0.2.0/src/fenolite/backends/altium/read/pcblib.py +297 -0
  221. fenolite-0.2.0/src/fenolite/backends/altium/read/pcbprims.py +697 -0
  222. fenolite-0.2.0/src/fenolite/backends/altium/read/pcbprops.py +177 -0
  223. fenolite-0.2.0/src/fenolite/backends/altium/read/pcbstack.py +354 -0
  224. fenolite-0.2.0/src/fenolite/backends/altium/read/project.py +436 -0
  225. fenolite-0.2.0/src/fenolite/backends/altium/read/proptext.py +69 -0
  226. fenolite-0.2.0/src/fenolite/backends/altium/read/rul.py +84 -0
  227. fenolite-0.2.0/src/fenolite/backends/altium/read/rules.py +396 -0
  228. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/__init__.py +176 -0
  229. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/_build.py +342 -0
  230. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/_container.py +54 -0
  231. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/census.py +313 -0
  232. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/document.py +846 -0
  233. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/framing.py +97 -0
  234. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/issues.py +45 -0
  235. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/pins.py +172 -0
  236. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/props.py +200 -0
  237. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/records.py +1991 -0
  238. fenolite-0.2.0/src/fenolite/backends/altium/read/sch/units.py +105 -0
  239. fenolite-0.2.0/src/fenolite/backends/altium/read/schlib.py +619 -0
  240. fenolite-0.2.0/src/fenolite/backends/altium/read/scope.py +198 -0
  241. fenolite-0.2.0/src/fenolite/backends/altium/read/sheet.py +845 -0
  242. fenolite-0.2.0/src/fenolite/backends/altium/read/stackup.py +135 -0
  243. fenolite-0.2.0/src/fenolite/backends/altium/read/textfile.py +206 -0
  244. fenolite-0.2.0/src/fenolite/backends/altium/roundtrip.py +739 -0
  245. fenolite-0.2.0/src/fenolite/backends/altium/schdoc.py +511 -0
  246. fenolite-0.2.0/src/fenolite/backends/altium/schlib.py +294 -0
  247. fenolite-0.2.0/src/fenolite/backends/altium/symbols.py +112 -0
  248. fenolite-0.2.0/src/fenolite/backends/base.py +1008 -0
  249. fenolite-0.2.0/src/fenolite/backends/kicad/PROVENANCE.md +110 -0
  250. fenolite-0.2.0/src/fenolite/backends/kicad/__init__.py +105 -0
  251. fenolite-0.2.0/src/fenolite/backends/kicad/_fpmap.py +597 -0
  252. fenolite-0.2.0/src/fenolite/backends/kicad/_json.py +202 -0
  253. fenolite-0.2.0/src/fenolite/backends/kicad/_libread.py +212 -0
  254. fenolite-0.2.0/src/fenolite/backends/kicad/_pcbwrite.py +326 -0
  255. fenolite-0.2.0/src/fenolite/backends/kicad/altium_import.py +104 -0
  256. fenolite-0.2.0/src/fenolite/backends/kicad/backend.py +253 -0
  257. fenolite-0.2.0/src/fenolite/backends/kicad/bom.py +117 -0
  258. fenolite-0.2.0/src/fenolite/backends/kicad/canary.py +267 -0
  259. fenolite-0.2.0/src/fenolite/backends/kicad/claims.py +87 -0
  260. fenolite-0.2.0/src/fenolite/backends/kicad/cli.py +602 -0
  261. fenolite-0.2.0/src/fenolite/backends/kicad/copper.py +1092 -0
  262. fenolite-0.2.0/src/fenolite/backends/kicad/copperrules.py +126 -0
  263. fenolite-0.2.0/src/fenolite/backends/kicad/data/altium_import_exclusions.toml +74 -0
  264. fenolite-0.2.0/src/fenolite/backends/kicad/data/libraries.toml +42 -0
  265. fenolite-0.2.0/src/fenolite/backends/kicad/data/project_template_10.json +680 -0
  266. fenolite-0.2.0/src/fenolite/backends/kicad/data/project_template_9.json +664 -0
  267. fenolite-0.2.0/src/fenolite/backends/kicad/data/tokens.toml +2324 -0
  268. fenolite-0.2.0/src/fenolite/backends/kicad/drc.py +179 -0
  269. fenolite-0.2.0/src/fenolite/backends/kicad/dru.py +536 -0
  270. fenolite-0.2.0/src/fenolite/backends/kicad/embed.py +393 -0
  271. fenolite-0.2.0/src/fenolite/backends/kicad/erc.py +333 -0
  272. fenolite-0.2.0/src/fenolite/backends/kicad/fields.py +147 -0
  273. fenolite-0.2.0/src/fenolite/backends/kicad/fill.py +130 -0
  274. fenolite-0.2.0/src/fenolite/backends/kicad/frame.py +828 -0
  275. fenolite-0.2.0/src/fenolite/backends/kicad/helpmatrix.py +158 -0
  276. fenolite-0.2.0/src/fenolite/backends/kicad/ipcd356.py +95 -0
  277. fenolite-0.2.0/src/fenolite/backends/kicad/layers.py +171 -0
  278. fenolite-0.2.0/src/fenolite/backends/kicad/libcache.py +240 -0
  279. fenolite-0.2.0/src/fenolite/backends/kicad/liberrors.py +68 -0
  280. fenolite-0.2.0/src/fenolite/backends/kicad/libs.py +801 -0
  281. fenolite-0.2.0/src/fenolite/backends/kicad/lowering.py +343 -0
  282. fenolite-0.2.0/src/fenolite/backends/kicad/mod.py +569 -0
  283. fenolite-0.2.0/src/fenolite/backends/kicad/netlist.py +214 -0
  284. fenolite-0.2.0/src/fenolite/backends/kicad/netnames.py +75 -0
  285. fenolite-0.2.0/src/fenolite/backends/kicad/oracle.py +683 -0
  286. fenolite-0.2.0/src/fenolite/backends/kicad/outline.py +195 -0
  287. fenolite-0.2.0/src/fenolite/backends/kicad/padnets.py +217 -0
  288. fenolite-0.2.0/src/fenolite/backends/kicad/parity_inputs.py +155 -0
  289. fenolite-0.2.0/src/fenolite/backends/kicad/pcb.py +2751 -0
  290. fenolite-0.2.0/src/fenolite/backends/kicad/plot.py +117 -0
  291. fenolite-0.2.0/src/fenolite/backends/kicad/pro.py +885 -0
  292. fenolite-0.2.0/src/fenolite/backends/kicad/proerrors.py +47 -0
  293. fenolite-0.2.0/src/fenolite/backends/kicad/projectset.py +240 -0
  294. fenolite-0.2.0/src/fenolite/backends/kicad/replace.py +185 -0
  295. fenolite-0.2.0/src/fenolite/backends/kicad/roundtrip.py +70 -0
  296. fenolite-0.2.0/src/fenolite/backends/kicad/rulemap.py +639 -0
  297. fenolite-0.2.0/src/fenolite/backends/kicad/sch.py +1468 -0
  298. fenolite-0.2.0/src/fenolite/backends/kicad/sch_netlist.py +439 -0
  299. fenolite-0.2.0/src/fenolite/backends/kicad/schgen.py +678 -0
  300. fenolite-0.2.0/src/fenolite/backends/kicad/schlayout.py +843 -0
  301. fenolite-0.2.0/src/fenolite/backends/kicad/sexpr.py +639 -0
  302. fenolite-0.2.0/src/fenolite/backends/kicad/slots.py +181 -0
  303. fenolite-0.2.0/src/fenolite/backends/kicad/sym.py +493 -0
  304. fenolite-0.2.0/src/fenolite/backends/kicad/symembed.py +372 -0
  305. fenolite-0.2.0/src/fenolite/backends/kicad/triad.py +70 -0
  306. fenolite-0.2.0/src/fenolite/backends/kicad/versions.py +817 -0
  307. fenolite-0.2.0/src/fenolite/backends/kicad/wks.py +1107 -0
  308. fenolite-0.2.0/src/fenolite/backends/kicad/zones.py +772 -0
  309. fenolite-0.2.0/src/fenolite/backends/matrix.py +386 -0
  310. fenolite-0.2.0/src/fenolite/backends/registry.py +63 -0
  311. fenolite-0.2.0/src/fenolite/backends/specctra/PROVENANCE.md +25 -0
  312. fenolite-0.2.0/src/fenolite/backends/specctra/__init__.py +13 -0
  313. fenolite-0.2.0/src/fenolite/backends/specctra/claims.py +23 -0
  314. fenolite-0.2.0/src/fenolite/backends/specctra/dsn.py +602 -0
  315. fenolite-0.2.0/src/fenolite/backends/specctra/lexer.py +243 -0
  316. fenolite-0.2.0/src/fenolite/backends/specctra/ses.py +374 -0
  317. fenolite-0.2.0/src/fenolite/catalog/__init__.py +1736 -0
  318. fenolite-0.2.0/src/fenolite/catalog/_symbol_expansion.py +434 -0
  319. fenolite-0.2.0/src/fenolite/checks/__init__.py +34 -0
  320. fenolite-0.2.0/src/fenolite/checks/assignment_compare.py +340 -0
  321. fenolite-0.2.0/src/fenolite/checks/clearance.py +241 -0
  322. fenolite-0.2.0/src/fenolite/checks/codes.py +144 -0
  323. fenolite-0.2.0/src/fenolite/checks/containers.py +109 -0
  324. fenolite-0.2.0/src/fenolite/checks/copper.py +701 -0
  325. fenolite-0.2.0/src/fenolite/checks/diff.py +445 -0
  326. fenolite-0.2.0/src/fenolite/checks/documents.py +223 -0
  327. fenolite-0.2.0/src/fenolite/checks/drc.py +97 -0
  328. fenolite-0.2.0/src/fenolite/checks/drc_json.py +142 -0
  329. fenolite-0.2.0/src/fenolite/checks/equivalence/__init__.py +41 -0
  330. fenolite-0.2.0/src/fenolite/checks/equivalence/codes.py +74 -0
  331. fenolite-0.2.0/src/fenolite/checks/equivalence/exclusions.py +217 -0
  332. fenolite-0.2.0/src/fenolite/checks/equivalence/levels.py +412 -0
  333. fenolite-0.2.0/src/fenolite/checks/equivalence/model.py +148 -0
  334. fenolite-0.2.0/src/fenolite/checks/equivalence/norm.py +135 -0
  335. fenolite-0.2.0/src/fenolite/checks/erc.py +67 -0
  336. fenolite-0.2.0/src/fenolite/checks/erc_json.py +69 -0
  337. fenolite-0.2.0/src/fenolite/checks/erc_lite.py +70 -0
  338. fenolite-0.2.0/src/fenolite/checks/fill.py +95 -0
  339. fenolite-0.2.0/src/fenolite/checks/parity.py +304 -0
  340. fenolite-0.2.0/src/fenolite/checks/parity_stage.py +155 -0
  341. fenolite-0.2.0/src/fenolite/checks/render.py +35 -0
  342. fenolite-0.2.0/src/fenolite/checks/roundtrip.py +30 -0
  343. fenolite-0.2.0/src/fenolite/checks/rt2.py +252 -0
  344. fenolite-0.2.0/src/fenolite/checks/rta2.py +117 -0
  345. fenolite-0.2.0/src/fenolite/checks/stages.py +299 -0
  346. fenolite-0.2.0/src/fenolite/checks/validate.py +40 -0
  347. fenolite-0.2.0/src/fenolite/cli/_assembly.py +122 -0
  348. fenolite-0.2.0/src/fenolite/cli/_boardview.py +108 -0
  349. fenolite-0.2.0/src/fenolite/cli/_documents.py +149 -0
  350. fenolite-0.2.0/src/fenolite/cli/_examples.py +43 -0
  351. fenolite-0.2.0/src/fenolite/cli/_kicadtool.py +64 -0
  352. fenolite-0.2.0/src/fenolite/cli/_manifest.py +125 -0
  353. fenolite-0.2.0/src/fenolite/cli/_script.py +103 -0
  354. fenolite-0.2.0/src/fenolite/cli/api.py +111 -0
  355. fenolite-0.2.0/src/fenolite/cli/cmd__echo.py +61 -0
  356. fenolite-0.2.0/src/fenolite/cli/cmd_analyze.py +291 -0
  357. fenolite-0.2.0/src/fenolite/cli/cmd_bom.py +219 -0
  358. fenolite-0.2.0/src/fenolite/cli/cmd_build.py +861 -0
  359. fenolite-0.2.0/src/fenolite/cli/cmd_capabilities.py +145 -0
  360. fenolite-0.2.0/src/fenolite/cli/cmd_catalog.py +72 -0
  361. fenolite-0.2.0/src/fenolite/cli/cmd_check.py +228 -0
  362. fenolite-0.2.0/src/fenolite/cli/cmd_diff.py +276 -0
  363. fenolite-0.2.0/src/fenolite/cli/cmd_doctor.py +219 -0
  364. fenolite-0.2.0/src/fenolite/cli/cmd_equivalent.py +379 -0
  365. fenolite-0.2.0/src/fenolite/cli/cmd_explain.py +53 -0
  366. fenolite-0.2.0/src/fenolite/cli/cmd_export.py +179 -0
  367. fenolite-0.2.0/src/fenolite/cli/cmd_fill.py +149 -0
  368. fenolite-0.2.0/src/fenolite/cli/cmd_fmt.py +118 -0
  369. fenolite-0.2.0/src/fenolite/cli/cmd_inspect.py +353 -0
  370. fenolite-0.2.0/src/fenolite/cli/cmd_manifest.py +536 -0
  371. fenolite-0.2.0/src/fenolite/cli/cmd_neighbors.py +60 -0
  372. fenolite-0.2.0/src/fenolite/cli/cmd_net.py +60 -0
  373. fenolite-0.2.0/src/fenolite/cli/cmd_netlist.py +197 -0
  374. fenolite-0.2.0/src/fenolite/cli/cmd_pads.py +173 -0
  375. fenolite-0.2.0/src/fenolite/cli/cmd_parity.py +136 -0
  376. fenolite-0.2.0/src/fenolite/cli/cmd_place.py +405 -0
  377. fenolite-0.2.0/src/fenolite/cli/cmd_pnp.py +87 -0
  378. fenolite-0.2.0/src/fenolite/cli/cmd_region.py +80 -0
  379. fenolite-0.2.0/src/fenolite/cli/cmd_render.py +127 -0
  380. fenolite-0.2.0/src/fenolite/cli/cmd_restore.py +167 -0
  381. fenolite-0.2.0/src/fenolite/cli/cmd_roundtrip.py +234 -0
  382. fenolite-0.2.0/src/fenolite/cli/cmd_route.py +334 -0
  383. fenolite-0.2.0/src/fenolite/cli/cmd_sync.py +181 -0
  384. fenolite-0.2.0/src/fenolite/cli/cmd_template.py +174 -0
  385. fenolite-0.2.0/src/fenolite/cli/data/explain.toml +2148 -0
  386. fenolite-0.2.0/src/fenolite/cli/errors.py +168 -0
  387. fenolite-0.2.0/src/fenolite/cli/explain.py +147 -0
  388. fenolite-0.2.0/src/fenolite/cli/main.py +346 -0
  389. fenolite-0.2.0/src/fenolite/cli/output.py +287 -0
  390. fenolite-0.2.0/src/fenolite/core/ids.py +94 -0
  391. fenolite-0.2.0/src/fenolite/dsl/__init__.py +107 -0
  392. fenolite-0.2.0/src/fenolite/dsl/_minimal.py +13 -0
  393. fenolite-0.2.0/src/fenolite/dsl/convert.py +358 -0
  394. fenolite-0.2.0/src/fenolite/dsl/design.py +734 -0
  395. fenolite-0.2.0/src/fenolite/dsl/errors.py +12 -0
  396. fenolite-0.2.0/src/fenolite/dsl/footprint.py +183 -0
  397. fenolite-0.2.0/src/fenolite/dsl/intents.py +440 -0
  398. fenolite-0.2.0/src/fenolite/dsl/interfaces.py +222 -0
  399. fenolite-0.2.0/src/fenolite/dsl/module.py +76 -0
  400. fenolite-0.2.0/src/fenolite/dsl/part.py +441 -0
  401. fenolite-0.2.0/src/fenolite/dsl/quantity.py +226 -0
  402. fenolite-0.2.0/src/fenolite/dsl/select.py +86 -0
  403. fenolite-0.2.0/src/fenolite/dsl/symbol.py +195 -0
  404. fenolite-0.2.0/src/fenolite/dsl/units.py +156 -0
  405. fenolite-0.2.0/src/fenolite/exports/__init__.py +19 -0
  406. fenolite-0.2.0/src/fenolite/exports/assembly.py +491 -0
  407. fenolite-0.2.0/src/fenolite/exports/bom.py +270 -0
  408. fenolite-0.2.0/src/fenolite/exports/codes.py +53 -0
  409. fenolite-0.2.0/src/fenolite/exports/manifest.py +430 -0
  410. fenolite-0.2.0/src/fenolite/exports/placement.py +222 -0
  411. fenolite-0.2.0/src/fenolite/exports/plan.py +205 -0
  412. fenolite-0.2.0/src/fenolite/exports/preset.py +329 -0
  413. fenolite-0.2.0/src/fenolite/exports/states.py +229 -0
  414. fenolite-0.2.0/src/fenolite/geometry/__init__.py +112 -0
  415. fenolite-0.2.0/src/fenolite/geometry/boolean/__init__.py +57 -0
  416. fenolite-0.2.0/src/fenolite/geometry/boolean/_extra.py +30 -0
  417. fenolite-0.2.0/src/fenolite/geometry/boolean/base.py +77 -0
  418. fenolite-0.2.0/src/fenolite/geometry/boolean/fallback.py +64 -0
  419. fenolite-0.2.0/src/fenolite/geometry/errors.py +69 -0
  420. fenolite-0.2.0/src/fenolite/geometry/index.py +123 -0
  421. fenolite-0.2.0/src/fenolite/geometry/polygon.py +521 -0
  422. fenolite-0.2.0/src/fenolite/geometry/predicates.py +265 -0
  423. fenolite-0.2.0/src/fenolite/geometry/shapes.py +436 -0
  424. fenolite-0.2.0/src/fenolite/geometry/shelf.py +33 -0
  425. fenolite-0.2.0/src/fenolite/geometry/thick.py +402 -0
  426. fenolite-0.2.0/src/fenolite/geometry/transform.py +245 -0
  427. fenolite-0.2.0/src/fenolite/geometry/vector.py +76 -0
  428. fenolite-0.2.0/src/fenolite/lens/__init__.py +3 -0
  429. fenolite-0.2.0/src/fenolite/lens/altium.py +1364 -0
  430. fenolite-0.2.0/src/fenolite/lens/altium_copper.py +794 -0
  431. fenolite-0.2.0/src/fenolite/lens/build.py +1453 -0
  432. fenolite-0.2.0/src/fenolite/lens/extract.py +43 -0
  433. fenolite-0.2.0/src/fenolite/lens/fields.py +271 -0
  434. fenolite-0.2.0/src/fenolite/lens/moved.py +94 -0
  435. fenolite-0.2.0/src/fenolite/lens/placements.py +198 -0
  436. fenolite-0.2.0/src/fenolite/lens/preserve.py +1205 -0
  437. fenolite-0.2.0/src/fenolite/lens/schplacements.py +210 -0
  438. fenolite-0.2.0/src/fenolite/lens/sync.py +198 -0
  439. fenolite-0.2.0/src/fenolite/model/__init__.py +137 -0
  440. fenolite-0.2.0/src/fenolite/model/board.py +400 -0
  441. fenolite-0.2.0/src/fenolite/model/canonical.py +253 -0
  442. fenolite-0.2.0/src/fenolite/model/circuit.py +136 -0
  443. fenolite-0.2.0/src/fenolite/model/design.py +300 -0
  444. fenolite-0.2.0/src/fenolite/model/library.py +199 -0
  445. fenolite-0.2.0/src/fenolite/model/presentation.py +275 -0
  446. fenolite-0.2.0/src/fenolite/model/rules.py +118 -0
  447. fenolite-0.2.0/src/fenolite/model/schema.py +41 -0
  448. fenolite-0.2.0/src/fenolite/model/schematic.py +161 -0
  449. fenolite-0.2.0/src/fenolite/placement/__init__.py +16 -0
  450. fenolite-0.2.0/src/fenolite/placement/codes.py +40 -0
  451. fenolite-0.2.0/src/fenolite/placement/grid.py +117 -0
  452. fenolite-0.2.0/src/fenolite/placement/legality.py +240 -0
  453. fenolite-0.2.0/src/fenolite/routing/__init__.py +22 -0
  454. fenolite-0.2.0/src/fenolite/routing/codes.py +19 -0
  455. fenolite-0.2.0/src/fenolite/routing/direct.py +72 -0
  456. fenolite-0.2.0/src/fenolite/routing/merge.py +106 -0
  457. fenolite-0.2.0/src/fenolite/routing/plugins/kicad/routingtools.py +251 -0
  458. fenolite-0.2.0/src/fenolite/routing/plugins/specctra/freerouting.py +374 -0
  459. fenolite-0.2.0/src/fenolite/routing/protocol.py +109 -0
  460. fenolite-0.2.0/src/fenolite/routing/registry.py +67 -0
  461. fenolite-0.2.0/src/fenolite/routing/select.py +61 -0
  462. fenolite-0.2.0/src/fenolite/templates/PROVENANCE.md +13 -0
  463. fenolite-0.2.0/src/fenolite/templates/__init__.py +59 -0
  464. fenolite-0.2.0/src/fenolite/templates/build.py +186 -0
  465. fenolite-0.2.0/src/fenolite/templates/examples/iso5457_generic.sheet.toml +115 -0
  466. fenolite-0.2.0/src/fenolite/templates/examples/letter_generic.sheet.toml +106 -0
  467. fenolite-0.2.0/src/fenolite/templates/layout.py +154 -0
  468. fenolite-0.2.0/src/fenolite/templates/spec.py +587 -0
  469. fenolite-0.2.0/src/fenolite/verify/__init__.py +40 -0
  470. fenolite-0.2.0/src/fenolite/verify/evidence.py +55 -0
  471. fenolite-0.2.0/src/fenolite/verify/hypotheses.py +261 -0
  472. fenolite-0.2.0/tests/README.md +111 -0
  473. fenolite-0.2.0/tests/_acceptloop.py +113 -0
  474. fenolite-0.2.0/tests/_altium.py +466 -0
  475. fenolite-0.2.0/tests/_altium_built.py +62 -0
  476. fenolite-0.2.0/tests/_altium_copper.py +266 -0
  477. fenolite-0.2.0/tests/_altium_kicad.py +73 -0
  478. fenolite-0.2.0/tests/_altium_long.py +253 -0
  479. fenolite-0.2.0/tests/_altium_pcb_read.py +916 -0
  480. fenolite-0.2.0/tests/_altium_read.py +909 -0
  481. fenolite-0.2.0/tests/_altium_records.py +622 -0
  482. fenolite-0.2.0/tests/_altium_sch_build.py +203 -0
  483. fenolite-0.2.0/tests/_altium_sheet.py +315 -0
  484. fenolite-0.2.0/tests/_analysis.py +180 -0
  485. fenolite-0.2.0/tests/_assembly.py +90 -0
  486. fenolite-0.2.0/tests/_board_only.py +38 -0
  487. fenolite-0.2.0/tests/_boardcorpus.py +403 -0
  488. fenolite-0.2.0/tests/_boards.py +347 -0
  489. fenolite-0.2.0/tests/_build_judge.py +68 -0
  490. fenolite-0.2.0/tests/_build_preserve_variants.py +18 -0
  491. fenolite-0.2.0/tests/_buildhelp.py +197 -0
  492. fenolite-0.2.0/tests/_cfb_build.py +363 -0
  493. fenolite-0.2.0/tests/_cfb_read.py +396 -0
  494. fenolite-0.2.0/tests/_cliexamples.py +64 -0
  495. fenolite-0.2.0/tests/_copper.py +112 -0
  496. fenolite-0.2.0/tests/_coppercheck.py +422 -0
  497. fenolite-0.2.0/tests/_corpus.py +68 -0
  498. fenolite-0.2.0/tests/_drcrepeat.py +98 -0
  499. fenolite-0.2.0/tests/_erc.py +128 -0
  500. fenolite-0.2.0/tests/_fakecli.py +337 -0
  501. fenolite-0.2.0/tests/_fakefreerouting.py +104 -0
  502. fenolite-0.2.0/tests/_fakerouter.py +65 -0
  503. fenolite-0.2.0/tests/_fuzzmod.py +24 -0
  504. fenolite-0.2.0/tests/_gendesigns.py +238 -0
  505. fenolite-0.2.0/tests/_ipc.py +75 -0
  506. fenolite-0.2.0/tests/_kicad.py +69 -0
  507. fenolite-0.2.0/tests/_layout_edit.py +357 -0
  508. fenolite-0.2.0/tests/_lensfix.py +111 -0
  509. fenolite-0.2.0/tests/_libcensus.py +117 -0
  510. fenolite-0.2.0/tests/_libs.py +73 -0
  511. fenolite-0.2.0/tests/_minimum_bench.py +315 -0
  512. fenolite-0.2.0/tests/_netclass_bench.py +222 -0
  513. fenolite-0.2.0/tests/_netexport.py +88 -0
  514. fenolite-0.2.0/tests/_netlist.py +28 -0
  515. fenolite-0.2.0/tests/_paritycorpus.py +151 -0
  516. fenolite-0.2.0/tests/_parityedit.py +261 -0
  517. fenolite-0.2.0/tests/_placed.py +119 -0
  518. fenolite-0.2.0/tests/_preserve_help.py +75 -0
  519. fenolite-0.2.0/tests/_prodesigns.py +45 -0
  520. fenolite-0.2.0/tests/_project.py +119 -0
  521. fenolite-0.2.0/tests/_projects.py +239 -0
  522. fenolite-0.2.0/tests/_resources.py +152 -0
  523. fenolite-0.2.0/tests/_routed.py +95 -0
  524. fenolite-0.2.0/tests/_rulesdesign.py +42 -0
  525. fenolite-0.2.0/tests/_schbuild.py +210 -0
  526. fenolite-0.2.0/tests/_schcorpus.py +211 -0
  527. fenolite-0.2.0/tests/_schfix.py +86 -0
  528. fenolite-0.2.0/tests/_schprojects.py +132 -0
  529. fenolite-0.2.0/tests/_schtext.py +182 -0
  530. fenolite-0.2.0/tests/_specctra.py +67 -0
  531. fenolite-0.2.0/tests/_triangle.py +174 -0
  532. fenolite-0.2.0/tests/conftest.py +102 -0
  533. fenolite-0.2.0/tests/consistency/test_cli_consistency.py +252 -0
  534. fenolite-0.2.0/tests/corpus/manifest.toml +4441 -0
  535. fenolite-0.2.0/tests/corpus/test_altium_cfb.py +88 -0
  536. fenolite-0.2.0/tests/corpus/test_altium_documents.py +144 -0
  537. fenolite-0.2.0/tests/corpus/test_altium_import.py +351 -0
  538. fenolite-0.2.0/tests/corpus/test_altium_pcb_census.py +271 -0
  539. fenolite-0.2.0/tests/corpus/test_altium_pcb_rows.py +62 -0
  540. fenolite-0.2.0/tests/corpus/test_altium_roundtrip.py +131 -0
  541. fenolite-0.2.0/tests/corpus/test_altium_sch_read.py +232 -0
  542. fenolite-0.2.0/tests/corpus/test_altium_text.py +195 -0
  543. fenolite-0.2.0/tests/corpus/test_board_census.py +134 -0
  544. fenolite-0.2.0/tests/corpus/test_board_fields.py +137 -0
  545. fenolite-0.2.0/tests/corpus/test_board_read.py +44 -0
  546. fenolite-0.2.0/tests/corpus/test_board_rt1.py +36 -0
  547. fenolite-0.2.0/tests/corpus/test_copper_offset_census.py +91 -0
  548. fenolite-0.2.0/tests/corpus/test_copper_perf.py +72 -0
  549. fenolite-0.2.0/tests/corpus/test_demo_libs.py +172 -0
  550. fenolite-0.2.0/tests/corpus/test_fmt_idempotent.py +102 -0
  551. fenolite-0.2.0/tests/corpus/test_fmt_identity_9.py +85 -0
  552. fenolite-0.2.0/tests/corpus/test_footprint_rt.py +120 -0
  553. fenolite-0.2.0/tests/corpus/test_manifest.py +882 -0
  554. fenolite-0.2.0/tests/corpus/test_outline_census.py +62 -0
  555. fenolite-0.2.0/tests/corpus/test_outline_corpus.py +79 -0
  556. fenolite-0.2.0/tests/corpus/test_rt0.py +144 -0
  557. fenolite-0.2.0/tests/corpus/test_schdot_corpus.py +132 -0
  558. fenolite-0.2.0/tests/corpus/test_schematic_census.py +105 -0
  559. fenolite-0.2.0/tests/corpus/test_schematic_rt.py +89 -0
  560. fenolite-0.2.0/tests/corpus/test_wks_corpus.py +33 -0
  561. fenolite-0.2.0/tests/corpus/test_zone_clearance_census.py +123 -0
  562. fenolite-0.2.0/tests/data/MANIFEST.toml +1355 -0
  563. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t10/blink.kicad_dru +1 -0
  564. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t10/blink.kicad_pcb +852 -0
  565. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t10/blink.kicad_pro +708 -0
  566. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t10/fp-lib-table +4 -0
  567. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t10/lib/Mini.pretty/Mini_LED_THT_3mm.kicad_mod +127 -0
  568. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t10/lib/Mini.pretty/Mini_QFP-32_7x7mm_P0.8mm.kicad_mod +374 -0
  569. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t10/lib/Mini.pretty/Mini_R_0603.kicad_mod +134 -0
  570. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t9/blink.kicad_dru +1 -0
  571. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t9/blink.kicad_pcb +857 -0
  572. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t9/blink.kicad_pro +691 -0
  573. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t9/fp-lib-table +3 -0
  574. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t9/lib/Mini.pretty/Mini_LED_THT_3mm.kicad_mod +127 -0
  575. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t9/lib/Mini.pretty/Mini_QFP-32_7x7mm_P0.8mm.kicad_mod +374 -0
  576. fenolite-0.2.0/tests/data/acceptance/blink_2layer_t9/lib/Mini.pretty/Mini_R_0603.kicad_mod +134 -0
  577. fenolite-0.2.0/tests/data/acceptance/board_40parts_t10/board_40parts.kicad_dru +36 -0
  578. fenolite-0.2.0/tests/data/acceptance/board_40parts_t10/board_40parts.kicad_pcb +11239 -0
  579. fenolite-0.2.0/tests/data/acceptance/board_40parts_t10/board_40parts.kicad_pro +708 -0
  580. fenolite-0.2.0/tests/data/acceptance/board_40parts_t10/fp-lib-table +4 -0
  581. fenolite-0.2.0/tests/data/acceptance/board_40parts_t10/lib/Mini.pretty/Mini_LED_THT_3mm.kicad_mod +127 -0
  582. fenolite-0.2.0/tests/data/acceptance/board_40parts_t10/lib/Mini.pretty/Mini_QFP-32_7x7mm_P0.8mm.kicad_mod +374 -0
  583. fenolite-0.2.0/tests/data/acceptance/board_40parts_t10/lib/Mini.pretty/Mini_R_0603.kicad_mod +134 -0
  584. fenolite-0.2.0/tests/data/acceptance/board_40parts_t9/board_40parts.kicad_dru +36 -0
  585. fenolite-0.2.0/tests/data/acceptance/board_40parts_t9/board_40parts.kicad_pcb +11281 -0
  586. fenolite-0.2.0/tests/data/acceptance/board_40parts_t9/board_40parts.kicad_pro +691 -0
  587. fenolite-0.2.0/tests/data/acceptance/board_40parts_t9/fp-lib-table +3 -0
  588. fenolite-0.2.0/tests/data/acceptance/board_40parts_t9/lib/Mini.pretty/Mini_LED_THT_3mm.kicad_mod +127 -0
  589. fenolite-0.2.0/tests/data/acceptance/board_40parts_t9/lib/Mini.pretty/Mini_QFP-32_7x7mm_P0.8mm.kicad_mod +374 -0
  590. fenolite-0.2.0/tests/data/acceptance/board_40parts_t9/lib/Mini.pretty/Mini_R_0603.kicad_mod +134 -0
  591. fenolite-0.2.0/tests/data/altium/blink/blink.PcbDoc +0 -0
  592. fenolite-0.2.0/tests/data/altium/blink/blink.PcbLib +0 -0
  593. fenolite-0.2.0/tests/data/altium/blink/blink.PrjPcb +26 -0
  594. fenolite-0.2.0/tests/data/altium/blink/blink.SchDoc +0 -0
  595. fenolite-0.2.0/tests/data/altium/blink/blink.SchLib +0 -0
  596. fenolite-0.2.0/tests/data/altium/hier/FenoliteHier.SchLib +0 -0
  597. fenolite-0.2.0/tests/data/altium/hier/altium_hier.PrjPcb +29 -0
  598. fenolite-0.2.0/tests/data/altium/hier/altium_hier.SchDoc +0 -0
  599. fenolite-0.2.0/tests/data/altium/hier/altium_hier_flash.Harness +1 -0
  600. fenolite-0.2.0/tests/data/altium/hier/altium_hier_flash.SchDoc +0 -0
  601. fenolite-0.2.0/tests/data/altium/hier/altium_hier_mcu.Harness +1 -0
  602. fenolite-0.2.0/tests/data/altium/hier/altium_hier_mcu.SchDoc +0 -0
  603. fenolite-0.2.0/tests/data/altium/kicad_example/altium_kicad.PrjPcb +8 -0
  604. fenolite-0.2.0/tests/data/altium/kicad_example/altium_kicad.SchDoc +0 -0
  605. fenolite-0.2.0/tests/data/altium/kicad_example/altium_kicad.SchLib +0 -0
  606. fenolite-0.2.0/tests/data/altium/no_connect/altium_no_connect.PrjPcb +8 -0
  607. fenolite-0.2.0/tests/data/altium/no_connect/altium_no_connect.SchDoc +0 -0
  608. fenolite-0.2.0/tests/data/altium/no_connect/altium_no_connect.SchLib +0 -0
  609. fenolite-0.2.0/tests/data/altium/no_connect/ascii/altium_no_connect.SchDoc +57 -0
  610. fenolite-0.2.0/tests/data/altium/read/jobs.OutJob +41 -0
  611. fenolite-0.2.0/tests/data/altium/read/project_companions.PrjPcb +15 -0
  612. fenolite-0.2.0/tests/data/altium/read/project_crlf.PrjPcb +19 -0
  613. fenolite-0.2.0/tests/data/altium/read/project_utf8.PrjPcb +42 -0
  614. fenolite-0.2.0/tests/data/altium/read/rules_export.RUL +3 -0
  615. fenolite-0.2.0/tests/data/altium/read/rules_summary.RUL +4 -0
  616. fenolite-0.2.0/tests/data/altium/read/two_layer.stackup +1 -0
  617. fenolite-0.2.0/tests/data/altium/routed/routed.PcbDoc +0 -0
  618. fenolite-0.2.0/tests/data/altium/routed/routed.PcbLib +0 -0
  619. fenolite-0.2.0/tests/data/altium/routed/routed.PrjPcb +26 -0
  620. fenolite-0.2.0/tests/data/altium/routed/routed.SchDoc +0 -0
  621. fenolite-0.2.0/tests/data/altium/routed/routed.SchLib +0 -0
  622. fenolite-0.2.0/tests/data/altium/sample/FenoliteSample.SchLib +0 -0
  623. fenolite-0.2.0/tests/data/altium/sample/altium_sample.PrjPcb +8 -0
  624. fenolite-0.2.0/tests/data/altium/sample/altium_sample.SchDoc +123 -0
  625. fenolite-0.2.0/tests/data/altium/sample/binary/altium_sample.PrjPcb +8 -0
  626. fenolite-0.2.0/tests/data/altium/sample/binary/altium_sample.SchDoc +0 -0
  627. fenolite-0.2.0/tests/data/altium/sample/variants/altium_sample_lf.SchDoc +123 -0
  628. fenolite-0.2.0/tests/data/altium/sample/variants/altium_sample_nouid.SchDoc +123 -0
  629. fenolite-0.2.0/tests/data/analysis/requirements_example.toml +28 -0
  630. fenolite-0.2.0/tests/data/assembly/bom_export.csv +4 -0
  631. fenolite-0.2.0/tests/data/assembly/columns.toml +22 -0
  632. fenolite-0.2.0/tests/data/assembly/invalid.toml +13 -0
  633. fenolite-0.2.0/tests/data/assembly/rotated.toml +38 -0
  634. fenolite-0.2.0/tests/data/exports/manifest_v01.json +43 -0
  635. fenolite-0.2.0/tests/data/kicad/board/dimension.kicad_pcb +89 -0
  636. fenolite-0.2.0/tests/data/kicad/board/two_layer.kicad_pcb +331 -0
  637. fenolite-0.2.0/tests/data/kicad/drc/report_mils.json +19 -0
  638. fenolite-0.2.0/tests/data/kicad/drc/report_mm.json +45 -0
  639. fenolite-0.2.0/tests/data/kicad/erc/report_10.json +65 -0
  640. fenolite-0.2.0/tests/data/kicad/erc/report_9.json +40 -0
  641. fenolite-0.2.0/tests/data/kicad/fill/triad_t9.kicad_pcb +750 -0
  642. fenolite-0.2.0/tests/data/kicad/fill/triad_t9_filled.kicad_pcb +758 -0
  643. fenolite-0.2.0/tests/data/kicad/fill/triad_t9_refilled.kicad_pcb +809 -0
  644. fenolite-0.2.0/tests/data/kicad/netlist/export_10.net +218 -0
  645. fenolite-0.2.0/tests/data/kicad/netlist/export_9.net +57 -0
  646. fenolite-0.2.0/tests/data/kicad/parity/agree/blink.kicad_pcb +788 -0
  647. fenolite-0.2.0/tests/data/kicad/parity/agree/blink.kicad_sch +1856 -0
  648. fenolite-0.2.0/tests/data/kicad/project/empty_10.kicad_pro +680 -0
  649. fenolite-0.2.0/tests/data/kicad/routing/two_pads.kicad_pcb +87 -0
  650. fenolite-0.2.0/tests/data/kicad/rules/broken.kicad_dru +5 -0
  651. fenolite-0.2.0/tests/data/kicad/rules/comments.kicad_dru +17 -0
  652. fenolite-0.2.0/tests/data/kicad/rules/opaque.kicad_dru +17 -0
  653. fenolite-0.2.0/tests/data/kicad/rules/overlap.kicad_dru +9 -0
  654. fenolite-0.2.0/tests/data/kicad/rules/selectors.kicad_dru +42 -0
  655. fenolite-0.2.0/tests/data/kicad/rules/ten_only.kicad_dru +8 -0
  656. fenolite-0.2.0/tests/data/kicad/rules/units.kicad_dru +13 -0
  657. fenolite-0.2.0/tests/data/kicad/schematic/bus.kicad_sch +440 -0
  658. fenolite-0.2.0/tests/data/kicad/schematic/flat.kicad_sch +1866 -0
  659. fenolite-0.2.0/tests/data/kicad/schematic/flat_v9.kicad_sch +1732 -0
  660. fenolite-0.2.0/tests/data/kicad/schematic/hier/child.kicad_sch +450 -0
  661. fenolite-0.2.0/tests/data/kicad/schematic/hier/top.kicad_sch +323 -0
  662. fenolite-0.2.0/tests/data/kicad/schematic/hier_v9/child.kicad_sch +396 -0
  663. fenolite-0.2.0/tests/data/kicad/schematic/hier_v9/top.kicad_sch +295 -0
  664. fenolite-0.2.0/tests/data/kicad/schematic/multi/cell.kicad_sch +458 -0
  665. fenolite-0.2.0/tests/data/kicad/schematic/multi/top.kicad_sch +165 -0
  666. fenolite-0.2.0/tests/data/kicad/schematic/units.kicad_sch +743 -0
  667. fenolite-0.2.0/tests/data/kicad/schematic/units_v9.kicad_sch +692 -0
  668. fenolite-0.2.0/tests/data/kicad/sexpr/EXPECT.toml +252 -0
  669. fenolite-0.2.0/tests/data/kicad/sexpr/escapes.kicad_pcb +127 -0
  670. fenolite-0.2.0/tests/data/kicad/sexpr/minimal.kicad_pcb +27 -0
  671. fenolite-0.2.0/tests/data/kicad/sexpr/mirror/bare-symbols.kicad_pcb +27 -0
  672. fenolite-0.2.0/tests/data/kicad/sexpr/mirror/bom.kicad_pcb +27 -0
  673. fenolite-0.2.0/tests/data/kicad/sexpr/mirror/comment-line.kicad_pcb +28 -0
  674. fenolite-0.2.0/tests/data/kicad/sexpr/mirror/crlf.kicad_pcb +27 -0
  675. fenolite-0.2.0/tests/data/kicad/sexpr/mirror/empty.kicad_pcb +0 -0
  676. fenolite-0.2.0/tests/data/kicad/sexpr/mirror/glued-atom.kicad_pcb +27 -0
  677. fenolite-0.2.0/tests/data/kicad/sexpr/mirror/newline-in-string.kicad_pcb +38 -0
  678. fenolite-0.2.0/tests/data/kicad/sexpr/mirror/quote-in-atom.kicad_pcb +27 -0
  679. fenolite-0.2.0/tests/data/kicad/sexpr/mirror/unbalanced.kicad_pcb +27 -0
  680. fenolite-0.2.0/tests/data/kicad/sexpr/semantic/coord-negative-zero.kicad_pcb +27 -0
  681. fenolite-0.2.0/tests/data/kicad/sexpr/semantic/coord-over-precise.kicad_pcb +27 -0
  682. fenolite-0.2.0/tests/data/kicad/sexpr/semantic/width-exponent.kicad_pcb +27 -0
  683. fenolite-0.2.0/tests/data/kicad/sexpr/semantic/width-hex.kicad_pcb +27 -0
  684. fenolite-0.2.0/tests/data/kicad/sexpr/semantic/width-leading-dot.kicad_pcb +27 -0
  685. fenolite-0.2.0/tests/data/kicad/sexpr/semantic/width-plus-dot.kicad_pcb +27 -0
  686. fenolite-0.2.0/tests/data/kicad/sexpr/semantic/width-plus.kicad_pcb +27 -0
  687. fenolite-0.2.0/tests/data/kicad/sexpr/semantic/width-trailing-dot.kicad_pcb +27 -0
  688. fenolite-0.2.0/tests/data/kicad/sexpr/semantic/width-unit.kicad_pcb +27 -0
  689. fenolite-0.2.0/tests/data/kicad/sexpr/unmirrored/cr-in-string.kicad_pcb +27 -0
  690. fenolite-0.2.0/tests/data/kicad/sexpr/unmirrored/empty-list.kicad_pcb +28 -0
  691. fenolite-0.2.0/tests/data/kicad/sexpr/unmirrored/invalid-utf8.kicad_pcb +27 -0
  692. fenolite-0.2.0/tests/data/kicad/sexpr/unmirrored/list-starting-with-list.kicad_pcb +27 -0
  693. fenolite-0.2.0/tests/data/kicad/sexpr/unmirrored/too-deep.kicad_pcb +28 -0
  694. fenolite-0.2.0/tests/data/kicad/sexpr/unmirrored/trailing-content.kicad_pcb +28 -0
  695. fenolite-0.2.0/tests/data/kicad/sexpr/unmirrored/unterminated-string.kicad_pcb +25 -0
  696. fenolite-0.2.0/tests/data/kicad/sheets/all_items.kicad_wks +68 -0
  697. fenolite-0.2.0/tests/data/kicad/sheets/logo_1x1.png +0 -0
  698. fenolite-0.2.0/tests/data/kicad/sheets/probe_bitmap.kicad_wks +27 -0
  699. fenolite-0.2.0/tests/data/kicad/sheets/probe_bitmap_corrupt.kicad_wks +26 -0
  700. fenolite-0.2.0/tests/data/kicad/sheets/probe_broken.kicad_wks +18 -0
  701. fenolite-0.2.0/tests/data/kicad/sheets/probe_corners.kicad_wks +33 -0
  702. fenolite-0.2.0/tests/data/kicad/sheets/probe_notonpage1.kicad_wks +22 -0
  703. fenolite-0.2.0/tests/data/kicad/sheets/probe_page1only.kicad_wks +22 -0
  704. fenolite-0.2.0/tests/data/kicad/sheets/probe_percent.kicad_wks +25 -0
  705. fenolite-0.2.0/tests/data/kicad/sheets/probe_percent_legacy.kicad_wks +23 -0
  706. fenolite-0.2.0/tests/data/kicad/sheets/probe_pro.kicad_wks +21 -0
  707. fenolite-0.2.0/tests/data/kicad/sheets/probe_repeat.kicad_wks +37 -0
  708. fenolite-0.2.0/tests/data/kicad/sheets/probe_resolution.kicad_wks +22 -0
  709. fenolite-0.2.0/tests/data/kicad/sheets/probe_shape.kicad_wks +25 -0
  710. fenolite-0.2.0/tests/data/kicad/sheets/probe_tokens.kicad_wks +65 -0
  711. fenolite-0.2.0/tests/data/kicad/sheets/probe_undefined.kicad_wks +21 -0
  712. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_bold.kicad_wks +20 -0
  713. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_bottom.kicad_wks +18 -0
  714. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_center.kicad_wks +18 -0
  715. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_italic.kicad_wks +20 -0
  716. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_lbcorner.kicad_wks +17 -0
  717. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_left.kicad_wks +18 -0
  718. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_ltcorner.kicad_wks +17 -0
  719. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_notonpage1.kicad_wks +22 -0
  720. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_page1only.kicad_wks +18 -0
  721. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_rbcorner.kicad_wks +17 -0
  722. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_right.kicad_wks +18 -0
  723. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_rtcorner.kicad_wks +17 -0
  724. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_top.kicad_wks +18 -0
  725. fenolite-0.2.0/tests/data/kicad/sheets/probe_value_unknown.kicad_wks +17 -0
  726. fenolite-0.2.0/tests/data/kicad/sheets/sub_um.kicad_wks +20 -0
  727. fenolite-0.2.0/tests/data/kicad/tokens/canary/canary.kicad_dru +4 -0
  728. fenolite-0.2.0/tests/data/kicad/tokens/canary/canary.kicad_pcb +47 -0
  729. fenolite-0.2.0/tests/data/kicad/tokens/canary/canary.kicad_pro +1 -0
  730. fenolite-0.2.0/tests/data/kicad/tokens/drawing_sheet.kicad_wks +18 -0
  731. fenolite-0.2.0/tests/data/kicad/tokens/examples.toml +961 -0
  732. fenolite-0.2.0/tests/data/kicad/tokens/future.kicad_pcb +27 -0
  733. fenolite-0.2.0/tests/data/kicad/tokens/old/old.kicad_mod +24 -0
  734. fenolite-0.2.0/tests/data/kicad/tokens/old/old.kicad_pcb +30 -0
  735. fenolite-0.2.0/tests/data/kicad/tokens/old/old.kicad_sch +13 -0
  736. fenolite-0.2.0/tests/data/kicad/tokens/old/old.kicad_sym +39 -0
  737. fenolite-0.2.0/tests/data/kicad/tokens/page_layout.kicad_wks +16 -0
  738. fenolite-0.2.0/tests/data/kicad/tokens/skeleton.kicad_mod +52 -0
  739. fenolite-0.2.0/tests/data/kicad/tokens/skeleton.kicad_pcb +128 -0
  740. fenolite-0.2.0/tests/data/kicad/tokens/skeleton.kicad_sch +308 -0
  741. fenolite-0.2.0/tests/data/kicad/tokens/skeleton.kicad_sym +129 -0
  742. fenolite-0.2.0/tests/data/kicad/tokens/skeleton.kicad_wks +51 -0
  743. fenolite-0.2.0/tests/data/lens/acceptance/design.py +55 -0
  744. fenolite-0.2.0/tests/data/lens/acceptance/fp-lib-table +4 -0
  745. fenolite-0.2.0/tests/data/lens/acceptance/sym-lib-table +4 -0
  746. fenolite-0.2.0/tests/data/lens/sync_minimal/fp-lib-table +3 -0
  747. fenolite-0.2.0/tests/data/lens/sync_minimal/minimal.kicad_dru +1 -0
  748. fenolite-0.2.0/tests/data/lens/sync_minimal/minimal.kicad_pcb +75 -0
  749. fenolite-0.2.0/tests/data/lens/sync_minimal/minimal.kicad_pro +704 -0
  750. fenolite-0.2.0/tests/data/lens/sync_minimal/minimal.kicad_sch +13 -0
  751. fenolite-0.2.0/tests/data/lens/sync_minimal/sym-lib-table +3 -0
  752. fenolite-0.2.0/tests/data/libs/Escapes_v9.pretty/Mini_Escapes.kicad_mod +204 -0
  753. fenolite-0.2.0/tests/data/libs/Frame.pretty/Frame_Loop.kicad_mod +102 -0
  754. fenolite-0.2.0/tests/data/libs/Frame.pretty/Frame_NoCourtyard.kicad_mod +68 -0
  755. fenolite-0.2.0/tests/data/libs/Frame.pretty/Frame_Offset.kicad_mod +77 -0
  756. fenolite-0.2.0/tests/data/libs/Frame.pretty/Frame_OpenCourtyard.kicad_mod +92 -0
  757. fenolite-0.2.0/tests/data/libs/Frame.pretty/Frame_Round.kicad_mod +73 -0
  758. fenolite-0.2.0/tests/data/libs/Frame.pretty/Frame_Shapes.kicad_mod +111 -0
  759. fenolite-0.2.0/tests/data/libs/Frame.pretty/Frame_Trapezoid.kicad_mod +74 -0
  760. fenolite-0.2.0/tests/data/libs/Mini.kicad_sym +1557 -0
  761. fenolite-0.2.0/tests/data/libs/Mini.pretty/Mini_Edge_Cases.kicad_mod +144 -0
  762. fenolite-0.2.0/tests/data/libs/Mini.pretty/Mini_LED_THT_3mm.kicad_mod +128 -0
  763. fenolite-0.2.0/tests/data/libs/Mini.pretty/Mini_QFP-32_7x7mm_P0.8mm.kicad_mod +375 -0
  764. fenolite-0.2.0/tests/data/libs/Mini.pretty/Mini_R_0603.kicad_mod +135 -0
  765. fenolite-0.2.0/tests/data/libs/Mini_v9.kicad_sym +1401 -0
  766. fenolite-0.2.0/tests/data/libs/Mini_v9.pretty/Mini_LED_THT_3mm.kicad_mod +127 -0
  767. fenolite-0.2.0/tests/data/libs/Mini_v9.pretty/Mini_QFP-32_7x7mm_P0.8mm.kicad_mod +374 -0
  768. fenolite-0.2.0/tests/data/libs/Mini_v9.pretty/Mini_R_0603.kicad_mod +134 -0
  769. fenolite-0.2.0/tests/data/libs/project/fp-lib-table +9 -0
  770. fenolite-0.2.0/tests/data/libs/project/nested/fp-lib-table +3 -0
  771. fenolite-0.2.0/tests/data/libs/project/nested/sym-lib-table +3 -0
  772. fenolite-0.2.0/tests/data/libs/project/sym-lib-table +9 -0
  773. fenolite-0.2.0/tests/data/specctra/two_pads.dsn +69 -0
  774. fenolite-0.2.0/tests/data/specctra/two_pads.ses +37 -0
  775. fenolite-0.2.0/tests/kicad/_fpwrite.py +124 -0
  776. fenolite-0.2.0/tests/kicad/_libtables.py +243 -0
  777. fenolite-0.2.0/tests/kicad/_probes.py +361 -0
  778. fenolite-0.2.0/tests/kicad/acceptance/test_finished.py +280 -0
  779. fenolite-0.2.0/tests/kicad/altium/test_copper_from_oracle.py +223 -0
  780. fenolite-0.2.0/tests/kicad/altium/test_import_oracle.py +310 -0
  781. fenolite-0.2.0/tests/kicad/altium/test_pcbdoc_copper_oracle.py +264 -0
  782. fenolite-0.2.0/tests/kicad/altium/test_pcbdoc_oracle.py +169 -0
  783. fenolite-0.2.0/tests/kicad/altium/test_pcbdoc_read_oracle.py +335 -0
  784. fenolite-0.2.0/tests/kicad/altium/test_pcblib_oracle.py +221 -0
  785. fenolite-0.2.0/tests/kicad/altium/test_pcblib_read_oracle.py +133 -0
  786. fenolite-0.2.0/tests/kicad/altium/test_schlib_oracle.py +271 -0
  787. fenolite-0.2.0/tests/kicad/altium/test_schlib_read_oracle.py +213 -0
  788. fenolite-0.2.0/tests/kicad/altium/test_script_copper_oracle.py +207 -0
  789. fenolite-0.2.0/tests/kicad/analysis/_creepbench.py +113 -0
  790. fenolite-0.2.0/tests/kicad/analysis/test_creepage_bracket.py +35 -0
  791. fenolite-0.2.0/tests/kicad/assembly/_asmcases.py +405 -0
  792. fenolite-0.2.0/tests/kicad/assembly/test_assembly_oracle.py +131 -0
  793. fenolite-0.2.0/tests/kicad/assembly/test_bom_probes.py +58 -0
  794. fenolite-0.2.0/tests/kicad/board/_bench.py +134 -0
  795. fenolite-0.2.0/tests/kicad/board/_fieldbench.py +456 -0
  796. fenolite-0.2.0/tests/kicad/board/_fieldprobe.py +380 -0
  797. fenolite-0.2.0/tests/kicad/board/_frame.py +148 -0
  798. fenolite-0.2.0/tests/kicad/board/_triad.py +113 -0
  799. fenolite-0.2.0/tests/kicad/board/_upgrade.py +29 -0
  800. fenolite-0.2.0/tests/kicad/board/conftest.py +12 -0
  801. fenolite-0.2.0/tests/kicad/board/test_board_frame.py +89 -0
  802. fenolite-0.2.0/tests/kicad/board/test_board_loads.py +43 -0
  803. fenolite-0.2.0/tests/kicad/board/test_board_upgraded.py +146 -0
  804. fenolite-0.2.0/tests/kicad/board/test_cross_version.py +158 -0
  805. fenolite-0.2.0/tests/kicad/board/test_drc_report.py +33 -0
  806. fenolite-0.2.0/tests/kicad/board/test_field_oracle.py +150 -0
  807. fenolite-0.2.0/tests/kicad/board/test_field_probes.py +43 -0
  808. fenolite-0.2.0/tests/kicad/board/test_flip_oracle.py +95 -0
  809. fenolite-0.2.0/tests/kicad/board/test_genver.py +24 -0
  810. fenolite-0.2.0/tests/kicad/board/test_net_forms.py +53 -0
  811. fenolite-0.2.0/tests/kicad/board/test_triad.py +90 -0
  812. fenolite-0.2.0/tests/kicad/board/test_unknown_child.py +68 -0
  813. fenolite-0.2.0/tests/kicad/board/test_uuid_keep_written.py +31 -0
  814. fenolite-0.2.0/tests/kicad/build/_buildcases.py +271 -0
  815. fenolite-0.2.0/tests/kicad/build/_probe_boards.py +94 -0
  816. fenolite-0.2.0/tests/kicad/build/_vendorcases.py +371 -0
  817. fenolite-0.2.0/tests/kicad/build/test_build_oracle.py +63 -0
  818. fenolite-0.2.0/tests/kicad/build/test_build_probes.py +35 -0
  819. fenolite-0.2.0/tests/kicad/build/test_script_rules_oracle.py +73 -0
  820. fenolite-0.2.0/tests/kicad/build/test_vendor_oracle.py +70 -0
  821. fenolite-0.2.0/tests/kicad/build/test_vendor_probes.py +48 -0
  822. fenolite-0.2.0/tests/kicad/check/_checkcases.py +230 -0
  823. fenolite-0.2.0/tests/kicad/check/_checkrun.py +49 -0
  824. fenolite-0.2.0/tests/kicad/check/_drccases.py +194 -0
  825. fenolite-0.2.0/tests/kicad/check/_erccases.py +662 -0
  826. fenolite-0.2.0/tests/kicad/check/_fixtures.py +159 -0
  827. fenolite-0.2.0/tests/kicad/check/_limitbench.py +65 -0
  828. fenolite-0.2.0/tests/kicad/check/_netcases.py +92 -0
  829. fenolite-0.2.0/tests/kicad/check/_paritycases.py +258 -0
  830. fenolite-0.2.0/tests/kicad/check/test_canary.py +71 -0
  831. fenolite-0.2.0/tests/kicad/check/test_check_built.py +100 -0
  832. fenolite-0.2.0/tests/kicad/check/test_check_demos.py +92 -0
  833. fenolite-0.2.0/tests/kicad/check/test_check_oracle.py +109 -0
  834. fenolite-0.2.0/tests/kicad/check/test_copy_set.py +21 -0
  835. fenolite-0.2.0/tests/kicad/check/test_corpus_rt.py +102 -0
  836. fenolite-0.2.0/tests/kicad/check/test_drc_facts.py +51 -0
  837. fenolite-0.2.0/tests/kicad/check/test_drc_limit.py +54 -0
  838. fenolite-0.2.0/tests/kicad/check/test_erc_facts.py +90 -0
  839. fenolite-0.2.0/tests/kicad/check/test_erc_oracle.py +164 -0
  840. fenolite-0.2.0/tests/kicad/check/test_help_matrix.py +41 -0
  841. fenolite-0.2.0/tests/kicad/check/test_negatives.py +83 -0
  842. fenolite-0.2.0/tests/kicad/check/test_netlist_oracle.py +173 -0
  843. fenolite-0.2.0/tests/kicad/check/test_parity.py +92 -0
  844. fenolite-0.2.0/tests/kicad/check/test_parity_agreement.py +109 -0
  845. fenolite-0.2.0/tests/kicad/check/test_parity_probes.py +57 -0
  846. fenolite-0.2.0/tests/kicad/check/test_read_refused.py +50 -0
  847. fenolite-0.2.0/tests/kicad/check/test_roundtrip_cmd.py +73 -0
  848. fenolite-0.2.0/tests/kicad/check/test_rt2_stage.py +34 -0
  849. fenolite-0.2.0/tests/kicad/conftest.py +37 -0
  850. fenolite-0.2.0/tests/kicad/copper/_benches.py +250 -0
  851. fenolite-0.2.0/tests/kicad/copper/_copperparity.py +579 -0
  852. fenolite-0.2.0/tests/kicad/copper/test_copper_parity.py +92 -0
  853. fenolite-0.2.0/tests/kicad/copper/test_parity_bench.py +176 -0
  854. fenolite-0.2.0/tests/kicad/copper/test_via_renet.py +64 -0
  855. fenolite-0.2.0/tests/kicad/equivalence/test_import_runner.py +43 -0
  856. fenolite-0.2.0/tests/kicad/equivalence/test_triangle_blink.py +69 -0
  857. fenolite-0.2.0/tests/kicad/equivalence/test_triangle_corpus.py +211 -0
  858. fenolite-0.2.0/tests/kicad/export/_exportcases.py +158 -0
  859. fenolite-0.2.0/tests/kicad/export/test_export_oracle.py +121 -0
  860. fenolite-0.2.0/tests/kicad/export/test_export_probes.py +41 -0
  861. fenolite-0.2.0/tests/kicad/export/test_manifest_oracle.py +193 -0
  862. fenolite-0.2.0/tests/kicad/fill/_fillcases.py +178 -0
  863. fenolite-0.2.0/tests/kicad/fill/test_docker_cli.py +37 -0
  864. fenolite-0.2.0/tests/kicad/fill/test_fill_demos.py +74 -0
  865. fenolite-0.2.0/tests/kicad/fill/test_fill_oracle.py +62 -0
  866. fenolite-0.2.0/tests/kicad/fill/test_fill_probes.py +35 -0
  867. fenolite-0.2.0/tests/kicad/followups/_followcases.py +480 -0
  868. fenolite-0.2.0/tests/kicad/followups/test_followup_probes.py +88 -0
  869. fenolite-0.2.0/tests/kicad/frame/_arccases.py +244 -0
  870. fenolite-0.2.0/tests/kicad/frame/_framebench.py +366 -0
  871. fenolite-0.2.0/tests/kicad/frame/_framecases.py +330 -0
  872. fenolite-0.2.0/tests/kicad/frame/_offsetbench.py +227 -0
  873. fenolite-0.2.0/tests/kicad/frame/test_copper_oracle.py +61 -0
  874. fenolite-0.2.0/tests/kicad/frame/test_frame_oracle.py +62 -0
  875. fenolite-0.2.0/tests/kicad/frame/test_pad_offset.py +52 -0
  876. fenolite-0.2.0/tests/kicad/lens/_lenscases.py +232 -0
  877. fenolite-0.2.0/tests/kicad/lens/_renamecases.py +210 -0
  878. fenolite-0.2.0/tests/kicad/lens/test_lens_acceptance_oracle.py +52 -0
  879. fenolite-0.2.0/tests/kicad/lens/test_lens_probes.py +24 -0
  880. fenolite-0.2.0/tests/kicad/lens/test_preserve_oracle.py +42 -0
  881. fenolite-0.2.0/tests/kicad/lens/test_rename_oracle.py +46 -0
  882. fenolite-0.2.0/tests/kicad/lens/test_update_stand_in.py +39 -0
  883. fenolite-0.2.0/tests/kicad/libs/test_lib_hypotheses.py +65 -0
  884. fenolite-0.2.0/tests/kicad/libs/test_lib_tables_drc.py +75 -0
  885. fenolite-0.2.0/tests/kicad/libs/test_mini_oracle.py +138 -0
  886. fenolite-0.2.0/tests/kicad/libs/test_mod_write_oracle.py +45 -0
  887. fenolite-0.2.0/tests/kicad/place/_placecases.py +229 -0
  888. fenolite-0.2.0/tests/kicad/place/test_place_oracle.py +151 -0
  889. fenolite-0.2.0/tests/kicad/place/test_place_probes.py +35 -0
  890. fenolite-0.2.0/tests/kicad/project/_mincases.py +78 -0
  891. fenolite-0.2.0/tests/kicad/project/_procases.py +152 -0
  892. fenolite-0.2.0/tests/kicad/project/test_minimums_drc.py +70 -0
  893. fenolite-0.2.0/tests/kicad/project/test_netclass_drc.py +64 -0
  894. fenolite-0.2.0/tests/kicad/project/test_project_files.py +24 -0
  895. fenolite-0.2.0/tests/kicad/rules/_kindcases.py +394 -0
  896. fenolite-0.2.0/tests/kicad/rules/_paircases.py +81 -0
  897. fenolite-0.2.0/tests/kicad/rules/_rulebench.py +523 -0
  898. fenolite-0.2.0/tests/kicad/rules/_rulecases.py +355 -0
  899. fenolite-0.2.0/tests/kicad/rules/test_bench.py +53 -0
  900. fenolite-0.2.0/tests/kicad/rules/test_diffpair_names.py +26 -0
  901. fenolite-0.2.0/tests/kicad/rules/test_rule_conditions.py +36 -0
  902. fenolite-0.2.0/tests/kicad/rules/test_rule_design.py +41 -0
  903. fenolite-0.2.0/tests/kicad/rules/test_rule_dialect.py +32 -0
  904. fenolite-0.2.0/tests/kicad/rules/test_rule_floors.py +46 -0
  905. fenolite-0.2.0/tests/kicad/rules/test_rule_gating.py +33 -0
  906. fenolite-0.2.0/tests/kicad/rules/test_rule_kinds.py +34 -0
  907. fenolite-0.2.0/tests/kicad/rules/test_rule_kinds_new.py +82 -0
  908. fenolite-0.2.0/tests/kicad/rules/test_rule_order.py +35 -0
  909. fenolite-0.2.0/tests/kicad/schematic/_gencases.py +491 -0
  910. fenolite-0.2.0/tests/kicad/schematic/_hiercases.py +470 -0
  911. fenolite-0.2.0/tests/kicad/schematic/_netlistcases.py +245 -0
  912. fenolite-0.2.0/tests/kicad/schematic/_schcases.py +134 -0
  913. fenolite-0.2.0/tests/kicad/schematic/test_components_oracle.py +131 -0
  914. fenolite-0.2.0/tests/kicad/schematic/test_corpus_rt2.py +100 -0
  915. fenolite-0.2.0/tests/kicad/schematic/test_generated_oracle.py +313 -0
  916. fenolite-0.2.0/tests/kicad/schematic/test_hierarchy_oracle.py +101 -0
  917. fenolite-0.2.0/tests/kicad/schematic/test_hierarchy_probes.py +44 -0
  918. fenolite-0.2.0/tests/kicad/schematic/test_naming_probes.py +87 -0
  919. fenolite-0.2.0/tests/kicad/schematic/test_netlist_facts.py +62 -0
  920. fenolite-0.2.0/tests/kicad/schematic/test_own_netlist.py +91 -0
  921. fenolite-0.2.0/tests/kicad/schematic/test_schematic_upgraded.py +59 -0
  922. fenolite-0.2.0/tests/kicad/sheets/_acceptance.py +142 -0
  923. fenolite-0.2.0/tests/kicad/sheets/_expected.py +224 -0
  924. fenolite-0.2.0/tests/kicad/sheets/_sheet_bench.py +227 -0
  925. fenolite-0.2.0/tests/kicad/sheets/_sheetcases.py +338 -0
  926. fenolite-0.2.0/tests/kicad/sheets/_svg.py +142 -0
  927. fenolite-0.2.0/tests/kicad/sheets/test_project_sheet.py +53 -0
  928. fenolite-0.2.0/tests/kicad/sheets/test_sheet_acceptance.py +53 -0
  929. fenolite-0.2.0/tests/kicad/sheets/test_sheet_import.py +86 -0
  930. fenolite-0.2.0/tests/kicad/sheets/test_sheet_probes.py +90 -0
  931. fenolite-0.2.0/tests/kicad/sheets/test_sheet_verdict.py +80 -0
  932. fenolite-0.2.0/tests/kicad/sheets/test_svg_reader.py +68 -0
  933. fenolite-0.2.0/tests/kicad/test_environment.py +46 -0
  934. fenolite-0.2.0/tests/kicad/test_fmt_identity_10.py +101 -0
  935. fenolite-0.2.0/tests/kicad/test_geometry_arcs.py +135 -0
  936. fenolite-0.2.0/tests/kicad/test_geometry_frame.py +102 -0
  937. fenolite-0.2.0/tests/kicad/test_probe_results.py +19 -0
  938. fenolite-0.2.0/tests/kicad/test_rt0_oracle.py +102 -0
  939. fenolite-0.2.0/tests/kicad/test_sexpr_oracle.py +88 -0
  940. fenolite-0.2.0/tests/kicad/test_token_census.py +153 -0
  941. fenolite-0.2.0/tests/kicad/test_token_fuzz.py +44 -0
  942. fenolite-0.2.0/tests/kicad/test_version_constants.py +134 -0
  943. fenolite-0.2.0/tests/kicad/zones/_freshfill.py +227 -0
  944. fenolite-0.2.0/tests/kicad/zones/_gerber.py +69 -0
  945. fenolite-0.2.0/tests/kicad/zones/_padzonecases.py +85 -0
  946. fenolite-0.2.0/tests/kicad/zones/_zonebench.py +616 -0
  947. fenolite-0.2.0/tests/kicad/zones/test_pad_zone_requests.py +38 -0
  948. fenolite-0.2.0/tests/kicad/zones/test_zone_oracle.py +223 -0
  949. fenolite-0.2.0/tests/kicad/zones/test_zone_probes.py +31 -0
  950. fenolite-0.2.0/tests/kicad/zones/test_zonebench.py +200 -0
  951. fenolite-0.2.0/tests/libs/README.md +41 -0
  952. fenolite-0.2.0/tests/libs/test_build_official.py +92 -0
  953. fenolite-0.2.0/tests/libs/test_install_pin.py +105 -0
  954. fenolite-0.2.0/tests/libs/test_official_read.py +147 -0
  955. fenolite-0.2.0/tests/libs/test_official_resolve.py +151 -0
  956. fenolite-0.2.0/tests/residue/test_derived_corpus.py +124 -0
  957. fenolite-0.2.0/tests/residue/test_no_token_list.py +105 -0
  958. fenolite-0.2.0/tests/residue/test_scan.py +164 -0
  959. fenolite-0.2.0/tests/residue/test_template_residue.py +193 -0
  960. fenolite-0.2.0/tests/routing/test_acceptance_loop.py +138 -0
  961. fenolite-0.2.0/tests/routing/test_freerouting_gate.py +396 -0
  962. fenolite-0.2.0/tests/routing/test_freerouting_oracle.py +91 -0
  963. fenolite-0.2.0/tests/routing/test_krt_gate.py +278 -0
  964. fenolite-0.2.0/tests/routing/test_route_oracle.py +105 -0
  965. fenolite-0.2.0/tests/strategies.py +224 -0
  966. fenolite-0.2.0/tests/unit/analysis/test_boundary.py +92 -0
  967. fenolite-0.2.0/tests/unit/analysis/test_bracket_bench.py +43 -0
  968. fenolite-0.2.0/tests/unit/analysis/test_copper.py +128 -0
  969. fenolite-0.2.0/tests/unit/analysis/test_current.py +168 -0
  970. fenolite-0.2.0/tests/unit/analysis/test_distance.py +137 -0
  971. fenolite-0.2.0/tests/unit/analysis/test_facts_page.py +112 -0
  972. fenolite-0.2.0/tests/unit/analysis/test_findings.py +169 -0
  973. fenolite-0.2.0/tests/unit/analysis/test_report.py +88 -0
  974. fenolite-0.2.0/tests/unit/analysis/test_requirements.py +117 -0
  975. fenolite-0.2.0/tests/unit/analysis/test_surface.py +262 -0
  976. fenolite-0.2.0/tests/unit/analysis/test_views.py +409 -0
  977. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_board.py +310 -0
  978. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_bodies.py +89 -0
  979. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_census.py +87 -0
  980. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_circuit.py +118 -0
  981. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_codes.py +80 -0
  982. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_connectivity.py +229 -0
  983. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_copper.py +370 -0
  984. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_ext.py +57 -0
  985. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_ids.py +120 -0
  986. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_layers.py +133 -0
  987. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_library.py +202 -0
  988. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_netlist.py +526 -0
  989. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_own_files.py +208 -0
  990. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_package.py +116 -0
  991. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_pads.py +194 -0
  992. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_project.py +197 -0
  993. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_rules.py +117 -0
  994. fenolite-0.2.0/tests/unit/backends/altium/adapter/test_units.py +66 -0
  995. fenolite-0.2.0/tests/unit/backends/altium/read/test_bodies.py +121 -0
  996. fenolite-0.2.0/tests/unit/backends/altium/read/test_cfb_build.py +54 -0
  997. fenolite-0.2.0/tests/unit/backends/altium/read/test_cfb_codes.py +25 -0
  998. fenolite-0.2.0/tests/unit/backends/altium/read/test_cfb_errors.py +106 -0
  999. fenolite-0.2.0/tests/unit/backends/altium/read/test_cfb_fuzz.py +44 -0
  1000. fenolite-0.2.0/tests/unit/backends/altium/read/test_cfb_limits.py +36 -0
  1001. fenolite-0.2.0/tests/unit/backends/altium/read/test_cfb_notes.py +100 -0
  1002. fenolite-0.2.0/tests/unit/backends/altium/read/test_cfb_read.py +79 -0
  1003. fenolite-0.2.0/tests/unit/backends/altium/read/test_ini.py +126 -0
  1004. fenolite-0.2.0/tests/unit/backends/altium/read/test_load_project.py +184 -0
  1005. fenolite-0.2.0/tests/unit/backends/altium/read/test_outjob.py +80 -0
  1006. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcb_field_levels.py +107 -0
  1007. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcb_imports.py +80 -0
  1008. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcb_issues.py +126 -0
  1009. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcb_own_files.py +131 -0
  1010. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcb_records.py +96 -0
  1011. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcbdoc_read.py +133 -0
  1012. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcblib_read.py +110 -0
  1013. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcbprims.py +250 -0
  1014. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcbprims_pad.py +65 -0
  1015. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcbprims_region.py +63 -0
  1016. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcbprops.py +112 -0
  1017. fenolite-0.2.0/tests/unit/backends/altium/read/test_pcbstack.py +121 -0
  1018. fenolite-0.2.0/tests/unit/backends/altium/read/test_project_read.py +196 -0
  1019. fenolite-0.2.0/tests/unit/backends/altium/read/test_proptext.py +66 -0
  1020. fenolite-0.2.0/tests/unit/backends/altium/read/test_rul.py +106 -0
  1021. fenolite-0.2.0/tests/unit/backends/altium/read/test_rule_map.py +340 -0
  1022. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_additional.py +101 -0
  1023. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_ascii.py +158 -0
  1024. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_bounds.py +121 -0
  1025. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_document.py +228 -0
  1026. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_framing.py +66 -0
  1027. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_fuzz.py +56 -0
  1028. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_identity.py +206 -0
  1029. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_imports.py +73 -0
  1030. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_issues.py +134 -0
  1031. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_own_output.py +195 -0
  1032. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_owner.py +124 -0
  1033. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_parts.py +107 -0
  1034. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_pins.py +188 -0
  1035. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_props.py +69 -0
  1036. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_records.py +405 -0
  1037. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_records_table.py +126 -0
  1038. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_storage.py +110 -0
  1039. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_surface.py +100 -0
  1040. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_text.py +81 -0
  1041. fenolite-0.2.0/tests/unit/backends/altium/read/test_sch_units.py +107 -0
  1042. fenolite-0.2.0/tests/unit/backends/altium/read/test_schlib.py +170 -0
  1043. fenolite-0.2.0/tests/unit/backends/altium/read/test_schlib_side.py +119 -0
  1044. fenolite-0.2.0/tests/unit/backends/altium/read/test_scope.py +103 -0
  1045. fenolite-0.2.0/tests/unit/backends/altium/read/test_stackup.py +90 -0
  1046. fenolite-0.2.0/tests/unit/backends/altium/read/test_text_codes.py +58 -0
  1047. fenolite-0.2.0/tests/unit/backends/altium/read/test_text_imports.py +66 -0
  1048. fenolite-0.2.0/tests/unit/backends/altium/read/test_text_tables.py +114 -0
  1049. fenolite-0.2.0/tests/unit/backends/altium/read/test_textfile.py +146 -0
  1050. fenolite-0.2.0/tests/unit/backends/altium/test_altium_pcb_read.py +635 -0
  1051. fenolite-0.2.0/tests/unit/backends/altium/test_altsym.py +185 -0
  1052. fenolite-0.2.0/tests/unit/backends/altium/test_ascii.py +114 -0
  1053. fenolite-0.2.0/tests/unit/backends/altium/test_backend.py +189 -0
  1054. fenolite-0.2.0/tests/unit/backends/altium/test_backend_documents.py +136 -0
  1055. fenolite-0.2.0/tests/unit/backends/altium/test_binary.py +234 -0
  1056. fenolite-0.2.0/tests/unit/backends/altium/test_cfb.py +216 -0
  1057. fenolite-0.2.0/tests/unit/backends/altium/test_cfb_reader.py +190 -0
  1058. fenolite-0.2.0/tests/unit/backends/altium/test_cfb_storage.py +148 -0
  1059. fenolite-0.2.0/tests/unit/backends/altium/test_diff_records.py +130 -0
  1060. fenolite-0.2.0/tests/unit/backends/altium/test_docboard.py +544 -0
  1061. fenolite-0.2.0/tests/unit/backends/altium/test_docset.py +162 -0
  1062. fenolite-0.2.0/tests/unit/backends/altium/test_hierarchy.py +376 -0
  1063. fenolite-0.2.0/tests/unit/backends/altium/test_layout.py +479 -0
  1064. fenolite-0.2.0/tests/unit/backends/altium/test_libboard.py +540 -0
  1065. fenolite-0.2.0/tests/unit/backends/altium/test_pcbdoc.py +997 -0
  1066. fenolite-0.2.0/tests/unit/backends/altium/test_pcblib.py +319 -0
  1067. fenolite-0.2.0/tests/unit/backends/altium/test_pcbrecords.py +361 -0
  1068. fenolite-0.2.0/tests/unit/backends/altium/test_prjpcb.py +184 -0
  1069. fenolite-0.2.0/tests/unit/backends/altium/test_project.py +343 -0
  1070. fenolite-0.2.0/tests/unit/backends/altium/test_read_sheet.py +476 -0
  1071. fenolite-0.2.0/tests/unit/backends/altium/test_read_sheet_strings.py +188 -0
  1072. fenolite-0.2.0/tests/unit/backends/altium/test_readback.py +671 -0
  1073. fenolite-0.2.0/tests/unit/backends/altium/test_roundtrip.py +375 -0
  1074. fenolite-0.2.0/tests/unit/backends/altium/test_schdoc.py +847 -0
  1075. fenolite-0.2.0/tests/unit/backends/altium/test_schlib.py +338 -0
  1076. fenolite-0.2.0/tests/unit/backends/altium/test_symbols.py +68 -0
  1077. fenolite-0.2.0/tests/unit/backends/kicad/test_bom_csv.py +76 -0
  1078. fenolite-0.2.0/tests/unit/backends/kicad/test_canary.py +243 -0
  1079. fenolite-0.2.0/tests/unit/backends/kicad/test_check_emittable.py +118 -0
  1080. fenolite-0.2.0/tests/unit/backends/kicad/test_cli_candidates.py +54 -0
  1081. fenolite-0.2.0/tests/unit/backends/kicad/test_cli_export.py +75 -0
  1082. fenolite-0.2.0/tests/unit/backends/kicad/test_cli_refill.py +62 -0
  1083. fenolite-0.2.0/tests/unit/backends/kicad/test_cli_runner.py +512 -0
  1084. fenolite-0.2.0/tests/unit/backends/kicad/test_copper_issues.py +134 -0
  1085. fenolite-0.2.0/tests/unit/backends/kicad/test_copper_merge.py +252 -0
  1086. fenolite-0.2.0/tests/unit/backends/kicad/test_copper_stitch.py +432 -0
  1087. fenolite-0.2.0/tests/unit/backends/kicad/test_copper_tracks.py +570 -0
  1088. fenolite-0.2.0/tests/unit/backends/kicad/test_copper_uuid.py +77 -0
  1089. fenolite-0.2.0/tests/unit/backends/kicad/test_copperrules.py +208 -0
  1090. fenolite-0.2.0/tests/unit/backends/kicad/test_docker_cli.py +83 -0
  1091. fenolite-0.2.0/tests/unit/backends/kicad/test_drc.py +125 -0
  1092. fenolite-0.2.0/tests/unit/backends/kicad/test_dru.py +324 -0
  1093. fenolite-0.2.0/tests/unit/backends/kicad/test_dru_demos.py +31 -0
  1094. fenolite-0.2.0/tests/unit/backends/kicad/test_embed.py +171 -0
  1095. fenolite-0.2.0/tests/unit/backends/kicad/test_embed_bottom.py +124 -0
  1096. fenolite-0.2.0/tests/unit/backends/kicad/test_embed_copper.py +68 -0
  1097. fenolite-0.2.0/tests/unit/backends/kicad/test_embed_property.py +134 -0
  1098. fenolite-0.2.0/tests/unit/backends/kicad/test_erc.py +268 -0
  1099. fenolite-0.2.0/tests/unit/backends/kicad/test_fields_helper.py +227 -0
  1100. fenolite-0.2.0/tests/unit/backends/kicad/test_fill.py +97 -0
  1101. fenolite-0.2.0/tests/unit/backends/kicad/test_frame_custom.py +224 -0
  1102. fenolite-0.2.0/tests/unit/backends/kicad/test_frame_extent.py +216 -0
  1103. fenolite-0.2.0/tests/unit/backends/kicad/test_frame_issues.py +57 -0
  1104. fenolite-0.2.0/tests/unit/backends/kicad/test_frame_pads.py +261 -0
  1105. fenolite-0.2.0/tests/unit/backends/kicad/test_fuzz_harness.py +346 -0
  1106. fenolite-0.2.0/tests/unit/backends/kicad/test_helpmatrix.py +134 -0
  1107. fenolite-0.2.0/tests/unit/backends/kicad/test_import_board.py +138 -0
  1108. fenolite-0.2.0/tests/unit/backends/kicad/test_inventory.py +377 -0
  1109. fenolite-0.2.0/tests/unit/backends/kicad/test_ipcd356.py +59 -0
  1110. fenolite-0.2.0/tests/unit/backends/kicad/test_layers.py +63 -0
  1111. fenolite-0.2.0/tests/unit/backends/kicad/test_lib_table.py +102 -0
  1112. fenolite-0.2.0/tests/unit/backends/kicad/test_lib_table_write.py +47 -0
  1113. fenolite-0.2.0/tests/unit/backends/kicad/test_lib_vars.py +243 -0
  1114. fenolite-0.2.0/tests/unit/backends/kicad/test_libcache.py +204 -0
  1115. fenolite-0.2.0/tests/unit/backends/kicad/test_libs_sources.py +157 -0
  1116. fenolite-0.2.0/tests/unit/backends/kicad/test_lowering.py +283 -0
  1117. fenolite-0.2.0/tests/unit/backends/kicad/test_lowering_minimums.py +263 -0
  1118. fenolite-0.2.0/tests/unit/backends/kicad/test_lowering_netclass.py +60 -0
  1119. fenolite-0.2.0/tests/unit/backends/kicad/test_mini_v9_pins.py +43 -0
  1120. fenolite-0.2.0/tests/unit/backends/kicad/test_mod.py +179 -0
  1121. fenolite-0.2.0/tests/unit/backends/kicad/test_mod_pads.py +294 -0
  1122. fenolite-0.2.0/tests/unit/backends/kicad/test_mod_write.py +347 -0
  1123. fenolite-0.2.0/tests/unit/backends/kicad/test_netlist.py +199 -0
  1124. fenolite-0.2.0/tests/unit/backends/kicad/test_netnames.py +61 -0
  1125. fenolite-0.2.0/tests/unit/backends/kicad/test_oracle.py +832 -0
  1126. fenolite-0.2.0/tests/unit/backends/kicad/test_outline.py +303 -0
  1127. fenolite-0.2.0/tests/unit/backends/kicad/test_pad_zone_connect.py +234 -0
  1128. fenolite-0.2.0/tests/unit/backends/kicad/test_pad_zones.py +219 -0
  1129. fenolite-0.2.0/tests/unit/backends/kicad/test_padnets.py +125 -0
  1130. fenolite-0.2.0/tests/unit/backends/kicad/test_parity_inputs.py +134 -0
  1131. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_fields.py +346 -0
  1132. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_fields_write.py +364 -0
  1133. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_footprints.py +144 -0
  1134. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_items.py +134 -0
  1135. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_net_names.py +117 -0
  1136. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_nets.py +53 -0
  1137. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_numbers.py +91 -0
  1138. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_read.py +129 -0
  1139. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_rebuild.py +88 -0
  1140. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_sheet.py +241 -0
  1141. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_slot_angle.py +38 -0
  1142. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_write.py +390 -0
  1143. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_write_lossy.py +133 -0
  1144. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_write_nets.py +291 -0
  1145. fenolite-0.2.0/tests/unit/backends/kicad/test_pcb_write_projections.py +148 -0
  1146. fenolite-0.2.0/tests/unit/backends/kicad/test_pro.py +86 -0
  1147. fenolite-0.2.0/tests/unit/backends/kicad/test_pro_minimums.py +217 -0
  1148. fenolite-0.2.0/tests/unit/backends/kicad/test_pro_read.py +182 -0
  1149. fenolite-0.2.0/tests/unit/backends/kicad/test_pro_sheet.py +143 -0
  1150. fenolite-0.2.0/tests/unit/backends/kicad/test_pro_synth.py +96 -0
  1151. fenolite-0.2.0/tests/unit/backends/kicad/test_pro_update.py +179 -0
  1152. fenolite-0.2.0/tests/unit/backends/kicad/test_pro_versions.py +46 -0
  1153. fenolite-0.2.0/tests/unit/backends/kicad/test_project_fixtures.py +79 -0
  1154. fenolite-0.2.0/tests/unit/backends/kicad/test_project_json.py +117 -0
  1155. fenolite-0.2.0/tests/unit/backends/kicad/test_projectset.py +282 -0
  1156. fenolite-0.2.0/tests/unit/backends/kicad/test_replace.py +212 -0
  1157. fenolite-0.2.0/tests/unit/backends/kicad/test_resolver.py +290 -0
  1158. fenolite-0.2.0/tests/unit/backends/kicad/test_resolver_rows.py +263 -0
  1159. fenolite-0.2.0/tests/unit/backends/kicad/test_roundtrip.py +93 -0
  1160. fenolite-0.2.0/tests/unit/backends/kicad/test_rulemap.py +342 -0
  1161. fenolite-0.2.0/tests/unit/backends/kicad/test_rulemap_kinds.py +233 -0
  1162. fenolite-0.2.0/tests/unit/backends/kicad/test_rules_text.py +71 -0
  1163. fenolite-0.2.0/tests/unit/backends/kicad/test_sch_netlist.py +471 -0
  1164. fenolite-0.2.0/tests/unit/backends/kicad/test_sch_read.py +526 -0
  1165. fenolite-0.2.0/tests/unit/backends/kicad/test_sch_rebuild.py +244 -0
  1166. fenolite-0.2.0/tests/unit/backends/kicad/test_sch_tree.py +200 -0
  1167. fenolite-0.2.0/tests/unit/backends/kicad/test_sch_write.py +298 -0
  1168. fenolite-0.2.0/tests/unit/backends/kicad/test_schgen.py +255 -0
  1169. fenolite-0.2.0/tests/unit/backends/kicad/test_schgen_hierarchy.py +200 -0
  1170. fenolite-0.2.0/tests/unit/backends/kicad/test_schgen_text_overlap.py +131 -0
  1171. fenolite-0.2.0/tests/unit/backends/kicad/test_schlayout.py +256 -0
  1172. fenolite-0.2.0/tests/unit/backends/kicad/test_schlayout_snap.py +346 -0
  1173. fenolite-0.2.0/tests/unit/backends/kicad/test_sexpr_atoms.py +169 -0
  1174. fenolite-0.2.0/tests/unit/backends/kicad/test_sexpr_dumps.py +209 -0
  1175. fenolite-0.2.0/tests/unit/backends/kicad/test_sexpr_fixtures.py +75 -0
  1176. fenolite-0.2.0/tests/unit/backends/kicad/test_sexpr_parse.py +257 -0
  1177. fenolite-0.2.0/tests/unit/backends/kicad/test_sexpr_properties.py +47 -0
  1178. fenolite-0.2.0/tests/unit/backends/kicad/test_slots.py +192 -0
  1179. fenolite-0.2.0/tests/unit/backends/kicad/test_slots_ext.py +81 -0
  1180. fenolite-0.2.0/tests/unit/backends/kicad/test_sym.py +214 -0
  1181. fenolite-0.2.0/tests/unit/backends/kicad/test_sym_extends.py +113 -0
  1182. fenolite-0.2.0/tests/unit/backends/kicad/test_symembed.py +172 -0
  1183. fenolite-0.2.0/tests/unit/backends/kicad/test_throughput.py +73 -0
  1184. fenolite-0.2.0/tests/unit/backends/kicad/test_token_docs.py +43 -0
  1185. fenolite-0.2.0/tests/unit/backends/kicad/test_token_examples.py +116 -0
  1186. fenolite-0.2.0/tests/unit/backends/kicad/test_token_results.py +122 -0
  1187. fenolite-0.2.0/tests/unit/backends/kicad/test_versions.py +253 -0
  1188. fenolite-0.2.0/tests/unit/backends/kicad/test_wks_read.py +180 -0
  1189. fenolite-0.2.0/tests/unit/backends/kicad/test_wks_write.py +237 -0
  1190. fenolite-0.2.0/tests/unit/backends/kicad/test_write_errors.py +43 -0
  1191. fenolite-0.2.0/tests/unit/backends/kicad/test_write_triad.py +76 -0
  1192. fenolite-0.2.0/tests/unit/backends/kicad/test_zone_codec.py +235 -0
  1193. fenolite-0.2.0/tests/unit/backends/kicad/test_zone_merge.py +286 -0
  1194. fenolite-0.2.0/tests/unit/backends/kicad/test_zone_settings_read.py +234 -0
  1195. fenolite-0.2.0/tests/unit/backends/kicad/test_zone_settings_write.py +344 -0
  1196. fenolite-0.2.0/tests/unit/backends/specctra/test_dsn.py +673 -0
  1197. fenolite-0.2.0/tests/unit/backends/specctra/test_lexer.py +187 -0
  1198. fenolite-0.2.0/tests/unit/backends/specctra/test_ses.py +361 -0
  1199. fenolite-0.2.0/tests/unit/backends/test_base_types.py +434 -0
  1200. fenolite-0.2.0/tests/unit/backends/test_evidence_declared.py +366 -0
  1201. fenolite-0.2.0/tests/unit/backends/test_matrix_row.py +62 -0
  1202. fenolite-0.2.0/tests/unit/backends/test_registry.py +220 -0
  1203. fenolite-0.2.0/tests/unit/catalog/test_catalog.py +1031 -0
  1204. fenolite-0.2.0/tests/unit/catalog/test_footprint_previews.py +35 -0
  1205. fenolite-0.2.0/tests/unit/catalog/test_symbol_expansion.py +266 -0
  1206. fenolite-0.2.0/tests/unit/catalog/test_symbol_previews.py +73 -0
  1207. fenolite-0.2.0/tests/unit/checks/conftest.py +13 -0
  1208. fenolite-0.2.0/tests/unit/checks/equivalence/_cases.py +209 -0
  1209. fenolite-0.2.0/tests/unit/checks/equivalence/conftest.py +12 -0
  1210. fenolite-0.2.0/tests/unit/checks/equivalence/test_codes.py +106 -0
  1211. fenolite-0.2.0/tests/unit/checks/equivalence/test_exclusion_data.py +86 -0
  1212. fenolite-0.2.0/tests/unit/checks/equivalence/test_exclusions.py +176 -0
  1213. fenolite-0.2.0/tests/unit/checks/equivalence/test_levels.py +341 -0
  1214. fenolite-0.2.0/tests/unit/checks/equivalence/test_norm.py +130 -0
  1215. fenolite-0.2.0/tests/unit/checks/equivalence/test_package.py +124 -0
  1216. fenolite-0.2.0/tests/unit/checks/fakes.py +400 -0
  1217. fenolite-0.2.0/tests/unit/checks/test_assignment_compare.py +411 -0
  1218. fenolite-0.2.0/tests/unit/checks/test_clearance.py +344 -0
  1219. fenolite-0.2.0/tests/unit/checks/test_codes.py +136 -0
  1220. fenolite-0.2.0/tests/unit/checks/test_containers.py +121 -0
  1221. fenolite-0.2.0/tests/unit/checks/test_copper.py +672 -0
  1222. fenolite-0.2.0/tests/unit/checks/test_copper_stage.py +237 -0
  1223. fenolite-0.2.0/tests/unit/checks/test_diff.py +482 -0
  1224. fenolite-0.2.0/tests/unit/checks/test_documents.py +343 -0
  1225. fenolite-0.2.0/tests/unit/checks/test_drc_json.py +202 -0
  1226. fenolite-0.2.0/tests/unit/checks/test_drc_stage.py +182 -0
  1227. fenolite-0.2.0/tests/unit/checks/test_erc_json.py +117 -0
  1228. fenolite-0.2.0/tests/unit/checks/test_erc_lite.py +187 -0
  1229. fenolite-0.2.0/tests/unit/checks/test_erc_stage.py +130 -0
  1230. fenolite-0.2.0/tests/unit/checks/test_fill_stage.py +95 -0
  1231. fenolite-0.2.0/tests/unit/checks/test_parity.py +266 -0
  1232. fenolite-0.2.0/tests/unit/checks/test_parity_stage.py +264 -0
  1233. fenolite-0.2.0/tests/unit/checks/test_render_stage.py +106 -0
  1234. fenolite-0.2.0/tests/unit/checks/test_roundtrip_stage.py +40 -0
  1235. fenolite-0.2.0/tests/unit/checks/test_rt2_stage.py +246 -0
  1236. fenolite-0.2.0/tests/unit/checks/test_rta2.py +173 -0
  1237. fenolite-0.2.0/tests/unit/checks/test_stages.py +374 -0
  1238. fenolite-0.2.0/tests/unit/checks/test_validate_stage.py +73 -0
  1239. fenolite-0.2.0/tests/unit/cli/_asmcli.py +44 -0
  1240. fenolite-0.2.0/tests/unit/cli/_checkcli.py +47 -0
  1241. fenolite-0.2.0/tests/unit/cli/conftest.py +12 -0
  1242. fenolite-0.2.0/tests/unit/cli/test_analyze_cmd.py +178 -0
  1243. fenolite-0.2.0/tests/unit/cli/test_bom_cmd.py +409 -0
  1244. fenolite-0.2.0/tests/unit/cli/test_build_altium.py +479 -0
  1245. fenolite-0.2.0/tests/unit/cli/test_build_altium_script_copper.py +265 -0
  1246. fenolite-0.2.0/tests/unit/cli/test_build_command.py +290 -0
  1247. fenolite-0.2.0/tests/unit/cli/test_build_copper_from.py +333 -0
  1248. fenolite-0.2.0/tests/unit/cli/test_build_copper_guard.py +220 -0
  1249. fenolite-0.2.0/tests/unit/cli/test_build_errors.py +86 -0
  1250. fenolite-0.2.0/tests/unit/cli/test_build_fields_command.py +368 -0
  1251. fenolite-0.2.0/tests/unit/cli/test_build_minimums_command.py +94 -0
  1252. fenolite-0.2.0/tests/unit/cli/test_build_placement_guard.py +175 -0
  1253. fenolite-0.2.0/tests/unit/cli/test_build_preserve_command.py +517 -0
  1254. fenolite-0.2.0/tests/unit/cli/test_build_rules_command.py +74 -0
  1255. fenolite-0.2.0/tests/unit/cli/test_build_schematic_cmd.py +250 -0
  1256. fenolite-0.2.0/tests/unit/cli/test_build_zones_command.py +346 -0
  1257. fenolite-0.2.0/tests/unit/cli/test_capabilities.py +50 -0
  1258. fenolite-0.2.0/tests/unit/cli/test_capabilities_backends.py +92 -0
  1259. fenolite-0.2.0/tests/unit/cli/test_capabilities_experimental.py +110 -0
  1260. fenolite-0.2.0/tests/unit/cli/test_capabilities_matrix.py +112 -0
  1261. fenolite-0.2.0/tests/unit/cli/test_catalog.py +114 -0
  1262. fenolite-0.2.0/tests/unit/cli/test_check_altium.py +278 -0
  1263. fenolite-0.2.0/tests/unit/cli/test_check_cmd.py +467 -0
  1264. fenolite-0.2.0/tests/unit/cli/test_check_readonly.py +226 -0
  1265. fenolite-0.2.0/tests/unit/cli/test_diff_cmd.py +297 -0
  1266. fenolite-0.2.0/tests/unit/cli/test_doctor_cmd.py +192 -0
  1267. fenolite-0.2.0/tests/unit/cli/test_equivalent_cmd.py +496 -0
  1268. fenolite-0.2.0/tests/unit/cli/test_explain_cmd.py +116 -0
  1269. fenolite-0.2.0/tests/unit/cli/test_export_cmd.py +375 -0
  1270. fenolite-0.2.0/tests/unit/cli/test_fill_cmd.py +90 -0
  1271. fenolite-0.2.0/tests/unit/cli/test_fmt_cmd.py +120 -0
  1272. fenolite-0.2.0/tests/unit/cli/test_hermetic_examples.py +58 -0
  1273. fenolite-0.2.0/tests/unit/cli/test_inspect_cmd.py +283 -0
  1274. fenolite-0.2.0/tests/unit/cli/test_inspect_streams.py +100 -0
  1275. fenolite-0.2.0/tests/unit/cli/test_kicad_flags.py +68 -0
  1276. fenolite-0.2.0/tests/unit/cli/test_library_errors.py +229 -0
  1277. fenolite-0.2.0/tests/unit/cli/test_main.py +194 -0
  1278. fenolite-0.2.0/tests/unit/cli/test_manifest_cmd.py +519 -0
  1279. fenolite-0.2.0/tests/unit/cli/test_netlist_cmd.py +297 -0
  1280. fenolite-0.2.0/tests/unit/cli/test_pads_cmd.py +161 -0
  1281. fenolite-0.2.0/tests/unit/cli/test_paging.py +266 -0
  1282. fenolite-0.2.0/tests/unit/cli/test_parity_cmd.py +189 -0
  1283. fenolite-0.2.0/tests/unit/cli/test_place_cmd.py +319 -0
  1284. fenolite-0.2.0/tests/unit/cli/test_pnp_cmd.py +217 -0
  1285. fenolite-0.2.0/tests/unit/cli/test_render_cmd.py +193 -0
  1286. fenolite-0.2.0/tests/unit/cli/test_restore_cmd.py +167 -0
  1287. fenolite-0.2.0/tests/unit/cli/test_roundtrip_cmd.py +255 -0
  1288. fenolite-0.2.0/tests/unit/cli/test_route_cmd.py +281 -0
  1289. fenolite-0.2.0/tests/unit/cli/test_script.py +75 -0
  1290. fenolite-0.2.0/tests/unit/cli/test_sync_cmd.py +325 -0
  1291. fenolite-0.2.0/tests/unit/cli/test_template_cmd.py +102 -0
  1292. fenolite-0.2.0/tests/unit/cli/test_template_import.py +198 -0
  1293. fenolite-0.2.0/tests/unit/cli/test_views_cmd.py +170 -0
  1294. fenolite-0.2.0/tests/unit/core/test_ids.py +62 -0
  1295. fenolite-0.2.0/tests/unit/core/test_io.py +63 -0
  1296. fenolite-0.2.0/tests/unit/dsl/test_connect.py +83 -0
  1297. fenolite-0.2.0/tests/unit/dsl/test_copper_dsl.py +333 -0
  1298. fenolite-0.2.0/tests/unit/dsl/test_fields.py +178 -0
  1299. fenolite-0.2.0/tests/unit/dsl/test_footprint.py +134 -0
  1300. fenolite-0.2.0/tests/unit/dsl/test_harness.py +125 -0
  1301. fenolite-0.2.0/tests/unit/dsl/test_ids.py +48 -0
  1302. fenolite-0.2.0/tests/unit/dsl/test_interfaces.py +35 -0
  1303. fenolite-0.2.0/tests/unit/dsl/test_interfaces_typed.py +200 -0
  1304. fenolite-0.2.0/tests/unit/dsl/test_minimums.py +123 -0
  1305. fenolite-0.2.0/tests/unit/dsl/test_moved.py +198 -0
  1306. fenolite-0.2.0/tests/unit/dsl/test_no_connect.py +108 -0
  1307. fenolite-0.2.0/tests/unit/dsl/test_pad_zones.py +137 -0
  1308. fenolite-0.2.0/tests/unit/dsl/test_properties.py +77 -0
  1309. fenolite-0.2.0/tests/unit/dsl/test_quantity.py +151 -0
  1310. fenolite-0.2.0/tests/unit/dsl/test_rule_constructor.py +115 -0
  1311. fenolite-0.2.0/tests/unit/dsl/test_select.py +56 -0
  1312. fenolite-0.2.0/tests/unit/dsl/test_sheet_calls.py +134 -0
  1313. fenolite-0.2.0/tests/unit/dsl/test_structure.py +179 -0
  1314. fenolite-0.2.0/tests/unit/dsl/test_symbol.py +43 -0
  1315. fenolite-0.2.0/tests/unit/dsl/test_to_model.py +99 -0
  1316. fenolite-0.2.0/tests/unit/dsl/test_units.py +76 -0
  1317. fenolite-0.2.0/tests/unit/dsl/test_zones.py +226 -0
  1318. fenolite-0.2.0/tests/unit/exports/test_assembly.py +276 -0
  1319. fenolite-0.2.0/tests/unit/exports/test_assembly_guide.py +67 -0
  1320. fenolite-0.2.0/tests/unit/exports/test_bom.py +269 -0
  1321. fenolite-0.2.0/tests/unit/exports/test_manifest.py +249 -0
  1322. fenolite-0.2.0/tests/unit/exports/test_placement.py +189 -0
  1323. fenolite-0.2.0/tests/unit/exports/test_plan.py +182 -0
  1324. fenolite-0.2.0/tests/unit/exports/test_preset.py +158 -0
  1325. fenolite-0.2.0/tests/unit/exports/test_states.py +236 -0
  1326. fenolite-0.2.0/tests/unit/geometry/test_arc.py +310 -0
  1327. fenolite-0.2.0/tests/unit/geometry/test_boolean_fallback.py +133 -0
  1328. fenolite-0.2.0/tests/unit/geometry/test_extra_loader.py +39 -0
  1329. fenolite-0.2.0/tests/unit/geometry/test_index.py +64 -0
  1330. fenolite-0.2.0/tests/unit/geometry/test_normal_form.py +86 -0
  1331. fenolite-0.2.0/tests/unit/geometry/test_paths.py +105 -0
  1332. fenolite-0.2.0/tests/unit/geometry/test_polygon.py +257 -0
  1333. fenolite-0.2.0/tests/unit/geometry/test_predicates.py +259 -0
  1334. fenolite-0.2.0/tests/unit/geometry/test_shapes.py +66 -0
  1335. fenolite-0.2.0/tests/unit/geometry/test_thick.py +245 -0
  1336. fenolite-0.2.0/tests/unit/geometry/test_transform.py +346 -0
  1337. fenolite-0.2.0/tests/unit/geometry/test_vector.py +65 -0
  1338. fenolite-0.2.0/tests/unit/lens/test_alias_keep.py +172 -0
  1339. fenolite-0.2.0/tests/unit/lens/test_altium_binary_golden.py +106 -0
  1340. fenolite-0.2.0/tests/unit/lens/test_altium_build.py +463 -0
  1341. fenolite-0.2.0/tests/unit/lens/test_altium_copper_golden.py +206 -0
  1342. fenolite-0.2.0/tests/unit/lens/test_altium_copper_source.py +478 -0
  1343. fenolite-0.2.0/tests/unit/lens/test_altium_determinism.py +275 -0
  1344. fenolite-0.2.0/tests/unit/lens/test_altium_eco.py +199 -0
  1345. fenolite-0.2.0/tests/unit/lens/test_altium_existing.py +189 -0
  1346. fenolite-0.2.0/tests/unit/lens/test_altium_golden.py +167 -0
  1347. fenolite-0.2.0/tests/unit/lens/test_altium_hier.py +261 -0
  1348. fenolite-0.2.0/tests/unit/lens/test_altium_hier_golden.py +161 -0
  1349. fenolite-0.2.0/tests/unit/lens/test_altium_issues.py +898 -0
  1350. fenolite-0.2.0/tests/unit/lens/test_altium_no_connect_golden.py +104 -0
  1351. fenolite-0.2.0/tests/unit/lens/test_altium_pcb.py +1049 -0
  1352. fenolite-0.2.0/tests/unit/lens/test_altium_pcb_golden.py +128 -0
  1353. fenolite-0.2.0/tests/unit/lens/test_altium_rta2.py +145 -0
  1354. fenolite-0.2.0/tests/unit/lens/test_altium_schlib_golden.py +123 -0
  1355. fenolite-0.2.0/tests/unit/lens/test_build_authored_symbols.py +40 -0
  1356. fenolite-0.2.0/tests/unit/lens/test_build_catalog_inventory.py +136 -0
  1357. fenolite-0.2.0/tests/unit/lens/test_build_catalog_symbols.py +111 -0
  1358. fenolite-0.2.0/tests/unit/lens/test_build_copper.py +241 -0
  1359. fenolite-0.2.0/tests/unit/lens/test_build_determinism.py +79 -0
  1360. fenolite-0.2.0/tests/unit/lens/test_build_existing.py +75 -0
  1361. fenolite-0.2.0/tests/unit/lens/test_build_fields.py +205 -0
  1362. fenolite-0.2.0/tests/unit/lens/test_build_files.py +105 -0
  1363. fenolite-0.2.0/tests/unit/lens/test_build_hierarchy.py +237 -0
  1364. fenolite-0.2.0/tests/unit/lens/test_build_issues.py +100 -0
  1365. fenolite-0.2.0/tests/unit/lens/test_build_minimums.py +134 -0
  1366. fenolite-0.2.0/tests/unit/lens/test_build_netlist_guard.py +261 -0
  1367. fenolite-0.2.0/tests/unit/lens/test_build_no_connect.py +187 -0
  1368. fenolite-0.2.0/tests/unit/lens/test_build_pad_zones.py +308 -0
  1369. fenolite-0.2.0/tests/unit/lens/test_build_pins.py +112 -0
  1370. fenolite-0.2.0/tests/unit/lens/test_build_place.py +108 -0
  1371. fenolite-0.2.0/tests/unit/lens/test_build_preserve.py +56 -0
  1372. fenolite-0.2.0/tests/unit/lens/test_build_properties.py +160 -0
  1373. fenolite-0.2.0/tests/unit/lens/test_build_readback.py +59 -0
  1374. fenolite-0.2.0/tests/unit/lens/test_build_resolve.py +118 -0
  1375. fenolite-0.2.0/tests/unit/lens/test_build_schematic.py +409 -0
  1376. fenolite-0.2.0/tests/unit/lens/test_build_sheet.py +222 -0
  1377. fenolite-0.2.0/tests/unit/lens/test_build_vendor.py +183 -0
  1378. fenolite-0.2.0/tests/unit/lens/test_build_zones.py +123 -0
  1379. fenolite-0.2.0/tests/unit/lens/test_fields_merge.py +301 -0
  1380. fenolite-0.2.0/tests/unit/lens/test_interface_checks.py +141 -0
  1381. fenolite-0.2.0/tests/unit/lens/test_lens_acceptance.py +195 -0
  1382. fenolite-0.2.0/tests/unit/lens/test_moved.py +110 -0
  1383. fenolite-0.2.0/tests/unit/lens/test_net_alias.py +139 -0
  1384. fenolite-0.2.0/tests/unit/lens/test_placement_source.py +188 -0
  1385. fenolite-0.2.0/tests/unit/lens/test_placements_file.py +150 -0
  1386. fenolite-0.2.0/tests/unit/lens/test_preserve_board.py +49 -0
  1387. fenolite-0.2.0/tests/unit/lens/test_preserve_copper.py +35 -0
  1388. fenolite-0.2.0/tests/unit/lens/test_preserve_determinism.py +77 -0
  1389. fenolite-0.2.0/tests/unit/lens/test_preserve_fills.py +79 -0
  1390. fenolite-0.2.0/tests/unit/lens/test_preserve_footprints.py +150 -0
  1391. fenolite-0.2.0/tests/unit/lens/test_preserve_issues.py +64 -0
  1392. fenolite-0.2.0/tests/unit/lens/test_preserve_match.py +143 -0
  1393. fenolite-0.2.0/tests/unit/lens/test_preserve_place.py +71 -0
  1394. fenolite-0.2.0/tests/unit/lens/test_preserve_readback.py +67 -0
  1395. fenolite-0.2.0/tests/unit/lens/test_preserve_rules.py +68 -0
  1396. fenolite-0.2.0/tests/unit/lens/test_preserve_script_copper.py +141 -0
  1397. fenolite-0.2.0/tests/unit/lens/test_preserve_zones.py +246 -0
  1398. fenolite-0.2.0/tests/unit/lens/test_schplacements.py +183 -0
  1399. fenolite-0.2.0/tests/unit/lens/test_sync.py +177 -0
  1400. fenolite-0.2.0/tests/unit/model/test_board.py +174 -0
  1401. fenolite-0.2.0/tests/unit/model/test_board_import.py +142 -0
  1402. fenolite-0.2.0/tests/unit/model/test_circuit.py +94 -0
  1403. fenolite-0.2.0/tests/unit/model/test_design.py +290 -0
  1404. fenolite-0.2.0/tests/unit/model/test_dump_texts.py +27 -0
  1405. fenolite-0.2.0/tests/unit/model/test_fields_model.py +118 -0
  1406. fenolite-0.2.0/tests/unit/model/test_library.py +172 -0
  1407. fenolite-0.2.0/tests/unit/model/test_presentation.py +220 -0
  1408. fenolite-0.2.0/tests/unit/model/test_schematic.py +176 -0
  1409. fenolite-0.2.0/tests/unit/model/test_zone_settings.py +223 -0
  1410. fenolite-0.2.0/tests/unit/placement/test_grid.py +150 -0
  1411. fenolite-0.2.0/tests/unit/placement/test_legality.py +264 -0
  1412. fenolite-0.2.0/tests/unit/placement/test_place_codes.py +94 -0
  1413. fenolite-0.2.0/tests/unit/routing/_designs.py +84 -0
  1414. fenolite-0.2.0/tests/unit/routing/test_direct.py +58 -0
  1415. fenolite-0.2.0/tests/unit/routing/test_freerouting.py +315 -0
  1416. fenolite-0.2.0/tests/unit/routing/test_merge.py +74 -0
  1417. fenolite-0.2.0/tests/unit/routing/test_protocol.py +51 -0
  1418. fenolite-0.2.0/tests/unit/routing/test_registry.py +81 -0
  1419. fenolite-0.2.0/tests/unit/routing/test_routingtools.py +93 -0
  1420. fenolite-0.2.0/tests/unit/routing/test_select.py +58 -0
  1421. fenolite-0.2.0/tests/unit/templates/_specs.py +56 -0
  1422. fenolite-0.2.0/tests/unit/templates/conftest.py +14 -0
  1423. fenolite-0.2.0/tests/unit/templates/test_build.py +100 -0
  1424. fenolite-0.2.0/tests/unit/templates/test_examples.py +93 -0
  1425. fenolite-0.2.0/tests/unit/templates/test_layout.py +118 -0
  1426. fenolite-0.2.0/tests/unit/templates/test_spec.py +176 -0
  1427. fenolite-0.2.0/tests/unit/test_adrs.py +51 -0
  1428. fenolite-0.2.0/tests/unit/test_agent_skill.py +138 -0
  1429. fenolite-0.2.0/tests/unit/test_altium_roundtrip_page.py +108 -0
  1430. fenolite-0.2.0/tests/unit/test_altium_rows.py +415 -0
  1431. fenolite-0.2.0/tests/unit/test_altium_verification_docs.py +84 -0
  1432. fenolite-0.2.0/tests/unit/test_build_judge.py +69 -0
  1433. fenolite-0.2.0/tests/unit/test_capability_evidence.py +74 -0
  1434. fenolite-0.2.0/tests/unit/test_ci_workflow.py +547 -0
  1435. fenolite-0.2.0/tests/unit/test_conftest_libs.py +120 -0
  1436. fenolite-0.2.0/tests/unit/test_conftest_require.py +149 -0
  1437. fenolite-0.2.0/tests/unit/test_dco_check.py +133 -0
  1438. fenolite-0.2.0/tests/unit/test_docs_altium_read.py +106 -0
  1439. fenolite-0.2.0/tests/unit/test_drc_repeat.py +149 -0
  1440. fenolite-0.2.0/tests/unit/test_evidence_matrix_page.py +143 -0
  1441. fenolite-0.2.0/tests/unit/test_evidence_register.py +84 -0
  1442. fenolite-0.2.0/tests/unit/test_examples.py +84 -0
  1443. fenolite-0.2.0/tests/unit/test_format_facts.py +318 -0
  1444. fenolite-0.2.0/tests/unit/test_gendesigns.py +136 -0
  1445. fenolite-0.2.0/tests/unit/test_hypotheses_register.py +329 -0
  1446. fenolite-0.2.0/tests/unit/test_import_graph.py +353 -0
  1447. fenolite-0.2.0/tests/unit/test_kicad_major_marker.py +68 -0
  1448. fenolite-0.2.0/tests/unit/test_kicad_probes.py +156 -0
  1449. fenolite-0.2.0/tests/unit/test_layout_edit.py +45 -0
  1450. fenolite-0.2.0/tests/unit/test_legal_docs.py +60 -0
  1451. fenolite-0.2.0/tests/unit/test_libs_fetch.py +188 -0
  1452. fenolite-0.2.0/tests/unit/test_minimum_bench.py +116 -0
  1453. fenolite-0.2.0/tests/unit/test_netclass_bench.py +83 -0
  1454. fenolite-0.2.0/tests/unit/test_no_ported_code.py +51 -0
  1455. fenolite-0.2.0/tests/unit/test_parallel_runs.py +157 -0
  1456. fenolite-0.2.0/tests/unit/test_provenance.py +152 -0
  1457. fenolite-0.2.0/tests/unit/test_pyproject_invariants.py +162 -0
  1458. fenolite-0.2.0/tests/unit/test_release_record.py +249 -0
  1459. fenolite-0.2.0/tests/unit/test_release_record_v02.py +395 -0
  1460. fenolite-0.2.0/tests/unit/test_schema_drift.py +91 -0
  1461. fenolite-0.2.0/tests/unit/verify/test_cited_ids.py +93 -0
  1462. fenolite-0.2.0/tests/unit/verify/test_levels.py +108 -0
  1463. fenolite-0.2.0/tests/unit/verify/test_register.py +121 -0
  1464. fenolite-0.2.0/tests/unit/verify/test_release.py +55 -0
  1465. fenolite-0.2.0/tools/README.md +12 -0
  1466. fenolite-0.2.0/tools/altium_census.py +97 -0
  1467. fenolite-0.2.0/tools/catalog/render_footprints.py +152 -0
  1468. fenolite-0.2.0/tools/catalog/render_symbols.py +134 -0
  1469. fenolite-0.2.0/tools/corpus_fetch.py +113 -0
  1470. fenolite-0.2.0/tools/dco_check.py +82 -0
  1471. fenolite-0.2.0/tools/dco_exceptions.txt +5 -0
  1472. fenolite-0.2.0/tools/gen_evidence_matrix.py +177 -0
  1473. fenolite-0.2.0/tools/gen_schemas.py +192 -0
  1474. fenolite-0.2.0/tools/gen_token_docs.py +143 -0
  1475. fenolite-0.2.0/tools/kicad_libs_fetch.py +234 -0
  1476. fenolite-0.2.0/tools/kicad_token_fuzz.py +762 -0
  1477. fenolite-0.2.0/tools/residue/scope.toml +45 -0
  1478. fenolite-0.2.0/tools/test_outcomes.py +74 -0
  1479. fenolite-0.0.1.dev0/.gitignore +0 -32
  1480. fenolite-0.0.1.dev0/AGENTS.md +0 -47
  1481. fenolite-0.0.1.dev0/CHANGELOG.md +0 -19
  1482. fenolite-0.0.1.dev0/CLAUDE.md +0 -1
  1483. fenolite-0.0.1.dev0/CONTRIBUTING.md +0 -51
  1484. fenolite-0.0.1.dev0/LEGAL-ANNEX.md +0 -9
  1485. fenolite-0.0.1.dev0/LEGAL.md +0 -49
  1486. fenolite-0.0.1.dev0/Makefile +0 -30
  1487. fenolite-0.0.1.dev0/PKG-INFO +0 -117
  1488. fenolite-0.0.1.dev0/README.md +0 -74
  1489. fenolite-0.0.1.dev0/docs/adr/0003-clean-room-and-provenance.md +0 -50
  1490. fenolite-0.0.1.dev0/docs/adr/README.md +0 -34
  1491. fenolite-0.0.1.dev0/docs/cli-contract.md +0 -71
  1492. fenolite-0.0.1.dev0/docs/design-model.md +0 -70
  1493. fenolite-0.0.1.dev0/docs/evidence/README.md +0 -10
  1494. fenolite-0.0.1.dev0/docs/evidence/residue-history.md +0 -9
  1495. fenolite-0.0.1.dev0/docs/evidence/sources.md +0 -9
  1496. fenolite-0.0.1.dev0/docs/formats/README.md +0 -6
  1497. fenolite-0.0.1.dev0/docs/formats/units.md +0 -45
  1498. fenolite-0.0.1.dev0/docs/hypotheses.md +0 -18
  1499. fenolite-0.0.1.dev0/docs/provenance.md +0 -33
  1500. fenolite-0.0.1.dev0/examples/README.md +0 -4
  1501. fenolite-0.0.1.dev0/openspec/README.md +0 -10
  1502. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0002-cli-contract/.openspec.yaml +0 -2
  1503. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0002-cli-contract/design.md +0 -49
  1504. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0002-cli-contract/proposal.md +0 -38
  1505. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0002-cli-contract/specs/cli-contract/spec.md +0 -115
  1506. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0002-cli-contract/specs/package-layering/spec.md +0 -22
  1507. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0002-cli-contract/tasks.md +0 -32
  1508. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0003-ip-hygiene/.openspec.yaml +0 -2
  1509. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0003-ip-hygiene/design.md +0 -47
  1510. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0003-ip-hygiene/proposal.md +0 -38
  1511. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0003-ip-hygiene/specs/corpus-policy/spec.md +0 -46
  1512. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0003-ip-hygiene/specs/ip-hygiene/spec.md +0 -56
  1513. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0003-ip-hygiene/specs/residue-scan/spec.md +0 -69
  1514. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0003-ip-hygiene/tasks.md +0 -33
  1515. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0004-design-model-core/.openspec.yaml +0 -2
  1516. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0004-design-model-core/design.md +0 -55
  1517. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0004-design-model-core/proposal.md +0 -37
  1518. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0004-design-model-core/specs/canonical-serialization/spec.md +0 -50
  1519. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0004-design-model-core/specs/core-primitives/spec.md +0 -74
  1520. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0004-design-model-core/specs/design-model/spec.md +0 -79
  1521. fenolite-0.0.1.dev0/openspec/changes/archive/2026-09-30-c0004-design-model-core/tasks.md +0 -37
  1522. fenolite-0.0.1.dev0/openspec/changes/c0001-repo-bootstrap/.openspec.yaml +0 -2
  1523. fenolite-0.0.1.dev0/openspec/changes/c0001-repo-bootstrap/design.md +0 -49
  1524. fenolite-0.0.1.dev0/openspec/changes/c0001-repo-bootstrap/proposal.md +0 -37
  1525. fenolite-0.0.1.dev0/openspec/changes/c0001-repo-bootstrap/specs/ci-baseline/spec.md +0 -36
  1526. fenolite-0.0.1.dev0/openspec/changes/c0001-repo-bootstrap/specs/licensing-and-notices/spec.md +0 -51
  1527. fenolite-0.0.1.dev0/openspec/changes/c0001-repo-bootstrap/specs/repo-layout/spec.md +0 -52
  1528. fenolite-0.0.1.dev0/openspec/changes/c0001-repo-bootstrap/tasks.md +0 -34
  1529. fenolite-0.0.1.dev0/openspec/config.yaml +0 -32
  1530. fenolite-0.0.1.dev0/openspec/specs/canonical-serialization/spec.md +0 -54
  1531. fenolite-0.0.1.dev0/openspec/specs/cli-contract/spec.md +0 -119
  1532. fenolite-0.0.1.dev0/openspec/specs/core-primitives/spec.md +0 -78
  1533. fenolite-0.0.1.dev0/openspec/specs/corpus-policy/spec.md +0 -50
  1534. fenolite-0.0.1.dev0/openspec/specs/design-model/spec.md +0 -83
  1535. fenolite-0.0.1.dev0/openspec/specs/ip-hygiene/spec.md +0 -60
  1536. fenolite-0.0.1.dev0/openspec/specs/package-layering/spec.md +0 -26
  1537. fenolite-0.0.1.dev0/openspec/specs/residue-scan/spec.md +0 -73
  1538. fenolite-0.0.1.dev0/packaging/phenolite/LICENSE +0 -202
  1539. fenolite-0.0.1.dev0/packaging/phenolite/README.md +0 -11
  1540. fenolite-0.0.1.dev0/packaging/phenolite/pyproject.toml +0 -29
  1541. fenolite-0.0.1.dev0/packaging/phenolite/src/phenolite/__init__.py +0 -8
  1542. fenolite-0.0.1.dev0/pyproject.toml +0 -85
  1543. fenolite-0.0.1.dev0/schemas/fenolite.envelope.v0.json +0 -226
  1544. fenolite-0.0.1.dev0/schemas/fenolite.model.v0/board.json +0 -1220
  1545. fenolite-0.0.1.dev0/schemas/fenolite.model.v0/circuit.json +0 -526
  1546. fenolite-0.0.1.dev0/schemas/fenolite.model.v0/rules.json +0 -286
  1547. fenolite-0.0.1.dev0/src/fenolite/__init__.py +0 -7
  1548. fenolite-0.0.1.dev0/src/fenolite/cli/api.py +0 -101
  1549. fenolite-0.0.1.dev0/src/fenolite/cli/cmd__echo.py +0 -50
  1550. fenolite-0.0.1.dev0/src/fenolite/cli/cmd_capabilities.py +0 -112
  1551. fenolite-0.0.1.dev0/src/fenolite/cli/errors.py +0 -120
  1552. fenolite-0.0.1.dev0/src/fenolite/cli/main.py +0 -215
  1553. fenolite-0.0.1.dev0/src/fenolite/cli/output.py +0 -201
  1554. fenolite-0.0.1.dev0/src/fenolite/core/ids.py +0 -89
  1555. fenolite-0.0.1.dev0/src/fenolite/model/__init__.py +0 -74
  1556. fenolite-0.0.1.dev0/src/fenolite/model/board.py +0 -250
  1557. fenolite-0.0.1.dev0/src/fenolite/model/canonical.py +0 -248
  1558. fenolite-0.0.1.dev0/src/fenolite/model/circuit.py +0 -100
  1559. fenolite-0.0.1.dev0/src/fenolite/model/design.py +0 -206
  1560. fenolite-0.0.1.dev0/src/fenolite/model/rules.py +0 -102
  1561. fenolite-0.0.1.dev0/src/fenolite/model/schema.py +0 -20
  1562. fenolite-0.0.1.dev0/tests/README.md +0 -12
  1563. fenolite-0.0.1.dev0/tests/_resources.py +0 -36
  1564. fenolite-0.0.1.dev0/tests/conftest.py +0 -32
  1565. fenolite-0.0.1.dev0/tests/consistency/test_cli_consistency.py +0 -150
  1566. fenolite-0.0.1.dev0/tests/corpus/manifest.toml +0 -17
  1567. fenolite-0.0.1.dev0/tests/corpus/test_manifest.py +0 -131
  1568. fenolite-0.0.1.dev0/tests/data/MANIFEST.toml +0 -8
  1569. fenolite-0.0.1.dev0/tests/residue/test_no_token_list.py +0 -39
  1570. fenolite-0.0.1.dev0/tests/residue/test_scan.py +0 -138
  1571. fenolite-0.0.1.dev0/tests/strategies.py +0 -110
  1572. fenolite-0.0.1.dev0/tests/unit/cli/test_capabilities.py +0 -43
  1573. fenolite-0.0.1.dev0/tests/unit/cli/test_main.py +0 -157
  1574. fenolite-0.0.1.dev0/tests/unit/core/test_ids.py +0 -51
  1575. fenolite-0.0.1.dev0/tests/unit/core/test_io.py +0 -62
  1576. fenolite-0.0.1.dev0/tests/unit/model/test_board.py +0 -51
  1577. fenolite-0.0.1.dev0/tests/unit/model/test_circuit.py +0 -44
  1578. fenolite-0.0.1.dev0/tests/unit/model/test_design.py +0 -136
  1579. fenolite-0.0.1.dev0/tests/unit/test_adrs.py +0 -44
  1580. fenolite-0.0.1.dev0/tests/unit/test_import_graph.py +0 -207
  1581. fenolite-0.0.1.dev0/tests/unit/test_legal_docs.py +0 -60
  1582. fenolite-0.0.1.dev0/tests/unit/test_no_prior_code.py +0 -51
  1583. fenolite-0.0.1.dev0/tests/unit/test_provenance.py +0 -125
  1584. fenolite-0.0.1.dev0/tests/unit/test_pyproject_invariants.py +0 -60
  1585. fenolite-0.0.1.dev0/tests/unit/test_schema_drift.py +0 -75
  1586. fenolite-0.0.1.dev0/tools/README.md +0 -5
  1587. fenolite-0.0.1.dev0/tools/corpus_fetch.py +0 -92
  1588. fenolite-0.0.1.dev0/tools/gen_schemas.py +0 -173
  1589. fenolite-0.0.1.dev0/tools/residue/scope.toml +0 -20
  1590. fenolite-0.0.1.dev0/uv.lock +0 -1922
  1591. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/LICENSE +0 -0
  1592. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/NOTICE +0 -0
  1593. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/docs/adr/0001-neutral-model.md +0 -0
  1594. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/docs/adr/0004-licence-apache-2.0.md +0 -0
  1595. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/schemas/README.md +0 -0
  1596. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/schemas/fenolite.error.v0.json +0 -0
  1597. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/schemas/fenolite.model.v0/findings.json +0 -0
  1598. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/schemas/fenolite.model.v0/manufacturing.json +0 -0
  1599. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/schemas/fenolite.model.v0/meta.json +0 -0
  1600. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/__main__.py +0 -0
  1601. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/cli/__init__.py +0 -0
  1602. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/cli/exitcodes.py +0 -0
  1603. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/core/__init__.py +0 -0
  1604. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/core/coords.py +0 -0
  1605. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/core/errors.py +0 -0
  1606. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/core/evidence.py +0 -0
  1607. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/core/io.py +0 -0
  1608. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/core/provenance.py +0 -0
  1609. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/core/units.py +0 -0
  1610. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/model/base.py +0 -0
  1611. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/model/findings.py +0 -0
  1612. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/model/manufacturing.py +0 -0
  1613. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/src/fenolite/py.typed +0 -0
  1614. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/_scanmod.py +0 -0
  1615. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/_schema.py +0 -0
  1616. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/residue/test_hook.py +0 -0
  1617. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/residue/test_official_libs.py +0 -0
  1618. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/residue/test_repo_clean.py +0 -0
  1619. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/README.md +0 -0
  1620. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/cli/test_exitcodes.py +0 -0
  1621. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/cli/test_output.py +0 -0
  1622. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/cli/test_tty.py +0 -0
  1623. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/core/test_errors.py +0 -0
  1624. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/core/test_evidence.py +0 -0
  1625. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/core/test_units.py +0 -0
  1626. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/model/test_canonical.py +0 -0
  1627. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/model/test_rules.py +0 -0
  1628. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/test_cli_stub.py +0 -0
  1629. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/test_no_copyleft_deps.py +0 -0
  1630. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/test_repo_layout.py +0 -0
  1631. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tests/unit/test_spdx_headers.py +0 -0
  1632. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tools/hooks/pre-commit +0 -0
  1633. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tools/residue/README.md +0 -0
  1634. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tools/residue/blobs.sha256 +0 -0
  1635. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tools/residue/patterns.regex +0 -0
  1636. {fenolite-0.0.1.dev0 → fenolite-0.2.0}/tools/residue/scan.py +0 -0
@@ -0,0 +1,35 @@
1
+ # Claude Code local state
2
+ .claude/*
3
+
4
+ # Private planning material (never published)
5
+ private/
6
+
7
+ # Real boards built with Fenolite while it grows (dogfooding, never published)
8
+ dogfood/
9
+
10
+ # Fenolite derived cache
11
+ .fenolite/
12
+
13
+ # Python / tooling
14
+ .venv/
15
+ __pycache__/
16
+ *.py[cod]
17
+ .pytest_cache/
18
+ .ruff_cache/
19
+ .hypothesis/
20
+ .coverage
21
+ htmlcov/
22
+ /dist/
23
+ /build/
24
+ *.egg-info/
25
+
26
+ # Editor/OS
27
+ .DS_Store
28
+ .idea/
29
+ .vscode/
30
+
31
+ # Backups written by atomic saves
32
+ *.bak
33
+
34
+ # Temporary verification artefacts
35
+ verify_results/*.tmp
@@ -0,0 +1,139 @@
1
+ # Changelog
2
+
3
+ All notable changes to Fenolite are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
+ [Semantic Versioning](https://semver.org/) (pre-1.0: minor versions may break).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.2.0] - 2026-10-06
10
+
11
+ ### Added
12
+
13
+ - v0.2 acceptance: the schematic of a built project judged by KiCad's own ERC, netlist and parity test on 9.0 and 10.0, round trips of the demo schematics, the BOM and placement tables, the project manifest, the inspection commands, the complete layout lens, six more rule kinds and Fenolite's own parity check; the release record `docs/release/v0.2.md` names the test behind each item, its limits and what else is in the package (c0093).
14
+ - `fenolite build` writes a schematic (`<name>.kicad_sch`, symbol libraries and `sym-lib-table`) that KiCad's ERC and parity test accept on 9.0 and 10.0; pads of unconnected pins and net names with a slash are written as KiCad stores them; `--schematic skip` keeps the previous output (c0061). A sheet holds every unit of every part, a global label per connected pin, a no-connect flag per `no_connect` mark and a power flag per supply net that nothing drives; `schematic-placements.toml` beside the script fixes symbol positions, and an edited schematic is replaced with a warning and a backup (`docs/schematic.md`). New `build` issue codes are listed in `docs/cli-contract.md`.
15
+ - The schematic gets one sheet per module and puts 2-pin parts beside the IC pins they connect to, joined by a wire; `--schematic-layout grid` writes one flat sheet. Each module with a part is written to `sheets/<module path>.kicad_sch` and named by a box without pins on the sheet above it; nets cross sheets by their global labels, so net names stay those of the script, and a footprint of a part in a module carries the path of its sheets. `fenolite netlist --source fenolite` and the build's netlist guard read the sheet tree and the wires, so a sheet that KiCad would drop in silence stops the build. `fenolite parity` and the `parity` stage of `check` read the sheet tree with Fenolite's own netlist, so a project with module sheets needs no tool there either (c0070). The Reference and the Value of a turned or mirrored symbol are written level and centred, clear of the labels at its pins.
16
+ - KiCad schematics are read into a typed sheet (symbols, labels, no-connect flags, sheet references, embedded symbols) with every other child kept in place: `fenolite.backends.kicad.sch.read_schematic`, `rebuild_schematic`, `roundtrip_schematic`, `sheet_files`, `components` and `hierarchy_components`, and the model `fenolite.model.schematic.SchematicSheet` with schema `fenolite.schematic.v0`. Round trips are proved over the demo schematics: RT0 and RT1 pass on the 125 readable demo rows and on two third-party schematics re-saved by KiCad 10 (`H-K-SCH-READ`, `H-K-SCH-RT1`), and the components read from 34 demo projects on 10.0.6 and 31 on 9.0.9 equal those of `kicad-cli sch export netlist` (`H-K-SCH-COMPONENTS-2`). The token fuzz has load checks for schematics and symbol libraries, and the token inventory covers schematic and symbol-library tokens: 49 rows and one form row of kinds `kicad_sch` and `kicad_sym`, each proved by the fuzz on 9.0.9 and 10.0.6 (`H-K-SCH-TOKENS`); a symbol-library row also matches inside a schematic. (c0060).
17
+ - `fenolite check` runs KiCad's ERC (`erc.kicad`) on the project's schematic and reports schematic parity findings of the DRC run (c0062). ERC violations are `kicad.erc.<type>` issues located as `REF-PIN`, `REF` or a label text; parity entries are `kicad.drc.<type>` issues, and `kicad.drc.parity-unchecked` says when KiCad could not compare the board with its schematic. The copy of a project that `kicad-cli` sees now holds the schematic, its sheet files, `sym-lib-table` and the project's symbol libraries. In a manifest, a sheet, a symbol library and the symbol table reach `native-verified` through that stage.
18
+ - `fenolite netlist`: components and nets of a KiCad project as JSON, from `kicad-cli` or from Fenolite's own reading of a generated schematic; `build` refuses a schematic whose netlist differs from the circuit; `check` compares the schematic's netlist with the model and the board (c0063). The own reading equals the export of `kicad-cli` 9.0.9 and 10.0.6 on the examples and on 25 generated designs.
19
+ - New command `parity` and `check` stage `parity`: schematic against board and symbol pins against footprint pads, without KiCad for generated projects, cross-checked with KiCad's parity test when it runs. Its counts per type equal KiCad's on the public demos of 9.0.9 and 10.0.6 (c0072).
20
+ - `fenolite bom` and `fenolite pnp`: the bill of materials and the placement table of a project as neutral tables, rendered to CSV through a user-written column template (names, order, grouping, units, origin, side names, rotation rules); no template of any assembly service ships. The bill has two sources: the model (`--source model`) and `kicad`, the default, whose parts come from `kicad-cli sch export bom` on a copy of the project's schematic, one row per reference, and Fenolite groups them under the user's column template. Options `--kicad-cli` and `--timeout`; code `bom.field-unsupported`; `counts.left_out` is `null` for this source. Measured on KiCad 9.0.9 and 10.0.6: the export's rows (`H-K-BOM-CSV`), the parts of a built model equal to KiCad's (`H-K-BOM-MODEL`) and the placement rows (`H-K-POS-ROWS`) are `KICAD-VERIFIED` (c0064; guide `docs/assembly.md`).
21
+ - `fenolite manifest`: a project manifest with the SHA-256 and a state (`generated`, `checked`, `roundtrip-ok`, `native-verified`) for every design file and artefact, and `--verify` to compare it with the files on disk; `--manifest` on `export`, `render`, `bom` and `pnp` now merges into the folder's manifest instead of replacing it. Each entry says in `held` what its next state is missing. A state is read from the stages of `check` and never says more than they do: a board is `native-verified` when KiCad's DRC reports no error, a file made from it stops at `checked`, and a schematic, its symbol libraries and their table are `native-verified` when KiCad's ERC reports no error. Manifests written by v0.1 are still read (c0065; guide `docs/exports.md`).
22
+ - New commands `diff`, `roundtrip`, `fmt`, `explain`, `restore`, `net`, `region` and `neighbors`; `--limit` and `--cursor` page a command's main list, `--format concise` keeps one issue per code; receipts carry an `id` and the `undo` command (c0066). `diff` lists the exact differences between two boards, libraries or built models (a moved footprint is one change) and has a tree view of two KiCad files; `roundtrip` says whether a file survives RT0, RT1 and, through `kicad-cli`, RT2; `fmt` writes Fenolite's canonical print, a fixed point over the corpus; `explain` knows every error and issue code; `restore` puts back the backups of a confirmed write and deletes nothing. `diff` compares two schematics in its model view (`diff_sheets`: symbols by reference and unit, sheet references and embedded symbols by name, labels and no-connect flags by content), and `roundtrip` reaches RT1 on a schematic through the schematic reader's rebuild. The fixed point of `fmt` is measured over the 132 schematic rows of the corpus as well. `roundtrip --level rt2` also judges the schematic of a project (`result.rt2.schematic`): KiCad's ERC on the project and on Fenolite's re-dump of its sheets must give the same kinds of violations, the sheet, type, severity and exclusion of each (`ErcReport.kinds()`), and `exact` says whether the items agreed too. The item KiCad names for one violation can differ between two runs on one unchanged project, on 9.0.9 and on 10.0.6, so the items are not compared; a project on which the kinds do not repeat is not judged.
23
+ - `capabilities` lists `result.matrix`: for each backend and file kind, the evidence level of `detect`, `read`, `write`, `roundtrip_exact` and `roundtrip_modified`, the hypotheses behind it and the operations that are experimental. Every backend module now declares its evidence, and `docs/evidence/matrix.md` is generated from the declarations (`tools/gen_evidence_matrix.py`, with `--check`). A backend module without a declaration fails `tests/unit/backends/test_evidence_declared.py`, whose message says what to add, and every declared level is held to `docs/hypotheses.md`. The KiCad backend lists the write kind `kicad_lib_table`, and the Altium schematic reader's evidence no longer names the refuted `H-A-RD-SCH-TEXT` (c0067).
24
+ - `moved()` takes module paths and `moved_net()` renames nets without losing their routing; a footprint renamed through an alias keeps its KiCad edits (its uuids and its group memberships follow the new path); `fenolite sync --to-source` writes `placements.toml`, which `build` reads beside the script, for both targets and with `--discard-layout` too; `sync --check` fails when the committed file is stale, and `sync` reports what the next build would drop (`sync.orphan`, `sync.net-dropped`, `sync.value-differs`). `sync` also writes `schematic-placements.toml` from the symbols moved in KiCad's schematic editor, and reports a symbol it cannot hold with `sync.symbol-off-grid` (c0069).
25
+ - Six more rule kinds (hole to hole, hole clearance, annular width, courtyard, silkscreen, creepage) in the model, the `.kicad_dru` writer and reader, and `design.rules.rule()` with selectors from `fenolite.dsl.select`. Each kind is written only for the KiCad majors that enforce it: creepage rules are written for KiCad 10 only, and a build for KiCad 9 refuses them unless `--allow-lossy` drops them. A hand-written rule of one of these kinds is now read into the model instead of being kept opaque (c0071).
26
+ - Exact `Quantity` values in the DSL (`ohm("4k7")`, `farad("100n")`), typed `I2C`, `SPI`, `UART` and `USB2` interfaces with `attach` by role, and build warnings for differential-pair names KiCad does not pair (`build.diff-pair-name`) and for I2C lines without a pull-up (`build.i2c-pullup-missing`). A `Part` value given as a quantity is stored as its canonical text (`4.7kΩ`). KiCad 9.0.9 and 10.0.6 pair two net names that are equal except for a last `P`/`N` or `+`/`-` (c0073).
27
+ - `design.sheet()` and `design.title_block()` put the user's drawing sheet and title block on the board, and on the schematic when a build writes one: the build writes `<name>.kicad_wks` from a `.kicad_wks` or `*.sheet.toml` beside the script; `fenolite export --preset` applies the user's fab options from a TOML file; board outlines join endpoints closer than 10 µm and include footprint edge items, so all 21 demo boards close; stitching avoids rule areas that forbid vias and the board edge. KiCad 9.0.9 and 10.0.6 close an outline across a gap below 10 µm (c0074).
28
+ - New in the DSL: `Part.zone_connection`, `arc_to`, and `kind=` for vias; `build` reports `result.copper.arcs` and `result.preserved.pad_zones`. New command `pads` (c0068).
29
+ - DSL symbol authoring: design-attached `Symbol` definitions resolve custom component pins and are written as project-local KiCad symbol libraries with a `sym-lib-table` (c0058).
30
+ - Footprint DSL: `Footprint.pad(..., shared=True)` can author additional physical pads with the same number as an earlier pad, with stable unique IDs; accidental duplicates still fail.
31
+ - An offline catalog authored for Fenolite: 49 generic schematic symbols (passives, semiconductors, protection, power and control parts, electromechanical parts) and 100 footprint variants (chip and MELF parts, small-outline diodes and transistors, SOIC, TSSOP, MSOP and SSOP, QFN and DFN, QFP, DIP, 2.54 mm headers, connectors, buttons, radial and axial parts, mounting holes, a test point), with discovery through the API and `fenolite catalog`, resolution at build without a fetch, and project overrides. Every entry cites its public source; a symbol states a function and not a pinout, and a footprint is assigned in the script, never guessed. Land patterns are `INFERRED` starting points that need a review per part and process. Body outlines are on `F.Fab`, so silkscreen does not cross copper (c0075, c0076).
32
+ - Symbol definitions and DSL-authored symbols now carry ordered vector body graphics, which the KiCad symbol reader and writer preserve; the writer also keeps hidden pin-name and pin-number settings on a round trip (c0075, c0076).
33
+ - The `altium` backend reads `.PrjPcb`, `.SchDoc`, `.SchLib`, `.PcbDoc` and `.PcbLib` into the neutral model (nets from wires, labels, ports, power ports, buses and harnesses); a project read links footprints to schematic components by unique-id path and PCB nets by name. On four public Altium-saved projects from four repositories the schematic netlist equals the pad netlist of the PCB document, and the board import agrees with `kicad-cli pcb import` 10.0 (c0043).
34
+ - Model: `Circuit.buses` (`Bus`, `BusMember`), `PadstackLayer.offset`, and `ComponentBody` on footprint instances and definitions, with the findings `model.duplicate-bus-index` and `model.body-height`; all additive, the schemas are regenerated (c0043).
35
+ - `fenolite.backends.altium.read.bodies` decodes the component-body records of PCB documents and libraries byte for byte (c0043).
36
+ - Altium schematic reader: `fenolite.backends.altium.read.sch.read_schematic` reads `.SchDoc` and `.SchDot` files (binary and ASCII), and `read.schlib.read_schlib` reads `.SchLib` files into typed records with an owner tree. Unknown keys, records, streams and trailing bytes are preserved; streams rebuild byte for byte. Nine schematic and nine library rows join the corpus, and `tools/altium_census.py` reports their census (c0040).
37
+ - Altium PCB reader: lossless typed readers for Altium `.PcbDoc` and `.PcbLib` files preserve record bytes and keys, accept long and short record forms, and report located issues with strict mode available. Checked against eleven public files and KiCad CLI import/upgrade (c0041).
38
+ - Altium verification: `fenolite check` and `fenolite inspect` accept Altium documents and projects, read-only and without external tools; the round-trip levels RT-A0 (container copy), RT-A1 (records per stream) and RT-A2 (model → Altium → model on built projects, for what the built model holds: the circuit and the net classes); `fenolite diff A B` reads Altium inputs in its model view and gains a records view (`--view records`) for two Altium files of one kind; results over the public corpus in `docs/evidence/altium-roundtrip.md` (c0044).
39
+ - Design equivalence: `fenolite equivalent A [B] --level N` compares two designs at levels 1 to 4 (components, netlist as `REF-PIN` sets, footprints and pads, placement) with located differences, integer tolerances (`--tolerance-nm`, `--tolerance-udeg`), `--frame relative` and exclusion profiles; `--against kicad-import` compares Fenolite's read of a PCB document with `kicad-cli pcb import` (10.0 only) under a per-version exclusion list; results per corpus row in `docs/evidence/equivalence-triangle.md` (c0045).
40
+ - Altium sheet templates: `fenolite template import SRC --target kicad --out OUT` imports a `.SchDot` (or the template graphics of a `.SchDoc`) into the neutral drawing sheet and writes a `.kicad_wks`; size, lines, rectangles, texts, special strings and embedded PNG images are imported, everything else is reported, and a loss needs `--allow-lossy`. Writing a `.SchDot` is not included (c0046).
41
+
42
+ ### Changed
43
+
44
+ - Built projects change once. The next build of a v0.1 project adds the schematic files, with new files under `sheets/` and new footprint paths for parts in modules, and renames, in the board file only, the nets of unconnected pads (`unconnected-(U1-PA1-Pad2)`) and of nets with a slash (`mod{slash}LED_A`). Layouts, positions, tracks and zone fills are kept, and no other net is renamed (c0061, c0070).
45
+ - `fenolite check`: the `erc.lite` stage is removed from KiCad checks (`--stages erc.lite` is now a usage error), and the hermetic stage list is `--stages model.validate,roundtrip` (c0062). `fenolite check` now treats a pad on no net as a block of its own, reads the `N/C` label of the IPC-D-356 export as no net, and names a model pin by its pad when the part has a `pad_map`.
46
+ - `check` and the copper guard of `build` now apply a zone's own clearance between a fill and other copper, as KiCad's DRC does, and place the copper of a pad with an offset drill where KiCad places it: boards may gain `copper.clearance` findings of source `zone` and lose false ones on such pads (`--copper-check warn` writes anyway). `BoardPad.hole` of such a pad is back at the pad's position. The facts are measured on KiCad 9.0.9 and 10.0.6 (c0068).
47
+ - `fenolite capabilities` lists two backends, `altium` before `kicad`: select a backend by its `name`, not by its position (c0043).
48
+ - A component whose value is empty in the script is stored in the built model of an Altium build with the value its documents hold, the symbol's name (c0044).
49
+ - Examples: `examples/blink_2layer` marks its 29 unused pins with `no_connect` and `examples/blink_routed` marks its unused pins, so their schematics pass KiCad's ERC; the boards are unchanged, and the blink gets its resistor beside the controller pin on the sheet. `examples/blink_official` connects the analog supply pins of its microcontroller and marks its unused pins: KiCad's ERC reports nothing on it (it reported 29 errors and one warning). An authored symbol library for KiCad 9 now carries the 9.0 header version (`20241209`, was `20231120`).
50
+ - Development: Archived the completed specs of c0040 to c0046, c0060 to c0069, c0071 to c0076 and c0082, and cited their CI runs in the hypothesis register. A nightly job, `macos-app`, runs the KiCad tests on the `kicad-cli` of the 10.0.6 macOS disk image. The worksheet version oracle runs on fresh copies with its own configuration folders (c0082); the oracles of the Altium readers share one table of the corpus rows on which the Linux build of `kicad-cli` 10.0.6 fails in its own importer; a cost test of the Altium schematic reader counts calls instead of comparing times; cross-platform path assertions were repaired. None of this changes what the command line or the library does.
51
+
52
+ ### Fixed
53
+
54
+ - `route` no longer hands a router the one-pad `unconnected-(…)` nets that a build gives unused pins since the schematic writer: with them Freerouting left one connection of the 40-part example open.
55
+ - A component read from an Altium PCB document takes the designator text the board shows as its reference, and its source designator only without one, so the components of a repeated sheet no longer share a reference in a board read on its own; the fault was found by the equivalence triangle (c0045).
56
+ - `fenolite bom` no longer puts a part marked "do not populate" (DNP) on the line of fitted parts of the same value: with `exclude_dnp = false` in the column template, a line is all DNP or all fitted, whether or not `group_by` names `dnp`, for both sources, so no quantity counts a part that is not fitted. A DNP line stands where its first reference puts it, like every line. With `--against`, the `key` of a DNP line ends with `DNP` (c0094; guide `docs/assembly.md`).
57
+
58
+ ## [0.1.0] - 2026-10-05
59
+
60
+ ### Added
61
+
62
+ - v0.1 acceptance: a second example board of forty parts, the loop proved on both examples and both KiCad majors, the agent guide `agent/SKILL.md`, the `wheel` and `dco` jobs, Windows and Python 3.11 to 3.13 in CI, and the release record `docs/release/v0.1.md`.
63
+ - Altium project reader (c0042): `fenolite.backends.altium.read` reads the project file (`.PrjPcb`: documents and their kinds, parameters, the `[Design]` options and the hierarchy mode), output jobs (`.OutJob`), rule files in the export and the summary form (`.RUL`) and stack-up files (`.stackup`), each given back byte for byte with its byte-order mark, line ends, encoding and unknown keys. `rules.map_rules` maps Clearance, Width, Routing Via Style and Hole Size records onto the neutral rules through closed tables and a closed scope grammar, and lists every other record with one of ten reasons; `project.load_project` reads a project folder and its text companions for the import. Twelve public files join the corpus (`uses = altium-text`); project files and output jobs are `CORPUS-VERIFIED`, the rest `INFERRED` (`docs/evidence/altium-project-read.md`).
64
+ - Board analyses: `fenolite analyze PATH` measures the current capacity of tracks, arcs and vias from one published fit (each constant recorded with its source in `docs/analyses.md`; `decimal` arithmetic, rounded down), the clearance of pairs of nets through air, and their creepage along the board surface, around cut-outs and around the board edge (`fenolite.analysis`). Fenolite measures and the user decides: requirements come from a user TOML file (`fenolite.requirements.v0`, integers only, a voltage table looked up without interpolation), no requirement value and no default thickness or temperature rise is shipped, and every reply is `INFERRED` or lower. Ten `analysis.*` codes; an error finding exits 5. A recorded probe on `kicad-cli` 10.0.6 shows that KiCad's `creepage` rule agrees with Fenolite around a slot (11 mm) and reports nothing for copper on opposite faces across the board edge.
65
+ - DSL footprint authoring: a design-scoped builder creates pads and graphics; exact-ID assignments resolve in KiCad and experimental Altium builds (c0055).
66
+ - DSL component pin-to-pad mapping and authored slotted drills; KiCad writes supported aligned oval drills, while Altium reports its unsupported slot geometry (c0056).
67
+ - Compound-file reader for the second backend: `fenolite.backends.altium.read.cfb` reads MS-CFB versions 3 and 4 with DIFAT sectors and the mini stream, returns storages and streams by path, reports located errors and notes, and is bounded against hostile files; `fenolite inspect FILE --streams` lists the stream tree; ten public files join the corpus and CI fetches them before corpus tests (c0039).
68
+ - Routing plugins: a router protocol with an entry-point registry, `fenolite route` with the built-in `direct` router and the KiCadRoutingTools plugin (an external MIT tool run as a subprocess at a pinned tag), routed copper merged into the board and kept by later builds (c0016).
69
+ - Design rules in the script: `design.rules.minimum(clearance=…, track_width=…, via_diameter=…, via_drill=…, hole_size=…, edge_clearance=…, netclass=None)` declares design-rule minimums for the board or for one net class. They reach `rules.json`, the custom rules of `<name>.kicad_dru` and the board-setup minimums of `<name>.kicad_pro`, and `kicad-cli pcb drc` 9.0.9 and 10.0.6 enforce them (`H-K-DSL-MINIMUM`). The Altium build does not write them and reports them with `altium.not-lowered` (c0054).
70
+ - Freerouting plugin (c0023): `fenolite route --router freerouting` routes a board with Freerouting 2.4.1, a GPL-3.0 autorouter run as a subprocess with its analytics disabled (`FENOLITE_FREEROUTING_JAR` or `--router-path`, Java 25, `--router-option max-passes=N`; `docker:<image>` runs a container without a network). Fenolite writes the Specctra design file itself and reads the session back (`fenolite.backends.specctra`: `dsn.write_dsn`, `ses.read_session`, `ses.to_copper`, a codec and not a registered backend): one image per footprint, board-frame padstacks, nets and classes, keep-outs, existing copper as protected wiring. `RoutingJob.extra` carries the board-frame pads and the outline to plugins; `doctor` reports the jar and its Java; `route.option-ignored` is a new issue code. The router is listed with `sends_data_offsite: true` and needs `--allow-offsite` until its run without a network is recorded. ADR-0006 (`Proposed`) covers the facts taken from the Specctra reference.
71
+ - Zone fill: `fenolite fill` refills a board through `kicad-cli` 10 on a copy and writes the fills into the board for its own KiCad major, target 9 included; `check` gains the `zone.fill` stage; `--kicad-cli docker:<image>` runs `kicad-cli` in a container (c0015).
72
+ - Placement: `fenolite place` puts staged parts on the board in a deterministic grid or moves named parts, a legality check reports courtyard overlaps and parts outside the outline in `build` and `place`, and a placed part is kept by later builds. `fenolite place PATH` (`--strategy grid|manual`, `--move REF=X,Y[,ROT[,SIDE]]`, `--only`, `--pitch`, `--gap`, `--margin`, `--force`, `-o`) writes only with `--confirm` and refuses an illegal placement without `--force`; `fenolite.placement` holds `check` (exact courtyard overlap, outside-outline and edge-clearance tests on `PlacedExtent`s) and the grid placer; `backends.kicad.replace.move_footprint` translates a footprint or re-places it from its library definition with its uuid, fields, lock and pad nets kept; `backends.kicad.outline.board_outline` gives the outline as rings from the model or from `Edge.Cuts`; `fenolite build` reports `place.*` issues as warnings (`result.placement`) and never refuses for placement. Probes on `kicad-cli` 9.0.9 and 10.0.6: moved footprints read back at the requested position, rotation and side with their pad nets, and courtyards that only touch give no `courtyards_overlap`. `H-K-PLACE-MOVE` and `H-K-PLACE-TOUCH` are `KICAD-VERIFIED (9.0.x, 10.0.x)`, so a `place` reply carries `evidence.level` `KICAD-VERIFIED`; the outline rings stay `INFERRED` (`H-G-PLACE-OUTLINE`: 3 of 21 demo boards have an outline in KiCad and no ring here). KiCad's DRC judges the board (change c0022).
73
+ - Footprint fields: Reference, Value and every placed property of a footprint are typed fields (position, angle, layer, visibility, size, thickness, justification, mirror), read from 8.0 to 10.0 boards and written for 9.0 and 10.0; `Part.field(...)` and `fields(design)` place Reference and Value from the DSL, also outside the courtyard on a chosen side; rebuilds keep fields edited in KiCad unless the script locks them (`result.preserved.fields`); checked by `kicad-cli` 9.0 and 10.0 (`fenolite.model.FootprintField`, `fenolite.backends.kicad.fields`, `fenolite.lens.fields`; c0030).
74
+ - Zone settings: zones carry typed settings (clearance, minimum thickness, pad connection solid/thermal/none/thru-hole-only, thermal gap and spoke width, island removal, smoothing, hatched fill), read from KiCad 9.0 and 10.0 boards and written per target; pads carry a zone connection override; `Design.zone()` declares pours in design scripts, and rebuilds keep zones edited in KiCad unless the script locks them; created target-9 zones write `(filled_areas_thickness no)`, so their fills are plotted as written; checked by refills on `kicad-cli` 10.0 and loads on 9.0 (c0031).
75
+ - Copper check: Fenolite now judges shorts and clearance of a board's copper itself, exactly and without `kicad-cli`. `fenolite.geometry.thick` gives thick shapes (a core swept by a disc) with exact touch, closer-than, gap and witness tests; `fenolite.checks.check_copper` judges tracks, arcs, vias, board-frame pads and zone fills pair by pair, with the clearance in force taken from the project's own rules, net classes and board minimum (`checks.clearance`, `backends.base.DesignRules` and `DesignRulesSource`, `backends.kicad.copperrules`); `fenolite check` gains the default stage `copper.clearance`, between `erc.lite` and `drc.kicad`, and six codes (`copper.short`, `copper.clearance`, `copper.zone-overlap`, `copper.rules-incomplete`, `copper.item-unsupported`, `copper.clearance-unset`); `fenolite build` judges the triad it is about to write and refuses a short or a clearance error (`--copper-check refuse`, the default) or reports it and writes (`--copper-check warn`), with `result.copper_check`. Probes on `kicad-cli` 9.0.9 and 10.0.6 show why: a via that touches a track of another net whose net owns a pad is loaded on that net and no short is reported, copper without pads is merged into one net, and 10.0.6 reports a short between two nets with pads in about half of its runs; the verdicts of `check_copper` and of KiCad's DRC agree on every parity canary (seven pair kinds under a rule, a class and a board-minimum clearance, six resolution cases, and zone fills on 10.0.6). A board that holds a real short now exits 5 under `check` (`docs/formats/kicad/copper.md`, `docs/evidence/copper-check.md`, change c0029).
76
+ - Board-frame queries and manual copper: `board_pads`/`find_pads` give every pad's board-frame position, rotation, layers, net, hole and exact copper entries (all pads sharing a number); `placed_extent` gives a placed footprint's front and back courtyard with rotation and side applied; `BoardFrame` in `backends.base`; DSL copper intents (`Part.pad`, `via_step`, `Design.track`, `Design.via`, `Design.stitch`) resolved by the build after placement, with nets inferred and checked, version-8 uuids from the caller's key, and stale script copper removed on rebuild; checked by `kicad-cli` 9.0 and 10.0. `fenolite build` reports `result.copper`; the routed example is `examples/blink_routed`, and the guide is `docs/copper.md` (c0028).
77
+ - Altium change order without class differences (change c0048): a net class is declared in the schematic by a Parameter Set directive with a `ClassName` parameter on each of its nets, once per sheet, and a new project file ends with `[PrjClassGen]` (`NetClassManualEnabled=1`), so "Design » Update PCB Document" no longer proposes to remove the class from the board; the PCB document holds one component class per schematic sheet (named after the module, or after the sheet for the top sheet and for the single sheet of a flat build), and a project file with a PCB document or module sheets turns the rooms off for every schematic document. "Supply Nets" rules and rooms are not written and are documented as differences Altium may still propose (`docs/altium.md`, "Change order"). The golden schematics and project files of the samples with a net class or module sheets are rebuilt. Experimental; the maintainer's report of 2026-10-04 (AD 26.5) found only the "Supply Nets" rules in the change order of a build with module sheets, and the repeat of the same day on the rebuilt samples found the same for a flat build (`H-A-ECO-SHEETCLASS`; Part E of `docs/evidence/altium-pcb.md`).
78
+ - Altium PCB copper: the experimental `<name>.PcbDoc` now holds tracks, arcs and through vias, zones as unpoured polygon pours (repour in Altium), a 2- or 4-layer stack whose inner layers are signal layers or internal planes (`design.board(..., copper=4, planes={...})`), net classes and Clearance, Width and Routing Via Style rules; `--copper-from board.kicad_pcb` copies the copper of a routed KiCad board after checking that it matches the design, and the board's placements win; blind, buried and micro vias, split planes and copper outside the stack are refused; checked by `kicad-cli pcb import`; evidence `INFERRED`, with the maintainer's Altium Designer report recorded as an author report (c0038).
79
+ - KiCad libraries: pinned fetch and verified cache of the official libraries at 10.0.6 and 9.0.9 (`tools/kicad_libs_fetch.py`, `FENOLITE_LIBS_CACHE`), a `cache` library source, opt-in `kicad_common.json` path variables (`LibraryConfig.read_common`), a directory-scan fallback (row origin `scan`), builds that resolve from the cache and report `scan` rows, a census of the fetched trees (the 10.0.6 install equals its pinned tag), demo-library corpus rows (`libs`), an `env` keyword on `KicadCli.drc`, and `kicad-cli` probes for relative paths, the versioned fallback, nested tables, the configuration folder and KiCad's own path variables. The probes refuted one rule: KiCad resolves a relative library `uri` against its working directory, not against the table's folder, so the resolver now joins a relative `uri` to the project folder for rows of every table (a nested table's `../x` now means the folder above the project, not above the nested table).
80
+ - No-connect pins: `fenolite.dsl.no_connect(*pins)` marks pins as intentionally unconnected; the model keeps them as `Circuit.no_connects` (additive, schema regenerated); the Altium schematic gets a No ERC directive (record 22) at each marked pin, in both forms; the KiCad build keeps the marks in `.fenolite/` and refuses a marked pin on a net (`build.no-connect-on-net`, `model.no-connect-on-net`); `erc.lite.floating-pin` skips marked pins; evidence `INFERRED`, with the maintainer's Altium Designer report recorded as an author report (pending: Part N of `docs/evidence/altium-schematic.md`).
81
+ - Altium hierarchy and harnesses: `fenolite build --target altium --altium-sheets modules` writes a top sheet with sheet symbols and one sheet per top-level module, with matching ports and sheet entries; `fenolite.dsl.Harness(name, members)` groups nets, drawn as harness connectors, entries and signal harness lines in the binary schematic, with `.Harness` definition files; the PCB document links parts on module sheets through their sheet symbol; the default `flat` output is unchanged; evidence `INFERRED`, with the maintainer's Altium Designer report recorded as an author report (c0037). After the maintainer's report of 2026-10-03 (AD 26.5): a harness between two neighbouring modules is drawn on the top sheet as one signal harness line between the two sheet entries, without connector blocks and labels, which removes the "multiple names" warnings; the top sheet then gets no `.Harness` file; a new project file of a `modules` build lists the schematic documents first and together (the top sheet, the module sheets, then the PCB document, the libraries and the harness files), because with the PCB document and the libraries in between Altium Designer took only the first module sheet into the hierarchy (`H-A-SCH-HIER-ORDER`, confirmed by the maintainer's second report; the earlier guess about small sheets, `H-A-SCHBIN-MINI`, is refuted and its padding parameter `FenoliteNote` is removed); a flat build keeps its project file bytes, and an existing project file is kept as it is; `CHANNELOFFSET` of a PCB component counts the parts of its own sheet; a readback test checks that every board component links to a schematic component through a sheet symbol and that every module sheet is reachable from the top sheet.
82
+ - `fenolite export` and `fenolite render`: fabrication files (Gerbers and the job file, drill, positions, IPC-D-356) and review views (SVG plots, rendered PNG) through `kicad-cli` on a copy of the project, written only with `--confirm`, with the manifest `fenolite-artifacts.json` (`schemas/fenolite.artifacts.v0.json`): per file its SHA-256 and a date-stripped `content_sha256`, because KiCad stamps the creation date into Gerber and drill files. When one kind fails nothing is written. Opt-in `render` stage in `check` (`--stages render`), which never gives an error. Commands may declare `example_tools`, and the suites run such examples against a fake `kicad-cli`. Measured on `kicad-cli` 9.0.9 and 10.0.6 (`docs/evidence/kicad-export.md`); user guide `docs/exports.md` (c0024).
83
+ - Altium target writes PCB files: `fenolite build --target altium` writes `<name>.PcbLib` with the resolved KiCad footprints (SMD and through-hole pads, roundrect corners, silkscreen, fabrication and courtyard lines and arcs) and, experimentally, `<name>.PcbDoc` with the outline, two-layer stack, placed components, pads, nets and designators, linked to the schematic by unique ids; empty streams in compound files; write kinds `altium_pcblib` and `altium_pcbdoc`; new `altium.*` issue codes; kicad-cli `fp upgrade` and `pcb import` as oracles; capabilities entry `altium-pcb-writer`; evidence `INFERRED`, Altium checks as author reports.
84
+ - `fenolite check` judges KiCad DRC violations as located `kicad.drc.<type>` issues, compares the pad nets of model, board and IPC-D-356 export, and runs RT2 on request; RT0 to RT2 pass on the corpus with kicad-cli 10.0.6 and on the 9.0.9.1 demo boards in the `kicad-9` job. Findings carry KiCad's severity (which follows the project's `rule_severities`) and are located as `REF-PIN`, `REF`, a board locator or the report position; an unrouted board now exits 5. `netlist.assignment_compare` (default stage) compares partitions of `REF-PIN` elements and locates a reassigned pad; `roundtrip.rt2` (opt-in with `--stages`) fails only where KiCad repeats its own DRC report and otherwise says that RT2 is not judged, because on boards with hundreds of violations two DRC runs of one file differ. New: `checks.{drc_json,assignment_compare,rt2}`, `backends.kicad.padnets`, `KicadOracle.netlist` and `.rt2`, `NetlistOracle`, `RoundTripOracle`, `PadNetList`, `NetlistOutcome` and `Rt2Outcome` in `backends.base`, `DrcReport.entries()`, the `rt2-9` corpus rows, and four recorded measurements (token census, 10.0 byte identity, 5 MiB throughput, Edge.Cuts chaining: one demo outline is open by 33 nm) (`docs/evidence/kicad-rt2.md`, `docs/cli-contract.md`).
85
+ - Altium target writes schematic libraries: `fenolite build --target altium` writes `<name>.SchLib` with the resolved KiCad symbols (pins, units, Part Zero, synthesised body) and a generic `X.SchLib` for each Altium link library, lists them in the project file and draws the schematic from the same geometry; `cfb.Storage` for nested storages; write kind `altium_schlib`; new `altium.*` issue codes; kicad-cli `sym upgrade` round trip as oracle; evidence `INFERRED`, Altium checks as author reports (c0034).
86
+ - Layout preservation: `fenolite build` over an existing project keeps footprints moved in KiCad (matched by uuid, `fenolite.path` or a `moved(old, new)` alias, with the precedence locked `place()` > board > `place()` > staging), routing and zones on nets that still exist, fills while their digests are unchanged (`zone.fill-stale` otherwise), board-only footprints with their pins on their pads' nets, board settings, project keys and user custom rules after Fenolite's; removed parts give `layout.orphan`; `fenolite check` no longer asks footprints added in KiCad for a symbol; rebuilds and a regenerated `.fenolite/` are byte-identical; `build.layout-exists` now guards only `fp-lib-table` and vendored footprints; checked by `kicad-cli` 9.0 and 10.0 (`fenolite.lens.preserve`, `Design.moved`, `dsl.moves`, `result.preserved`, `docs/lens.md`).
87
+ - Altium target writes the binary schematic by default: `fenolite build --target altium` writes `<name>.SchDoc` as an MS-CFB compound file (stdlib writer; `FileHeader` and `Storage` streams; deterministic bytes); `--altium-format ascii` keeps the ASCII form; write kind `altium_schdoc_binary`; issue `altium.schematic-too-large`; evidence `INFERRED`, with the maintainer's Altium 365 Viewer and Altium Designer checks recorded as author reports.
88
+ - Experimental Altium target: `fenolite build design.py --out DIR --target altium` writes an Altium project file (written once) and an ASCII schematic with one generic component per part, library and footprint links, net labels and power ports on wire stubs, a deterministic grid layout and path-keyed unique ids; listed under `result.experimental` of `fenolite capabilities`; evidence `INFERRED`, with the maintainer's Altium checks recorded as author reports. Power ports of adjacent pins alternate between short and long stubs, so they do not overlap.
89
+ - Build properties and vendoring: DSL parts take `properties={…}` (printable text, reserved KiCad and Fenolite names refused), written as hidden properties after `fenolite.path` and read back unchanged; `fenolite build` copies the placed footprints of every library row (project, global, template) into `lib/` with project rows, so built projects pass `kicad-cli`'s library check in isolation (`--vendor project` keeps the old rule); new codes `build.property-reserved`, `build.property-invalid`, `build.property-conflict`, `build.vendor-unsafe-name` and `build.library-changed`. Measured on `kicad-cli` 9.0.9 and 10.0.6: vendored global footprints give no library violation, a project row hides a global row of the same nickname, and user properties load and survive a 10.0.6 re-save.
90
+ - Read-only `fenolite check` v0 (model validation, ERC lite, KiCad DRC with a scoped rules canary, RT1) with evidence per stage, plus `fenolite inspect --summary` and `fenolite doctor`; `kicad-cli` runs only on a closed copy of the project (`fenolite.checks`, `fenolite.backends.kicad.{projectset,canary,oracle,roundtrip,helpmatrix}`, `KicadBackend.validate`, `kicad_cli_candidates`, neutral `RoundTrip`, `Validation`, `Validator`, `ProjectSet`, `DrcOutcome` and `Oracle` in `backends.base`, `docs/formats/kicad/cli.md`, `docs/evidence/kicad-check.md`). Observed on 9.0.9 and 10.0.6: DRC on the copy set equals DRC on the whole folder, the canary fires once, changes nothing else and is silenced by a dropped rules file or an ignored clearance severity, help pages follow one `Usage:` grammar, and KiCad writes a DRC report for boards Fenolite refuses for trailing content. On some boards kicad-cli 10.0.6 does not repeat its own DRC report between identical runs (the partner item of a clearance violation, sometimes the count), so DRC comparisons repeat their reference run. The canary tracks change other violations of large boards on 9.0 and 10.0 (other partner items, sometimes one violation more or less), so on both majors `drc.kicad` runs DRC twice: a plain run gives the counted report and the canary run the verdict. The copy set, the canary verdict and the help grammar are `KICAD-VERIFIED` on 9.0 and 10.0, and so are the `drc.kicad` stage's oracle and `fenolite doctor`'s matrix.
91
+ - Sheet templates: a neutral drawing-sheet model with the board's paper and title block, a `.kicad_wks` reader and writer whose single output KiCad 9.0 and 10.0 load, project keys for the sheet and text variables, `fenolite template build` from closed `*.sheet.toml` files with per-number provenance, two CC0 examples, and one sheet drawn as predicted on A4 and A3 boards by `kicad-cli` 9.0 and 10.0 (`fenolite.model.presentation`, `fenolite.backends.kicad.wks`, `fenolite.templates`, `pcb.project_paper`/`paper_node`/`title_block_node`, `pro.apply_sheet_keys`, `schemas/fenolite.model.v0/drawing_sheet.json`, `docs/formats/kicad/worksheet.md`, `docs/formats/sheets.md`, `docs/sheet-templates.md`, ADR-0005 `Accepted`). Observed on both majors: a `User` page is truncated to whole mils, so `H-K-PCB-PAPER` is refuted and superseded by `H-K-PCB-PAPER-2`; KiCad draws sub-micrometre sheet lengths unchanged, so `H-K-WKS-RES` is refuted and superseded by `H-K-WKS-RES-2`; numbers step past `9` in repeated labels, and legacy `%` codes still resolve.
92
+ - KiCad board-setup minimums: the design's board-wide rules now lower into `board.design_settings.rules` of `.kicad_pro` on synthesis and update, so Board Setup shows the fab rule set's values, and class clearances that a board-wide rule overrides are reported (`kicad.project.class-shadowed`). Measured on `kicad-cli` 9.0.9 and 10.0.6: the five minimum keys are read and applied, a board-wide custom rule governs below the minimums although the manuals call them absolute (`H-K-PRO-MIN-RULE` refuted, `H-K-PRO-MIN-RULE-2`), and such a rule overrides a larger class clearance (`lowering.lower_minimums`, `class_conflicts`, `pro.project_minimums`, five `kicad.project.*` codes, `pro-min-*` probes).
93
+ - Thin DSL and build: `fenolite build design.py --out DIR` turns a stdlib-only `design.py` into a self-contained KiCad 9.0 or 10.0 project (triad, vendored footprints, per-target `fp-lib-table`, `.fenolite/` cache and build record) with ids keyed by names and paths, byte-identical rebuilds, a refusal to overwrite outputs edited since the last build (`--discard-layout`), `FEN-3005` for geometry errors, refusals that list their issues, and the CC0 blink checked by `kicad-cli` 9.0 and 10.0.
94
+ - Roadmap to 1.0 (`docs/roadmap.md`): phases and change ranges, where KiCad ends and the second backend starts, budgets, and proposed cuts for a leaner 1.0 (pending the maintainer's decision).
95
+ - KiCad project files: an exact JSON codec, `.kicad_pro` synthesis from GUI-saved templates for KiCad 9 and 10, in-place updates of managed keys with unknown keys preserved, net classes read into and lowered from the model, and `write_triad`, which always ships board, project and rules together; `kicad-cli` 9.0 and 10.0 enforce the written net classes (`fenolite.backends.kicad.{_json,pro,proerrors,triad}`, `lowering.lower_netclass`, `KicadBackend.lower`, `docs/formats/kicad/project.md`, `docs/evidence/kicad-project.md`, `tests/data/kicad/project/empty_10.kicad_pro`, demo `project` corpus rows). Observed on 9.0.9 and 10.0.6: net-class patterns are whole-name wildcards and regular expressions, a board-setup minimum governs a lower class value, `kicad-cli` never rewrites `.kicad_pro` (10.0.6 writes a `.kicad_prl`), and a `.kicad_dru` is read even without a project file, which partly refutes `H-K-TOK-RULES-SILENT`.
96
+ - KiCad footprint and rules writers: `.kicad_mod` writing for KiCad 9 and 10, a full-dialect `.kicad_dru` reader and writer with comments kept in place, and rules lowering in priority order with a closed selector grammar, target gating and a self-check, each proved on `kicad-cli` 9.0 and 10.0 with a canary rule (`fenolite.backends.kicad.{mod,dru,rulemap,lowering}`, `docs/formats/kicad/rules.md`, `tests/data/kicad/rules/`, `tests/data/libs/Escapes_v9.pretty/`). Footprints placed in boards read as definitions (`board_footprints`); the footprint codec round trip holds over 1 674 demo and 424 upgraded third-party footprints, which settles the footprint half of `H-K-LIB-READ`, and `H-K-SEXPR-ESCAPES` now holds on 9.0.9 too. Observed on both majors: the later rule governs, every selector op and the `*` glob select the model's items, and KiCad compares net and class names without regard to case.
97
+ - KiCad board backend, part 2: a `.kicad_pcb` writer for KiCad 9.0 and 10.0 (net form per target, obsolete rows, token gating with `--allow-lossy`, KiCad 8 boards read-only with `FEN-7003`), library footprints placed on either side with key-derived uuids, DRC JSON reports read into neutral types, the global flags `--kicad-version` and `--allow-lossy`, and written boards, bottom placements and library parity checked by `kicad-cli` 9.0 and 10.0 with probe outcomes pinned per version.
98
+ - Verification evidence: `fenolite.verify` (label grammar with qualified labels, hypothesis-register reader, cited-id scan, `release_verified`) and a guard test that keeps `docs/hypotheses.md` consistent with every hypothesis id cited in live text; refuted rows relabelled, `H-K-LIB-DRC` and `H-G-SHAPELY-GC` registered as pending, author-report rows for the earlier second-backend write validation (never release-verified), the S-0002 licence settled, and the change-id and ADR numbering rules written down.
99
+ - KiCad board backend, part 1: backend protocol and registry (`capabilities` lists backends), a package `kicad-cli` runner on temporary copies, and a typed `.kicad_pcb` reader for 8.0 and newer with lossless slots, same-version rebuild (RT1) over the demos and upgraded third-party boards, and placements and pads confirmed by `kicad-cli` exports on 9.0 and 10.0 (`fenolite.backends.{base,registry}`, `fenolite.backends.kicad.{backend,cli,ipcd356,layers,_fpmap,pcb}`, ADR-0002, `docs/formats/kicad/board.md`, `docs/evidence/kicad-board-read.md`, `tests/data/kicad/board/two_layer.kicad_pcb`). Model: `FootprintInstance.attributes`, `Via.via_type`, `ZoneFill.island`, `Zone.name`, and `model.duplicate-ref` as a warning for board-only and unannotated references. `H-K-PCB-READ` and `H-K-UNIT` are corpus-verified and `H-K-PCB-POS` verified with `kicad-cli` 9.0.9 and 10.0.6. Observed: a 10.0.6 re-save removes teardrop zones and `Footprint` properties and replaces `fp_text` items, so `H-K-UUID-KEEP` is refuted and superseded by `H-K-UUID-KEEP-2`; the IPC-D-356 `R` field of a pad is the negated stored pad angle.
100
+ - KiCad libraries: neutral library definitions (`FootprintDef`, `SymbolDef`), `.kicad_mod`/`.kicad_sym`/`.kicad_symdir` readers with slots, library-table resolution (project, global, template and nested tables, path variables, local install), and an authored CC0 mini library checked by `kicad-cli` 9.0 and 10.0 (`fenolite.model.library`, `fenolite.backends.kicad.{mod,sym,libs,liberrors}`, `schemas/fenolite.model.v0/library.json`, `docs/formats/kicad/libraries.md`, `docs/evidence/kicad-libs.md`, `tests/data/libs/`). The census of the local 10.0.6 install reads 15 450 footprints and 22 860 symbols without error; `H-K-LIB-NAME-STEM` (9.0.9, 10.0.6) and `H-K-LIB-SYMDIR` (10.0.6) verified. Observed: KiCad sorts pads, graphics, symbols and pins when it saves, and the official footprints repeat graphic uuids inside single files.
101
+ - KiCad format versions and gating (`versions.py`), token inventory `tokens.toml` with fuzz results on kicad-cli 9.0.9 and 10.0.6, `kicad-9` CI job and `kicad_min_major` test marker, error codes FEN-3003/FEN-3004/FEN-7002 (`tools/kicad_token_fuzz.py`, `tools/gen_token_docs.py`, `docs/formats/kicad/versions.md`, `docs/formats/kicad/tokens.md`, `docs/evidence/kicad/token-fuzz/`). All 184 inventory rows are verified on both majors; observed: both majors refuse future board headers, and 9.0.9 keeps pad-level tenting and drops the press-fit pad property.
102
+ - KiCad S-expression layer (spelling-preserving parser, KiCad-style and compact printers, fragment codec, tree equality), slots helper with extension-bag persistence, KiCad demo and third-party corpus rows with RT0, and the `kicad-10` Docker oracle job (`fenolite.backends.kicad`, `docs/formats/kicad/sexpr.md`, `docs/formats/kicad/corpus.md`; `FENOLITE_REQUIRE` required-resource mode; `tools/corpus_fetch.py --uses/--exclude-uses`). Verified with `kicad-cli` 10.0.6: lexical acceptance and rejections, string escapes, number reading, re-save equality; `H-K-SEXPR-NUM-WRITE` refuted (KiCad writes non-length values with up to 10 decimals).
103
+ - Geometry kernel: exact integer predicates, three-point arcs, polygons with a canonical normal form, mixed contours, deterministic µdeg transforms, STR spatial index, boolean backend protocol with a convex-only stdlib fallback, and KiCad frame and arc evidence tests (`fenolite.geometry`, `docs/geometry.md`, `docs/formats/kicad/geometry.md`; `H-G-ROT-DIR`, `H-G-BOTTOM-PLACE`, `H-G-ARC-ROUND`, `H-G-ARC-DIR` and `H-G-PTS-ARC` verified with `kicad-cli` 10.0.6).
104
+
105
+ ### Changed
106
+
107
+ - Packaging (change c0052): the `route` extra is removed (it named `freerouting-client`, which no code imports; routers run as separate programs); the package metadata gains `[project.urls]` and the classifier `Development Status :: 3 - Alpha`; the source distribution is built from an allowlist (`src`, `tests`, `docs`, `examples`, `schemas`, `tools` and the project documents) and no longer holds `openspec/`, the agent instruction files, `packaging/`, `uv.lock` or the `Makefile`. The wheel is unchanged.
108
+ - `fenolite capabilities`: the KiCad backend's evidence is computed from what `read` and `write` return and is checked against the hypothesis register: a level stronger than a row it names fails `tests/unit/test_capability_evidence.py`. The level stays `INFERRED`, and `docs/cli-contract.md` explains why the rows it names are stronger.
109
+ - Documents (change c0052): `docs/cli-contract.md` has a `template` section, and the consistency suite fails when a registered command is missing from that page; `docs/provenance.md` explains the private residue gate (the three `FENOLITE_RESIDUE_*` variables, where the gate is on, and that CI runs with it off); the register rows `H-G-ANGLE` and `H-A-UNIT` record what was observed, both still `INFERRED`; two skip guards for things that exist are removed from the tests.
110
+ - Source audit of S-0142: the unpinned AltiumSharp entry is marked not used (version 2 cites non-public decompiled material); the Altium fact rows that cited it are re-sourced (S-0130, S-0131, S-0132, S-0134, S-0143, S-0145, S-0150 at version 1) or kept as `INFERRED` hypotheses with no permitted source, and the `Storage` weight-key contradiction with version 1 is recorded. No written byte changes.
111
+ - Roadmap (`docs/roadmap.md`): the gaps found by a board built only through the public API are proposed as c0026–c0031; change sizes are design-days, and a pace measured from the git history replaces the old time ratio as the forecast; the implementation order now runs c0026 → c0027 → c0013 → c0019 → c0020 → c0021 → c0012 → c0028–c0031.
112
+ - CLI: `--fields` now also restricts the `plan` that the dispatcher adds to `result` on `--dry-run` or without `--confirm`, as the contract says; a refused command lists the `issues` of the raised error in its envelope; `GeometryError` maps to `FEN-3005` (exit 3).
113
+ - The KiCad capability report lists `kicad_pro` in `write_kinds` and `lower` in `operations` (`KicadBackend.lower` returns the board, project and rules files).
114
+ - Development: the test suite runs on parallel workers (`make check`, and `make check-fast` for the tests that need no external tool), the CI jobs record the outcome of every oracle test, internal helpers of the KiCad footprint writer were reorganised, and the repository ignores local build folders. None of this changes what the command line or the library does.
115
+
116
+ ### Fixed
117
+
118
+ - Windows: `kicad-cli.exe` is found on `PATH` and in KiCad's default install folders, which KiCad's installer does not put on `PATH`; files Fenolite writes keep LF line ends; a board on another drive than the working folder can be routed; a drawing-sheet path starting with `/` counts as absolute.
119
+ - `fenolite route` reads the net classes from the project file beside the board. Before, every net was routed with the default track width, clearance and via size, whatever its class said: a KiCad board holds no net class.
120
+ - `fenolite route --router freerouting` lists a net under `unrouted` when Freerouting reports that it left one of its connections open. Before, a net with any copper counted as routed, so a partly routed net was reported as done; KiCad's DRC in `fenolite check` still found it.
121
+ - A board whose rotated pad or rotated footprint carries a slotted hole is read and written again, and its footprints can be written as library files: the writer refused them (`KiCad writer cannot represent this slot rotation`, `KiCad oval drills can encode only horizontal or vertical slot axes`). `Padstack.hole_rotation` is now the slot's axis in the pad's own frame everywhere; on a board it used to include the pad's angle.
122
+ - Geometry: the documented and tested bound of two successive `Transform.apply` calls is `(1 + |cos θ| + |sin θ|)/2` nm per axis, at most `(1 + √2)/2 ≈ 1.2071` nm, not 1 nm; `test_composition_rounds_once` no longer fails at random, and a test reaches the bound exactly. No code changes (c0050).
123
+ - Script copper in the Altium build (change c0053): `fenolite build --target altium` now writes the tracks, vias and stitching vias that the design script declares (`Design.track`, `Design.via`, `Design.stitch`) into the experimental `<name>.PcbDoc`; before, they were left out without an issue. An intent that does not resolve refuses the build, an intent that creates nothing is reported, and with `--copper-from` the board wins with one `altium.not-lowered` info.
124
+ - `fenolite check` no longer reports `kicad.drc.rules-not-loaded` for rules that were loaded on a board with 499 or more clearance violations: `kicad-cli` stops reporting clearance violations near 499 per run and can leave the canary's own out, so such a run is now `inconclusive` with the reason `clearance-limit` (`kicad.drc.rules-unchecked`). The two-run canary test compares two DRC runs against what was measured to repeat, and the contract says which part of `check`'s output repeats between runs (c0051).
125
+ - Altium PCB document in the form Altium saves: `<name>.PcbDoc` now holds the whole `Board6` record (board keys, the outline as a polygon, sheet, sub-stack, drill pair, routing keys and snap grid, written by rule in `docboard.py` on top of `libboard.py`), net and component records with the common keys and unique ids, `UniqueIDPrimitiveInformation`, the option storages (`Advanced Placer Options6`, `Pin Swap Options6`, `Design Rule Checker Options6`, `PadViaLibrary`, `PadViaLibraryCache`, `LayerKindMapping`, `ConstraintManager`, `SignalClasses`) and 13 more empty storages; `write_pcbdoc` takes the file name. The first form gave a "catastrophic" error in Altium Designer 26.5 (maintainer's report, c0035); the new one opens there and its change order from the schematic reports no difference (author report of 2026-10-03). Texts, pads, tracks and arcs keep their short records.
126
+ - Altium PCB library opens in Altium Designer's form: `<name>.PcbLib` now holds the 53-byte `FileHeader` (version and library id), the whole board record in `Library/Data` (layer stack, grid, layer sets and view keys, written by rule in `libboard.py`) and the `Library` side streams (`EmbeddedFonts`, `ModelsNoEmbed`, `Textures`, `ComponentParamsTOC`, `PadViaLibrary`); `FileHeaderSix` of `<name>.PcbDoc` carries its id. The first form gave a "catastrophic" error in Altium Designer (maintainer's report, c0035); the new one opens in Altium Designer 26.5 (author report of 2026-10-03).
127
+
128
+ ## [0.0.1.dev0] - 2026-09-30
129
+
130
+ Pre-alpha repository bootstrap; not usable for real boards yet. Published to PyPI as `fenolite` and its
131
+ alias `phenolite` on 2026-09-30 (`pip install --pre fenolite`).
132
+
133
+ ### Added
134
+
135
+ - Repository bootstrap: package skeleton (`src/fenolite`, stdlib-only core, closed extras), Apache-2.0 licence with NOTICE and SPDX headers, `LEGAL.md`/`LEGAL-ANNEX.md`, DCO, ADR-0004, evidence registers and the `unit` CI baseline (ruff, pyright strict, pytest on ubuntu and macos).
136
+ - CLI contract v0: JSON envelope (`schemas/fenolite.envelope.v0.json`) and typed stderr errors (`schemas/fenolite.error.v0.json`), exit codes 0–7, `--fields`, mutation protocol (`--dry-run`/`--confirm`, atomic writes with `.bak`, receipts), `--seed`/`--timestamp`, the `capabilities` command, a consistency test over every command and a package-layering test.
137
+ - IP hygiene: ADR-0003 (clean-room and provenance), four explicit prohibitions in `LEGAL.md`, provenance rules and test, residue scan (`tools/residue/scan.py`: structural patterns, blob hashes, private token and hash lists kept outside the repository, UTF-16/cp1252/zip awareness, `--staged` and `--history` modes) with a pre-commit hook and CI step, copyleft-dependency and no-ported-code guards, corpus manifest with the embeddable rule and `tools/corpus_fetch.py`.
138
+ - Design model v0: `fenolite.core` (integer nm/µdeg units with exact parsing and half-even conversion to 1/10 000 mil, ids, evidence levels, errors and issues, provenance, coordinates, atomic I/O) and `fenolite.model` (entity header with native ids, provenance and extension bags; circuit, board, rules, manufacturing and findings layers; `Design` with indexes, validation and entity replacement; canonical JSON with a validating decoder; JSON Schemas in `schemas/fenolite.model.v0/`), ADR-0001 and `docs/design-model.md`.
139
+ - Name reservation: alias distribution `phenolite` (installs `fenolite`) and a release workflow that publishes both to PyPI with trusted publishing when a GitHub Release is published.
@@ -0,0 +1,64 @@
1
+ # Contributing to Fenolite
2
+
3
+ Thank you for helping. Fenolite is spec-driven, agent-friendly and strict about provenance.
4
+
5
+ ## Workflow
6
+
7
+ 1. **One change per pull request.** Every change starts as an OpenSpec change under
8
+ `openspec/changes/<id>/` (`proposal.md`, `design.md`, `specs/`, `tasks.md`). No code lands
9
+ without one. See `openspec/README.md`.
10
+ 2. Implement the tasks in order; each task names the command that proves it.
11
+ 3. While you work, run `make check-fast`: ruff, ruff format, pyright, the residue scan and the tests
12
+ that need no `kicad-cli`, corpus or KiCad libraries. Run `make check` (the same checks and every
13
+ test) once before pushing; CI runs the same steps. Both run the tests on parallel workers; see
14
+ `tests/README.md`, "Parallel runs".
15
+ 4. Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/)
16
+ (`feat(model): …`, `fix(kicad): …`, `docs: …`, `test: …`, `chore: …`).
17
+
18
+ ## Parallel worktrees
19
+
20
+ Several contributors or agents often work at once, each in its own worktree on one machine. A full
21
+ suite uses every core, so two of them at once are slower than one after the other.
22
+
23
+ - While working on a task, run `make check-fast` and the tests of the files you touched, for
24
+ example `uv run pytest tests/kicad/board/test_x.py -q`.
25
+ - Run `make check` once, on the rebased branch, right before the merge.
26
+ - Never start several full suites at the same time on one machine. If one is running, wait for it.
27
+
28
+ ## Developer Certificate of Origin
29
+
30
+ Every commit MUST carry a `Signed-off-by:` trailer certifying the
31
+ [Developer Certificate of Origin 1.1](https://developercertificate.org/):
32
+
33
+ ```bash
34
+ git commit -s -m "feat(core): add integer length units"
35
+ ```
36
+
37
+ By signing off you state that you wrote the contribution or have the right to submit it under
38
+ the Apache License 2.0.
39
+
40
+ ## Provenance rules (read `LEGAL.md`)
41
+
42
+ - Learn formats only from public documentation and from files you are entitled to read.
43
+ - Never decompile vendor software; never copy, transcribe or compile third-party parser code
44
+ or grammar files into Fenolite. Reading public sources for facts is fine: record each fact in
45
+ `docs/formats/` with its source.
46
+ - Never add files, values, names, templates or examples that belong to an employer or any other
47
+ organisation. Test data is authored for Fenolite or fetched from public sources listed in the
48
+ corpus manifest.
49
+ - Copyleft tools run only as external processes; they never become dependencies.
50
+
51
+ ## Allowed vs forbidden derivation
52
+
53
+ | Allowed | Forbidden |
54
+ |---|---|
55
+ | Reading a public format page and writing in `docs/formats/kicad/pcb.md`: "a `via` node carries `(at X Y)`, `(size D)`, `(drill D)`, `(layers A B)` — source S-0007", then implementing the parser from that page. | Opening a GPL parser's source, copying or paraphrasing its function that reads `via` nodes, or converting its grammar file into a Python parser. |
56
+ | Measuring a record layout on a public, licence-compatible sample file and recording the offsets with the file's manifest id. | Measuring anything on files you are not entitled to share or use (for example an employer's boards) or reusing values measured on them earlier. |
57
+ | Running a copyleft tool as a subprocess and comparing its output with Fenolite's (an oracle). | Adding that tool, or a library that links it, to `pyproject.toml`. |
58
+ | Writing an example board from scratch for `examples/`. | Recreating a board, template, title block, rule set or part list you know from work. |
59
+
60
+ ## Code style
61
+
62
+ - Python ≥ 3.11, stdlib-only core, full type hints (`pyright` strict on `src/`).
63
+ - Every `.py` file starts with the SPDX and copyright lines (see any existing file).
64
+ - Lengths are integer nanometres; angles are integer microdegrees; no floats in the model.
@@ -0,0 +1,75 @@
1
+ # Clean-room session log
2
+
3
+ One row per working session that touches `src/fenolite/backends/` or `docs/formats/`: what was
4
+ edited and which public sources were consulted. Only public sources and files the contributor is
5
+ entitled to use are consulted during these sessions.
6
+
7
+ | date | area | files touched | public sources consulted | author |
8
+ |---|---|---|---|---|
9
+ | 2026-10-05 | backends/altium | `src/fenolite/backends/base.py`, `src/fenolite/backends/altium/docset.py`, `roundtrip.py` and `backend.py`, `src/fenolite/backends/altium/PROVENANCE.md`, `docs/evidence/sources.md`, `docs/hypotheses.md` (c0044 verification: document sets, the round-trip levels RT-A0 to RT-A2 and the records view; own code over the readers and the compound writer, no new format fact and no source opened; public corpus rows read in the corpus cache for counts only, never committed) | S-0145, S-0163 (cited, not read again) | coding agent |
10
+ | 2026-10-05 | backends/altium, docs/formats | `docs/evidence/sources.md`, `docs/hypotheses.md`, `docs/formats/altium/connectivity.md`, `import.md`, `pcb-bodies.md`, `src/fenolite/backends/altium/PROVENANCE.md`, then `src/fenolite/backends/altium/adapter/`, `read/bodies.py` and `backend.py`, written from those pages (c0043 import: the Altium documentation pages on connectivity, buses, pads, 3D bodies and design rules read for facts; KiCad's importers read for facts only, nothing transcribed; AltiumSharp version 1 only; public project sets fetched to the corpus cache, never committed) | S-0130, S-0131, S-0160, S-0161, S-0185, S-0186, S-0286, S-0301, S-0302, S-0303 | coding agent |
11
+ | 2026-10-05 | backends/kicad | `src/fenolite/backends/kicad/_fpmap.py`, `mod.py`, `tests/unit/backends/kicad/test_mod_pads.py`, `test_mod_write.py` (investigated the rotated-slot writer refusal against `kicad-demo-10-0-6-pcb-04`; rebased onto the fix already merged to `main`; no KiCad source code read or copied) | S-0058 | Codex agent |
12
+ | 2026-10-05 | backends/altium, docs/formats | `docs/formats/altium/schematic-records.md`, `schematic-ascii.md`, `schematic-binary.md`, `schematic-library.md`, `src/fenolite/backends/altium/PROVENANCE.md` (c0040 schematic reader research: record keys from the converter's format page; the side-stream and storage layouts from KiCad's importer and binary parser read for facts only; AltiumSharp version 1 only; public corpus files fetched and never committed) | S-0130, S-0131, S-0148, S-0150, S-0152, S-0187, S-0188, S-0277, S-0278, S-0279, S-0280, S-0281, S-0282 | Claude agent |
13
+ | 2026-10-05 | backends/altium, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/altium/pcb-read.md, docs/evidence/altium-pcb-read.md, src/fenolite/backends/altium/PROVENANCE.md, then src/fenolite/backends/altium/read/pcbprops.py, pcbprims.py, pcbstack.py, pcb.py and pcblib.py, written from those pages (c0041 PCB reader: public sources only; AltiumSharp version 1 only; S-0173 never the only source of a row and its two facts attributed to vendor software unused; the corpus files are fetched by `tools/corpus_fetch.py` into the cache and never committed; Altium's documentation pages read for facts; `kicad-cli` run only as a subprocess; no parser code transcribed, nothing decompiled) | S-0002, S-0148, S-0150, S-0152, S-0160 to S-0163, S-0170 to S-0176, S-0188, S-0199, S-0200, S-0285, S-0286, S-0287 | coding agent |
14
+ | 2026-10-04 | backends/altium, docs/formats | `docs/formats/altium/compound-file.md`, `src/fenolite/backends/altium/PROVENANCE.md`, `LEGAL-ANNEX.md` (c0039 compound-file reader research; MS-CFB v12.0's version 4, DIFAT, metadata and high-size-bit provisions re-read; Altium's published viewer limit; no parser code or other implementation read) | S-0145, S-0149 | Codex agent |
15
+ | 2026-10-05 | backends/altium, docs/formats | `docs/formats/altium/project.md`, `output-job.md`, `rule-file.md`, `stackup-file.md`, `docs/evidence/sources.md`, `docs/hypotheses.md`, `src/fenolite/backends/altium/PROVENANCE.md`, then `src/fenolite/backends/altium/read/` (`textfile`, `ini`, `proptext`, `project`, `outjob`, `rul`, `rules`, `scope`, `stackup`), written from those pages (c0042 project reader: twelve public text files fetched to the corpus cache and read for facts, never committed; Altium's documentation pages S-0293 to S-0296 and S-0300 as recorded by the change's research of 2026-10-03; KiCad's importer for facts only, S-0160, S-0161; no parser code of another project was read, nothing copied) | S-0132, S-0138, S-0160, S-0161, S-0163, S-0187, S-0188, S-0293, S-0294, S-0295, S-0296, S-0297, S-0298, S-0299, S-0300 | Claude agent |
16
+ | 2026-09-30 | docs/formats | docs/formats/units.md | S-0001, S-0002 | maintainer |
17
+ | 2026-10-01 | docs/formats | docs/formats/kicad/geometry.md | S-0001, S-0010, S-0018, S-0019 | maintainer |
18
+ | 2026-10-01 | backends/kicad, docs/formats | src/fenolite/backends/kicad/PROVENANCE.md, docs/formats/kicad/sexpr.md, docs/formats/kicad/corpus.md | S-0001, S-0020, S-0021, S-0022, S-0023, S-0024, S-0025, S-0026, S-0027, S-0028, S-0029 | maintainer |
19
+ | 2026-10-01 | backends/kicad, docs/formats | src/fenolite/backends/kicad/versions.py, src/fenolite/backends/kicad/data/tokens.toml, docs/formats/kicad/versions.md, docs/formats/kicad/tokens.md | S-0001, S-0010, S-0020, S-0021, S-0022, S-0029, S-0030, S-0031, S-0032, S-0033, S-0034, S-0035, S-0036, S-0037, S-0038, S-0039 | maintainer |
20
+ | 2026-10-01 | backends/kicad, docs/formats | src/fenolite/backends/kicad/PROVENANCE.md, src/fenolite/backends/kicad/__init__.py, src/fenolite/backends/kicad/_libread.py, src/fenolite/backends/kicad/liberrors.py, src/fenolite/backends/kicad/mod.py, src/fenolite/backends/kicad/sym.py, src/fenolite/backends/kicad/libs.py, docs/formats/kicad/libraries.md | S-0001, S-0018, S-0020, S-0029, S-0030, S-0031, S-0040, S-0041, S-0042, S-0043, S-0044, S-0045, S-0046, S-0047, S-0048, S-0049 | maintainer |
21
+ | 2026-10-01 | backends, backends/kicad, docs/formats | src/fenolite/backends/base.py, src/fenolite/backends/registry.py, src/fenolite/backends/kicad/PROVENANCE.md, src/fenolite/backends/kicad/__init__.py, src/fenolite/backends/kicad/_fpmap.py, src/fenolite/backends/kicad/_libread.py, src/fenolite/backends/kicad/backend.py, src/fenolite/backends/kicad/cli.py, src/fenolite/backends/kicad/ipcd356.py, src/fenolite/backends/kicad/layers.py, src/fenolite/backends/kicad/mod.py, src/fenolite/backends/kicad/pcb.py, docs/formats/kicad/board.md | S-0001, S-0010, S-0019, S-0020, S-0021, S-0022, S-0024, S-0030, S-0033, S-0037, S-0038, S-0039, S-0050 | maintainer |
22
+ | 2026-10-01 | backends, backends/kicad, docs/formats | src/fenolite/backends/base.py, src/fenolite/backends/kicad/PROVENANCE.md, src/fenolite/backends/kicad/__init__.py, src/fenolite/backends/kicad/_fpmap.py, src/fenolite/backends/kicad/backend.py, src/fenolite/backends/kicad/cli.py, src/fenolite/backends/kicad/drc.py, src/fenolite/backends/kicad/embed.py, src/fenolite/backends/kicad/layers.py, src/fenolite/backends/kicad/mod.py, src/fenolite/backends/kicad/pcb.py, src/fenolite/backends/kicad/versions.py, docs/formats/kicad/board.md, docs/formats/kicad/drc.md | S-0010, S-0019, S-0020, S-0021, S-0022, S-0030, S-0033, S-0037, S-0039, S-0055, S-0056, S-0057, S-0058 | maintainer |
23
+ | 2026-10-02 | backends/kicad, docs/formats | src/fenolite/backends/kicad/PROVENANCE.md, src/fenolite/backends/kicad/__init__.py, src/fenolite/backends/kicad/_fpmap.py, src/fenolite/backends/kicad/_pcbwrite.py, src/fenolite/backends/kicad/backend.py, src/fenolite/backends/kicad/dru.py, src/fenolite/backends/kicad/lowering.py, src/fenolite/backends/kicad/mod.py, src/fenolite/backends/kicad/rulemap.py, docs/formats/kicad/rules.md, docs/formats/kicad/libraries.md | S-0010, S-0020, S-0022, S-0029, S-0030, S-0034, S-0037, S-0038, S-0040 | maintainer |
24
+ | 2026-10-02 | backends/kicad, docs/formats | src/fenolite/backends/kicad/PROVENANCE.md, src/fenolite/backends/kicad/__init__.py, src/fenolite/backends/kicad/_json.py, src/fenolite/backends/kicad/backend.py, src/fenolite/backends/kicad/lowering.py, src/fenolite/backends/kicad/pro.py, src/fenolite/backends/kicad/proerrors.py, src/fenolite/backends/kicad/triad.py, src/fenolite/backends/kicad/data/project_template_9.json, src/fenolite/backends/kicad/data/project_template_10.json, docs/formats/kicad/project.md, docs/formats/kicad/corpus.md | S-0010, S-0020, S-0023, S-0024, S-0029, S-0038, S-0045, S-0046, S-0065, S-0066 | maintainer |
25
+ | 2026-10-02 | backends/kicad, docs/formats | src/fenolite/backends/kicad/PROVENANCE.md, src/fenolite/backends/kicad/embed.py, src/fenolite/backends/kicad/libs.py, docs/formats/kicad/board.md, docs/formats/kicad/libraries.md, docs/formats/kicad/drc.md | S-0010, S-0022, S-0037, S-0038, S-0042, S-0043, S-0045, S-0046, S-0058, S-0070, S-0071, S-0072, S-0073, S-0074 | maintainer |
26
+ | 2026-10-02 | backends/kicad, templates, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, src/fenolite/backends/kicad/PROVENANCE.md, src/fenolite/templates/PROVENANCE.md (c0012 registers and naming gate) | S-0001, S-0020, S-0022, S-0029, S-0032, S-0035, S-0036, S-0037, S-0058, S-0075, S-0076, S-0077, S-0078, S-0079 | maintainer |
27
+ | 2026-10-02 | templates, docs/adr | docs/adr/0005-sheet-templates.md, src/fenolite/templates/examples/iso5457_generic.sheet.toml, src/fenolite/templates/examples/letter_generic.sheet.toml, src/fenolite/templates/PROVENANCE.md (review of ADR-0005, both examples and their provenance tables; ADR accepted) | S-0077, S-0078, S-0079 | maintainer |
28
+ | 2026-10-02 | backends/kicad, docs/formats | src/fenolite/backends/kicad/PROVENANCE.md, src/fenolite/backends/kicad/__init__.py, src/fenolite/backends/kicad/lowering.py, src/fenolite/backends/kicad/pro.py, src/fenolite/backends/kicad/proerrors.py, docs/formats/kicad/project.md, docs/formats/kicad/rules.md | S-0010, S-0020, S-0024, S-0029, S-0038, S-0058 | maintainer |
29
+ | 2026-10-02 | backends/altium, docs/formats | src/fenolite/backends/altium/__init__.py, src/fenolite/backends/altium/PROVENANCE.md, docs/formats/altium/schematic-ascii.md, docs/formats/altium/project.md (c0032, from the format research of the same day), then src/fenolite/backends/altium/ascii.py, symbols.py, layout.py, schdoc.py, prjpcb.py and project.py, written from those pages | S-0002, S-0020, S-0130, S-0131, S-0132, S-0133, S-0134, S-0135, S-0136, S-0137, S-0138, S-0139, S-0140, S-0141, S-0142, S-0143, S-0144 | maintainer |
30
+ | 2026-10-02 | backends/kicad, docs/formats | src/fenolite/backends/kicad/PROVENANCE.md, docs/formats/kicad/board.md, docs/formats/kicad/libraries.md | S-0020, S-0022, S-0024, S-0029, S-0037, S-0038, S-0045, S-0046, S-0048, S-0058, S-0105 | maintainer |
31
+ | 2026-10-02 | backends/altium, docs/formats | src/fenolite/backends/altium/PROVENANCE.md, docs/formats/altium/compound-file.md, docs/formats/altium/schematic-binary.md (c0033, from the binary format research of the same day), then src/fenolite/backends/altium/cfb.py and binary.py, written from those pages | S-0002, S-0130, S-0131, S-0133, S-0142, S-0143, S-0145, S-0146, S-0147, S-0148, S-0149 | maintainer |
32
+ | 2026-10-02 | backends/kicad, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, src/fenolite/backends/kicad/PROVENANCE.md, docs/formats/kicad/cli.md (c0013 registers and the cli page skeleton) | S-0010, S-0020, S-0022, S-0037, S-0038, S-0045, S-0046, S-0080, S-0081 | maintainer |
33
+ | 2026-10-02 | backends, backends/kicad, docs/formats | src/fenolite/backends/base.py, src/fenolite/backends/kicad/backend.py, src/fenolite/backends/kicad/cli.py, src/fenolite/backends/kicad/canary.py, src/fenolite/backends/kicad/helpmatrix.py, src/fenolite/backends/kicad/oracle.py, src/fenolite/backends/kicad/projectset.py, src/fenolite/backends/kicad/roundtrip.py, docs/formats/kicad/cli.md, docs/formats/kicad/drc.md (c0013 copy set, canary, help matrix, RT1 and oracle) | S-0010, S-0020, S-0022, S-0037, S-0038, S-0045, S-0046, S-0080, S-0081 | maintainer |
34
+ | 2026-10-02 | backends/kicad, docs/formats | src/fenolite/backends/kicad/PROVENANCE.md, docs/formats/kicad/board.md | S-0010, S-0022, S-0037, S-0038, S-0055, S-0056 | maintainer |
35
+ | 2026-10-02 | backends/altium, docs/formats | src/fenolite/backends/altium/layout.py, docs/formats/altium/schematic-ascii.md (c0032 task 4.2: power ports of adjacent pins staggered, a Fenolite layout choice prompted by the maintainer's KiCad 10.0.6 import of the CC0 sample) | none (no new source; the fact pages only) | maintainer |
36
+ | 2026-10-02 | backends/altium, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/altium/schematic-library.md, docs/formats/altium/compound-file.md, src/fenolite/backends/altium/PROVENANCE.md (c0034, from the schematic-library format research of the same day; AltiumSharp version 1 at afe796434b6d2110c745c90abe44a6ddf64f5bca only), then src/fenolite/backends/altium/cfb.py, altsym.py, schlib.py, project.py, prjpcb.py, layout.py, schdoc.py and src/fenolite/lens/altium.py, written from those pages | S-0002, S-0020, S-0130, S-0131, S-0145, S-0148, S-0150, S-0151, S-0152, S-0153, S-0154, S-0155 | maintainer |
37
+ | 2026-10-02 | backends/altium, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/altium/project.md, schematic-ascii.md, schematic-binary.md and schematic-library.md (the S-0142 audit), then docs/formats/altium/pcb-library.md, pcb-records.md, pcb-document.md, compound-file.md and src/fenolite/backends/altium/PROVENANCE.md (c0035, from the PCB format research of the same day), then src/fenolite/backends/altium/cfb.py, pcbrecords.py, pcblib.py, pcbdoc.py, project.py, prjpcb.py and src/fenolite/lens/altium.py, written from those pages. AltiumSharp was read only as version 1 at afe796434b6d2110c745c90abe44a6ddf64f5bca (`AltiumSharp/PcbLibWriter.cs`, `CompoundFileWriter.cs`, `Records/Pcb/*.cs`); version 2 was not used | S-0002, S-0020, S-0143, S-0145, S-0149, S-0150, S-0160, S-0161, S-0162, S-0163, S-0164, S-0165, S-0166 | maintainer |
38
+ | 2026-10-03 | backends/altium, docs/formats | docs/evidence/sources.md, docs/formats/altium/pcb-library.md, pcb-records.md and pcb-document.md, src/fenolite/backends/altium/PROVENANCE.md (c0035, after the maintainer's report that Altium Designer refuses the PCB library: four Altium-saved libraries under MIT and GPL-2.0 and one document under Apache-2.0 were downloaded to a scratch folder, read with tests/_cfb_read.py and compared with Fenolite's output; none is committed, nothing was decompiled, no code was read in S-0173 beyond its format page and report texts), then src/fenolite/backends/altium/libboard.py, pcblib.py, pcbrecords.py, pcbdoc.py and tests/_altium_pcb_read.py, written from those pages | S-0145, S-0150, S-0160, S-0162, S-0170, S-0171, S-0172, S-0173 | maintainer |
39
+ | 2026-10-03 | backends/altium, docs/formats | docs/evidence/sources.md, docs/formats/altium/pcb-document.md and src/fenolite/backends/altium/PROVENANCE.md (c0035, after the maintainer's report that Altium Designer 26.5 refuses the PCB document: three more Altium-saved documents under BSD-2-Clause, MIT and Apache-2.0 were downloaded to a scratch folder, read with tests/_cfb_read.py and compared with Fenolite's output and with the document of S-0172; none is committed, nothing was decompiled, no third-party code was read), then src/fenolite/backends/altium/docboard.py, libboard.py, pcbdoc.py, project.py and tests/_altium_pcb_read.py, written from those pages | S-0160, S-0161, S-0172, S-0174, S-0175, S-0176 | maintainer |
40
+ | 2026-10-03 | backends/kicad, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, src/fenolite/backends/kicad/PROVENANCE.md, docs/formats/kicad/drc.md, docs/formats/kicad/board.md (c0020 registers and the Findings and RT2 sections) | S-0019, S-0020, S-0022, S-0037, S-0055, S-0056, S-0058, S-0090, S-0091 | maintainer |
41
+ | 2026-10-03 | backends, backends/kicad, docs/formats | src/fenolite/backends/base.py, src/fenolite/backends/kicad/padnets.py, src/fenolite/backends/kicad/oracle.py, docs/formats/kicad/drc.md, docs/formats/kicad/board.md (c0020: netlist and RT2 oracles, the matcher moved from c0009's frame test, labels after the probes; no KiCad source read) | S-0019, S-0020, S-0022, S-0037, S-0055, S-0056 | maintainer |
42
+ | 2026-10-03 | backends/altium, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/altium/schematic-ascii.md, schematic-binary.md, project.md and pcb-document.md, src/fenolite/backends/altium/PROVENANCE.md (c0037, from the hierarchy and harness format research of the same day: the public Altium-saved sheets, harness definition files, project files and one PCB document of S-0187 (MIT) and S-0188 (LGPL-3.0) were downloaded to a scratch folder and read with tests/_cfb_read.py, the PCB document by a byte search; none is committed, nothing was decompiled, no name, value or coordinate of them is used, and AltiumSharp was consulted only as version 1 at afe796434b6d2110c745c90abe44a6ddf64f5bca, which holds nothing on these records), then src/fenolite/backends/altium/hierarchy.py, layout.py, schdoc.py, binary.py, prjpcb.py, project.py, pcbdoc.py, src/fenolite/lens/altium.py and tests/_altium_read.py, written from those pages | S-0130, S-0131, S-0132, S-0139, S-0150, S-0164, S-0185, S-0186, S-0187, S-0188 | maintainer |
43
+ | 2026-10-03 | backends/altium, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, src/fenolite/backends/altium/PROVENANCE.md and docs/formats/altium/pcb-copper.md (c0038, from the copper research of the same day: the Altium-saved documents of S-0172, S-0174, S-0175 and S-0176 and, after the maintainer's approval, two boards of the public repository luxonis/oak-hardware under MIT, `NG6011.PcbDoc` (S-0199) and `DM6010_R2M2E2.PcbDoc` (S-0200), downloaded to a scratch folder; both are scratch-only and never committed; nothing was decompiled, no third-party code was read or transcribed, AltiumSharp only as version 1 at afe796434b6d2110c745c90abe44a6ddf64f5bca), then src/fenolite/backends/altium/pcbrecords.py, libboard.py, docboard.py, pcbdoc.py, src/fenolite/lens/altium.py and tests/_altium_pcb_read.py, written from those pages | S-0002, S-0020, S-0150, S-0160, S-0161, S-0166, S-0172, S-0173, S-0174, S-0175, S-0176, S-0195, S-0196, S-0197, S-0198, S-0199, S-0200 | maintainer |
44
+ | 2026-10-03 | backends/kicad, exports, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/kicad/cli.md, src/fenolite/backends/kicad/PROVENANCE.md, src/fenolite/backends/kicad/cli.py, src/fenolite/exports/ (c0024 export and render commands run as subprocesses; nothing copied) | S-0020, S-0022, S-0037 | maintainer |
45
+ | 2026-10-03 | backends/altium, docs/formats | docs/formats/altium/pcb-document.md, schematic-ascii.md, schematic-binary.md and project.md, docs/evidence/sources.md, docs/evidence/altium-schematic.md, docs/hypotheses.md, src/fenolite/backends/altium/PROVENANCE.md (c0037, after the maintainer's report of Part H made with Altium Designer 26.5 under a trial licence: the public PCB document of S-0188 (LGPL-3.0), already in the scratch folder, was read again by a byte search and compared with Fenolite's output, which gave the per-sheet `CHANNELOFFSET`; the stream sizes and the sheet parameters of the public sheets of S-0187 and S-0188 were read with tests/_cfb_read.py, which gave the 4096-byte rule; two public Altium documentation pages on project validation were read and gave no fact; the project file and the project structure file that Altium Designer 26.5 saved from Fenolite's own board example, which the maintainer keeps outside the repository, were read for the facts of the author report; nothing was downloaded, decompiled or committed, and no name, value or coordinate of a third-party file is used), then src/fenolite/backends/altium/pcbdoc.py, layout.py, hierarchy.py, schdoc.py, binary.py and tests/_altium_read.py, written from those pages | S-0130, S-0145, S-0186, S-0187, S-0188 | maintainer |
46
+ | 2026-10-03 | backends/altium, docs/formats | docs/formats/altium/project.md and schematic-binary.md, docs/evidence/altium-schematic.md, docs/hypotheses.md, src/fenolite/backends/altium/PROVENANCE.md (c0037, after the maintainer's second report of step H7 made with Altium Designer 26.5 under a trial licence: only the outcomes the maintainer reported and Fenolite's own built project files were read; the project file that Altium saved stays with the maintainer, and of the variant folders only the `DocumentPath` and `HierarchyMode` lines of the project files were read; nothing was downloaded, decompiled or committed), then src/fenolite/backends/altium/prjpcb.py and binary.py, written from those pages | S-0134, S-0145, S-0188 | maintainer |
47
+ | 2026-10-03 | backends/kicad, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, src/fenolite/backends/kicad/PROVENANCE.md, docs/formats/kicad/libraries.md, tools/README.md, tests/libs/README.md (c0021 registers and the library cache, scan and configuration sections; no KiCad source code was read) | S-0020, S-0042, S-0043, S-0044, S-0045, S-0046, S-0048, S-0095, S-0096, S-0097 | maintainer |
48
+ | 2026-10-03 | backends/kicad, docs/formats | src/fenolite/backends/kicad/libcache.py, data/libraries.toml, libs.py and cli.py, tools/kicad_libs_fetch.py, docs/formats/kicad/libraries.md and corpus.md, docs/evidence/kicad-libs.md (c0021: pins from the tags API, the cache source, the directory scan, `kicad_common.json` variables and the relative-uri rule, written from the fact page and from `kicad-cli` probe outcomes on authored CC0 files; the official libraries were fetched into a cache outside the repository and only counted; demo library files were fetched into the corpus cache and none is committed; no KiCad source code was read) | S-0020, S-0023, S-0024, S-0025, S-0042, S-0043, S-0044, S-0045, S-0046, S-0095, S-0096, S-0097 | maintainer |
49
+ | 2026-10-03 | backends, backends/kicad, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/kicad/frame.md, docs/copper.md, src/fenolite/backends/kicad/PROVENANCE.md, then src/fenolite/backends/base.py, src/fenolite/backends/kicad/frame.py and copper.py, written from that page (c0028 board-frame queries and manual copper; S-0001, S-0038, S-0110 and S-0111 opened on this date) | S-0001, S-0010, S-0018, S-0019, S-0020, S-0022, S-0037, S-0038, S-0040, S-0058, S-0110, S-0111 | maintainer |
50
+ | 2026-10-04 | backends/kicad, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/kicad/board.md, src/fenolite/backends/kicad/PROVENANCE.md, then src/fenolite/backends/kicad/pcb.py and fields.py, written from that page (c0030 footprint fields: S-0120 opened on this date; the version-history file S-0030 and the keyword file S-0033 consulted at tag 8.0.0 for dated notes and single names only; the field facts come from `kicad-cli` probe outcomes on boards authored as text and from a census of the corpus boards; no other KiCad source was read) | S-0001, S-0010, S-0020, S-0021, S-0022, S-0027, S-0029, S-0030, S-0033, S-0037, S-0038, S-0040, S-0055, S-0056, S-0058, S-0120 | maintainer |
51
+ | 2026-10-04 | backends/kicad, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/kicad/board.md and gerber.md, src/fenolite/backends/kicad/PROVENANCE.md, then src/fenolite/backends/kicad/zones.py, pcb.py and _fpmap.py, written from those pages (c0031 zone settings; S-0001, S-0010, S-0021, S-0037 and S-0038 opened on this date, `pcb.keywords` at tag 8.0.0 read for 13 single names, the Gerber specification read for facts and never committed; no KiCad parser source was read) | S-0001, S-0010, S-0018, S-0020, S-0021, S-0022, S-0029, S-0033, S-0037, S-0038, S-0058, S-0125 | maintainer |
52
+ | 2026-10-04 | backends/kicad, checks, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/kicad/copper.md, src/fenolite/backends/kicad/PROVENANCE.md, then src/fenolite/backends/kicad/copperrules.py, src/fenolite/checks/clearance.py and copper.py, written from that page and from docs/formats/kicad/project.md and rules.md (c0029 copper check: `kicad-cli` run as a subprocess on authored benches; no KiCad source code was read, nothing copied) | S-0010, S-0019, S-0020, S-0022, S-0029, S-0037, S-0038, S-0055, S-0056 | maintainer |
53
+ | 2026-10-03 | backends/altium, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/altium/schematic-ascii.md, project.md and pcb-copper.md, docs/evidence/altium-pcb.md, src/fenolite/backends/altium/PROVENANCE.md, then src/fenolite/backends/altium/ and src/fenolite/lens/altium.py (c0048, after the maintainer's report of the change order made with Altium Designer 26.5 under a trial licence: Altium's public documentation pages were read; the public Altium-saved files of S-0187, S-0188, S-0172, S-0174 to S-0176, S-0199 and S-0200, already in the scratch folder, were read again with the test readers for their class records, directives and class keys; the project file that Altium saved from the built board example, the maintainer's own file, was read outside the repository for its class keys only; nothing was downloaded, decompiled, copied or committed) | S-0130, S-0185, S-0187, S-0188, S-0172, S-0174, S-0175, S-0176, S-0199, S-0200, S-0310, S-0311, S-0312, S-0313 | maintainer |
54
+ | 2026-10-04 | backends/kicad, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/kicad/board.md and cli.md, src/fenolite/backends/kicad/PROVENANCE.md, then the zone-fill runner and oracle from those facts (c0015; official Docker documentation read for command options; `kicad-cli` run only as a subprocess on authored boards; no third-party parser code read) | S-0020, S-0022, S-0029, S-0037, S-0205 | Codex agent |
55
+ | 2026-10-04 | backends/kicad, placement, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/kicad/board.md, docs/placement.md, src/fenolite/backends/kicad/PROVENANCE.md, then src/fenolite/backends/kicad/outline.py and replace.py and src/fenolite/placement/, written from that page (c0022 placement: S-0038 opened on this date for the "Courtyards overlap" check; `kicad-cli` run as a subprocess on authored benches and on the built blink; no KiCad source code was read, nothing copied) | S-0010, S-0019, S-0020, S-0021, S-0022, S-0037, S-0038, S-0058 | maintainer |
56
+ | 2026-10-04 | routing plugin | KiCadRoutingTools `v0.22.1` is run as a subprocess from a user-named checkout; Fenolite neither imports nor distributes it (c0016) | S-0215, S-0216, S-0217 | Codex agent |
57
+ | 2026-10-04 | backends/specctra, docs/formats | docs/adr/0006-specctra-and-freerouting.md, docs/evidence/sources.md, docs/hypotheses.md, docs/formats/specctra/dsn.md and ses.md, src/fenolite/backends/specctra/PROVENANCE.md, then src/fenolite/backends/specctra/ (lexer, design-file writer, session reader), written from those pages (c0023: the SPECCTRA Design Language Reference, S-0224, was read on line for facts under ADR-0006, which is `Proposed`; nothing of it was saved, copied or committed; Freerouting's documentation pages were read; Freerouting is a GPL-3.0 program run across a process boundary: the maintainer installed the 2.4.1 jar outside the repository and the probes ran it as a subprocess on files Fenolite wrote; no source code of Freerouting or of KiCad was read) | S-0022, S-0037, S-0220, S-0221, S-0222, S-0223, S-0224, S-0225, S-0226 | Claude agent |
58
+ | 2026-10-04 | docs/adr, routing/plugins | docs/adr/0006-specctra-and-freerouting.md (accepted), src/fenolite/routing/plugins/specctra/freerouting.py (container command line; `sends_data_offsite`), docs/evidence/routing.md, docs/hypotheses.md | S-0220 to S-0226 (no new source; the image configuration of S-0226 was read with `docker image inspect`) | maintainer |
59
+ | 2026-10-04 | analysis, docs | docs/evidence/sources.md, docs/hypotheses.md, docs/analyses.md and src/fenolite/analysis/PROVENANCE.md, then src/fenolite/analysis/ and src/fenolite/cli/cmd_analyze.py, written from those pages (c0047: the capacity fit and its range as the help text S-0269 states them, the via barrel as a fact of S-0270, recorded by the change's proposal on 2026-10-03; no standard was read, and no chart, table or figure of a standard is reproduced; the distance analyses are Fenolite's own geometry; no requirement value is shipped) | S-0011, S-0012, S-0020, S-0022, S-0269, S-0270, S-0271, S-0272, S-0273 | maintainer |
60
+ | 2026-10-05 | backends/kicad | src/fenolite/backends/kicad/cli.py (kicad-cli found in KiCad's default Windows install folder and through PATHEXT), projectset.py (a rooted path is absolute on Windows), libcache.py and oracle.py (text written with LF line ends on every system) | none: no format fact changed; the install folder `<Program Files>\KiCad\<major>.0\bin` is the one `tests/_resources.py` already searched | Claude agent |
61
+ | 2026-10-05 | backends/kicad, catalog | src/fenolite/backends/kicad/sym.py (Fenolite symbol-fill readback fix); generic symbol and package entries authored from the public product-category and package-drawing references registered as S-0316–S-0332; no CAD library or parser source copied | S-0316 to S-0332 | Luiz Carlos Gili |
62
+ | 2026-10-05 | backends/altium, docs/formats | docs/evidence/sources.md, docs/hypotheses.md, docs/formats/altium/sheet-template.md, src/fenolite/backends/altium/PROVENANCE.md, tests/corpus/manifest.toml, then src/fenolite/backends/altium/read/sheet.py and the `import` action of src/fenolite/cli/cmd_template.py, written from that page (c0046: the format notes of S-0130 and three Altium documentation pages were read for facts; nothing was copied, transcribed or followed; S-0131 was not opened during the implementation, its facts are those the design recorded on 2026-10-03; three public, MIT-licensed `.SchDot` files of S-0264 and S-0265 were fetched into the corpus cache by `tools/corpus_fetch.py`, read there for counts per record kind and key name, and never committed; no template, logo or title block of any organisation is committed or reproduced, and the test templates are authored in `tests/_altium_sheet.py`; no vendor software was run or decompiled) | S-0130, S-0131, S-0147, S-0261, S-0262, S-0263, S-0264, S-0265 | coding agent |
63
+ | 2026-10-05 | docs/formats, backends/kicad, exports | docs/formats/kicad/cli.md (three rows on the position CSV, from running `kicad-cli` 9.0.9 and 10.0.6 on authored boards), src/fenolite/backends/kicad/PROVENANCE.md, docs/assembly.md, src/fenolite/exports/{assembly,bom,placement}.py (c0064: tables and a user-written column template; every example column name is made up for Fenolite, and no template, column list or rotation table of any assembly service, distributor or company was consulted or reproduced) | S-0020, S-0022, S-0037 (the position file), S-0365 and S-0366 (CSV) | Luiz Carlos Gili |
64
+ | 2026-10-05 | backends/kicad, cli, checks, analysis | src/fenolite/backends/kicad/sexpr.py (`canonical` and `first_line_difference`: the existing parser and printer composed, no format fact added), src/fenolite/checks/diff.py, src/fenolite/analysis/views.py, src/fenolite/cli/explain.py with data/explain.toml and the commands of c0066 (the explanation texts are written for Fenolite from its own code and docs; no vendor text, parser code or grammar file was read or copied) | none: no source registered, no format page changed | Claude agent |
65
+ | 2026-10-05 | backends/kicad, model | docs/formats/kicad/schematic.md, docs/evidence/sources.md and docs/hypotheses.md, then src/fenolite/model/schematic.py, src/fenolite/backends/kicad/sch.py and sym.py (`symbol_from`), written from that page (c0060: the schematic format page S-0367 and the dated versions of S-0031 read for facts; the demo schematics read for counts only; authored fixtures under tests/data/kicad/schematic/ checked with `kicad-cli` run as a subprocess; no KiCad source or keyword file copied) | S-0001, S-0020, S-0022, S-0031, S-0037, S-0041, S-0058, S-0367 | Claude agent |
66
+ | 2026-10-05 | backends/kicad, docs/formats | src/fenolite/backends/kicad/frame.py (the offset of a pad's drill moves the copper entries and leaves the hole at the pad position), zones.py (pad zone connection requests on a built copy and on a kept footprint; no format fact) and copper.py (arc steps and via kinds of script copper; no format fact), docs/formats/kicad/frame.md, libraries.md ("Drill forms") and copper.md (the zone's own clearance against a fill; two fills; a refilled pour), docs/hypotheses.md (`H-G-FRAME-OFFSET`, `H-K-COPPER-ZONECLR`, `H-G-FRAME-ARC`, `H-K-COPPER-VIAKINDS`, `H-K-PAD-ZONE-LIB`, `H-K-CI-MACOSAPP`), written from the verdicts of `kicad-cli` 10.0.6 `pcb drc` and `pcb upgrade` on authored benches (c0068: `tests/kicad/frame/_offsetbench.py`, `_arccases.py`, `tests/kicad/copper/_copperparity.py`, `tests/kicad/zones/_freshfill.py`, `_padzonecases.py`); no KiCad source was read, and the macOS disk image of S-0361 was not downloaded | S-0001, S-0020, S-0022, S-0029, S-0038, S-0360 to S-0363 | Claude agent |
67
+ | 2026-10-05 | backends, backends/kicad, backends/altium, backends/specctra, verify | src/fenolite/backends/matrix.py and base.py (`MatrixRow`), `claims.py` in the three backend packages, one evidence declaration in each backend module that had none (a `# evidence:` comment, or a constant over rows that `docs/hypotheses.md` already holds), src/fenolite/verify/evidence.py, tools/gen_evidence_matrix.py and docs/evidence/matrix.md (c0067: declarations and a generated table of them; no format fact, no source and no hypothesis added, no row of the register changed) | none: no source registered, no format page changed | Claude agent |
68
+ | 2026-10-05 | backends/kicad, lens, docs/formats | docs/formats/kicad/schematic.md ("Generated sheets") and board.md (the `N/C` label), docs/evidence/sources.md and docs/hypotheses.md, then src/fenolite/backends/kicad/netnames.py, symembed.py, schlayout.py, schgen.py, sch.py (`write_schematic`), pcb.py (stored net names) and padnets.py, src/fenolite/lens/build.py and schplacements.py, written from that page (c0061: every fact was measured by running `kicad-cli` 9.0.9 and 10.0.6 as a subprocess on sheets authored for Fenolite and on projects it built; the manuals S-0022, S-0037 and S-0046 and the format page S-0367 were read for facts; no KiCad source, keyword file or library symbol was copied; the power flag symbol is drawn for Fenolite) | S-0020, S-0022, S-0037, S-0046, S-0367 | Claude agent |
69
+ | 2026-10-05 | backends/specctra | src/fenolite/backends/specctra/dsn.py (a one-pad net with the `unconnected-(` spelling is written as a pad on no net; no format fact added: the spelling is the recorded one of docs/formats/kicad/schematic.md, "Net names") | none beyond the sources already listed for that page | Claude agent |
70
+ | 2026-10-06 | backends/kicad, docs/formats | src/fenolite/backends/kicad/bom.py and cli.py (`export_bom`), docs/formats/kicad/cli.md ("Bill of materials", from running `kicad-cli` 9.0.9 and 10.0.6 on schematics that Fenolite built; c0064). No manual page, parser or exporter source was read; no BOM layout of any assembly service, distributor or company was consulted | S-0020 | Luiz Carlos Gili |
71
+ | 2026-10-05 | backends/kicad, checks, lens, cli, docs/formats | docs/formats/kicad/schematic.md ("Netlist export"), docs/evidence/sources.md and docs/hypotheses.md (`H-K-NETLIST-SHAPE`, `H-K-NETLIST-OWN`), then src/fenolite/backends/kicad/netlist.py and sch_netlist.py, sch.py (`opaque_heads`), oracle.py (`schematic_netlist`), src/fenolite/backends/base.py (`SchematicNetlistOracle`), src/fenolite/checks/assignment_compare.py, src/fenolite/lens/build.py (the netlist guard) and src/fenolite/cli/cmd_netlist.py, written from that page (c0063: every fact was measured by running `kicad-cli` 9.0.9 and 10.0.6 as a subprocess on projects Fenolite built; the manuals S-0022 and S-0037 were read for the command and its options; no netlist format page exists; no KiCad source, keyword file or library symbol was read or copied; the two exports under tests/data/kicad/netlist/ are authored for Fenolite) | S-0020, S-0022, S-0037 | Claude agent |
72
+ | 2026-10-05 | backends/kicad, docs/formats | docs/formats/kicad/erc.md, docs/evidence/sources.md and docs/hypotheses.md, then src/fenolite/backends/base.py (the neutral ERC report and oracle types), src/fenolite/backends/kicad/erc.py, cli.py (`KicadCli.erc`, the parity flag), projectset.py (the schematic files of the copy set) and oracle.py (`erc`, `rt2_erc`, parity in `drc`), written from that page (c0062: every fact was measured by running `kicad-cli` 9.0.9 and 10.0.6 as a subprocess on projects Fenolite built and on sheets authored for Fenolite; the key names of the report are those the tool wrote, which the proposal had compared with the schema files S-0450 and S-0451 on 2026-10-04; the schema files were not fetched again, and no KiCad source, schema or keyword file was copied) | S-0020, S-0022, S-0037, S-0046, S-0450, S-0451 | Claude agent |
73
+ | 2026-10-06 | backends, checks, docs/formats | src/fenolite/backends/base.py (`ErcReport.kinds()`), src/fenolite/checks/rt2.py (`erc_rt2` compares kinds) and docs/formats/kicad/erc.md (two rows restated: `sch erc` can name another item of one violation in each run), from running `kicad-cli` 9.0.9 and 10.0.6 as a subprocess on the corpus projects of the manifest (c0062, c0066). No manual page, parser or tool source was read | none beyond S-0020, already listed for that page | Luiz Carlos Gili |
74
+ | 2026-10-06 | backends/kicad, lens, cli, docs/formats | docs/formats/kicad/schematic.md (the rows of `H-K-SCH-HIER-FILE`, `H-K-SCH-HIER-PATH` and `H-K-SCH-WIRE-END`) and docs/hypotheses.md, then src/fenolite/model/schematic.py (`Wire`), src/fenolite/backends/kicad/sch.py (wires and sheet references of a created sheet, `opaque_wires`), schlayout.py (satellites, clusters, sheet references), schgen.py (one sheet per module), sch_netlist.py (the sheet tree and wires), src/fenolite/lens/build.py and src/fenolite/cli/cmd_build.py and cmd_netlist.py, written from that page (c0070: every fact was measured by running `kicad-cli` 9.0.9 and 10.0.6 as a subprocess on sheets written by hand for Fenolite in tests/kicad/schematic/_hiercases.py and on projects Fenolite built; the file format page S-0367 was read for the children of `wire` and `sheet`; no KiCad source, keyword file, library symbol or third-party schematic was read or copied; every layout length is a Fenolite choice) | S-0020, S-0029, S-0367 | Claude agent |
75
+ | 2026-10-06 | backends/kicad, docs/formats | src/fenolite/backends/kicad/schlayout.py (`turned_text_room`, the text room of a turned unit in `text_box` and in the snap) and sch.py (the Reference and Value of a turned or mirrored instance: centred, at the angle drawn level), and one row of docs/formats/kicad/schematic.md (how a field is drawn in a turned symbol), from looking at the PDF exports that `kicad-cli` 9.0.9 and 10.0.6, run as a subprocess, made of sheets Fenolite built (c0070, the text overlap the maintainer saw on the renders). No manual page, parser or tool source was read | none beyond S-0020 and S-0029, already listed for that page | Luiz Carlos Gili |
@@ -0,0 +1,48 @@
1
+ # Legal notes
2
+
3
+ Fenolite is licensed under the Apache License, Version 2.0 (see `LICENSE` and `NOTICE`).
4
+ This file explains where Fenolite's knowledge of third-party file formats comes from and how the
5
+ project relates to earlier, non-public work in the same domain. It is a statement of project
6
+ policy, not legal advice.
7
+
8
+ ## A. Format analysis
9
+
10
+ Fenolite reads and writes files produced by other electronic design automation (EDA) tools.
11
+
12
+ 1. Knowledge of third-party file formats comes **only** from public documentation (official
13
+ documentation, published specifications, public developer documentation of open-source tools)
14
+ and from files the contributor is entitled to read (files they created themselves, or files
15
+ published under a licence that permits the use).
16
+ 2. Every format fact used by the code is recorded in `docs/formats/<backend>/*.md` with its public
17
+ source, listed in `docs/evidence/sources.md`, and carries an evidence label. Code is written
18
+ from those pages, never from third-party source code. Reading public copyleft sources to learn
19
+ a **fact** is allowed only when the fact is recorded there with its source.
20
+ 3. Copyleft software (GPL, AGPL and similar) is used only behind a process boundary (a
21
+ subprocess exchanging files or documented JSON) or through a plugin API that its project
22
+ publishes; it is never imported, vendored or transcribed (ADR-0004).
23
+
24
+ The following are **forbidden** (ADR-0003):
25
+
26
+ - **(P1)** decompiling, disassembling or otherwise reverse engineering vendor software — contributors
27
+ never decompile a tool to learn its format;
28
+ - **(P2)** transcribing, compiling or converting GPL/AGPL parser sources or machine-readable grammar
29
+ files (for example Kaitai `.ksy` descriptions) into Fenolite code;
30
+ - **(P3)** using files the contributor is not entitled to read (for example an employer's design
31
+ files, or files obtained under terms that do not allow this use);
32
+ - **(P4)** using an employer's software licence to study or reverse engineer a tool for Fenolite.
33
+
34
+ Opening a file one is entitled to read in a tool one is licensed to use, and reporting what the
35
+ tool does with it, is ordinary use and may be recorded as a fact with evidence label
36
+ `…(author-report)`; no file used in such a session enters the repository unless it is authored for
37
+ Fenolite or published under a licence listed as embeddable in the corpus manifest.
38
+
39
+ ## B. Material from organisations
40
+
41
+ Fenolite is developed **clean-room** with respect to non-public material:
42
+
43
+ - no design files, templates, title blocks, rule sets, part libraries, parameter conventions,
44
+ constants measured on non-public files, seeds, fixtures, test data, statistics, vocabularies or
45
+ examples belonging to any organisation (including a contributor's employer or clients) are added
46
+ to Fenolite, even when such files were used privately to try an idea;
47
+ - every format fact is derived from the public sources in block A and recorded with them;
48
+ - work sessions on format code are logged in `LEGAL-ANNEX.md`.