factorforge-cds 3.5.4__tar.gz → 3.5.10__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 (268) hide show
  1. {factorforge_cds-3.5.4/src/factorforge_cds.egg-info → factorforge_cds-3.5.10}/PKG-INFO +51 -4
  2. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/README.md +49 -3
  3. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/pyproject.toml +2 -1
  4. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/cli/main.py +26 -11
  5. factorforge_cds-3.5.10/src/factorforge/closed_loop/__init__.py +27 -0
  6. factorforge_cds-3.5.10/src/factorforge/closed_loop/contracts.py +103 -0
  7. factorforge_cds-3.5.10/src/factorforge/closed_loop/ledger.py +222 -0
  8. factorforge_cds-3.5.10/src/factorforge/closed_loop/readiness.py +172 -0
  9. factorforge_cds-3.5.10/src/factorforge/codon/__init__.py +25 -0
  10. factorforge_cds-3.5.10/src/factorforge/codon/allocator.py +87 -0
  11. factorforge_cds-3.5.10/src/factorforge/codon/policy.py +212 -0
  12. factorforge_cds-3.5.10/src/factorforge/codon/qa.py +166 -0
  13. factorforge_cds-3.5.10/src/factorforge/codon/twin_generator.py +338 -0
  14. factorforge_cds-3.5.10/src/factorforge/core/__init__.py +35 -0
  15. factorforge_cds-3.5.10/src/factorforge/core/experiment.py +282 -0
  16. factorforge_cds-3.5.10/src/factorforge/core/policy.py +403 -0
  17. factorforge_cds-3.5.10/src/factorforge/data/human_stemcell_codons.json +329 -0
  18. factorforge_cds-3.5.10/src/factorforge/data/profiles/human_stemcell_derived_codons.json +329 -0
  19. factorforge_cds-3.5.10/src/factorforge/data/profiles/human_stemcell_policy.json +76 -0
  20. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/__init__.py +26 -0
  21. factorforge_cds-3.5.10/src/factorforge/engines/dp_v2_2.py +617 -0
  22. factorforge_cds-3.5.10/src/factorforge/engines/dp_v2_3.py +770 -0
  23. factorforge_cds-3.5.10/src/factorforge/engines/local_rewriter.py +1575 -0
  24. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/utils.py +1 -0
  25. factorforge_cds-3.5.10/src/factorforge/engines/sllm/adapters.py +241 -0
  26. factorforge_cds-3.5.10/src/factorforge/engines/stemcell_3dp.py +395 -0
  27. factorforge_cds-3.5.10/src/factorforge/engines/structural_pause.py +219 -0
  28. factorforge_cds-3.5.10/src/factorforge/engines/structure_web.py +111 -0
  29. factorforge_cds-3.5.10/src/factorforge/guards/__init__.py +15 -0
  30. factorforge_cds-3.5.10/src/factorforge/guards/initiation_mfe.py +141 -0
  31. factorforge_cds-3.5.10/src/factorforge/guards/plant_rna_guards.py +303 -0
  32. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/io/__init__.py +2 -2
  33. factorforge_cds-3.5.10/src/factorforge/io/package_compiler.py +467 -0
  34. factorforge_cds-3.5.10/src/factorforge/nbfold/__init__.py +94 -0
  35. factorforge_cds-3.5.10/src/factorforge/nbfold/annotations.py +1743 -0
  36. factorforge_cds-3.5.10/src/factorforge/nbfold/bridge.py +1200 -0
  37. factorforge_cds-3.5.10/src/factorforge/nbfold/cli.py +228 -0
  38. factorforge_cds-3.5.10/src/factorforge/nbfold/contracts.py +303 -0
  39. factorforge_cds-3.5.10/src/factorforge/nbfold/pipeline.py +1580 -0
  40. factorforge_cds-3.5.10/src/factorforge/pipeline/__init__.py +5 -0
  41. factorforge_cds-3.5.10/src/factorforge/pipeline/design_pipeline.py +631 -0
  42. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/registry/version_manifest.json +30 -3
  43. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/rules/registry.py +80 -5
  44. factorforge_cds-3.5.10/src/factorforge/structure/__init__.py +11 -0
  45. factorforge_cds-3.5.10/src/factorforge/structure/auto_annotator.py +296 -0
  46. factorforge_cds-3.5.10/src/factorforge/structure/auto_resolver.py +174 -0
  47. factorforge_cds-3.5.10/src/factorforge/telemetry/__init__.py +19 -0
  48. factorforge_cds-3.5.10/src/factorforge/telemetry/gcs_reconciliation.py +266 -0
  49. factorforge_cds-3.5.10/src/factorforge/telemetry/training_logger.py +600 -0
  50. factorforge_cds-3.5.10/src/factorforge/validation/tradeoff_suite.py +591 -0
  51. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10/src/factorforge_cds.egg-info}/PKG-INFO +51 -4
  52. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge_cds.egg-info/SOURCES.txt +65 -0
  53. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge_cds.egg-info/requires.txt +1 -0
  54. factorforge_cds-3.5.10/tests/test_3dp_review_regressions.py +33 -0
  55. factorforge_cds-3.5.10/tests/test_3dp_validation_suite.py +149 -0
  56. factorforge_cds-3.5.10/tests/test_auto_annotator.py +111 -0
  57. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_benchmark_regression.py +2 -1
  58. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_benchmark_smoke.py +2 -2
  59. factorforge_cds-3.5.10/tests/test_candidate_review_safety.py +98 -0
  60. factorforge_cds-3.5.10/tests/test_dp_v2_2_0.py +153 -0
  61. factorforge_cds-3.5.10/tests/test_dp_v2_3_0.py +184 -0
  62. factorforge_cds-3.5.10/tests/test_durable_reconciliation.py +225 -0
  63. factorforge_cds-3.5.10/tests/test_enterprise_integration_396.py +142 -0
  64. factorforge_cds-3.5.10/tests/test_hpx_viewer.py +125 -0
  65. factorforge_cds-3.5.10/tests/test_initiation_mfe.py +54 -0
  66. factorforge_cds-3.5.10/tests/test_job350_codon_twins.py +159 -0
  67. factorforge_cds-3.5.10/tests/test_job351_closed_loop_foundation.py +253 -0
  68. factorforge_cds-3.5.10/tests/test_job355_design_experiment.py +523 -0
  69. factorforge_cds-3.5.10/tests/test_local_rewriter.py +353 -0
  70. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_multi_engine_governance.py +3 -3
  71. factorforge_cds-3.5.10/tests/test_nbfold_phase_c.py +767 -0
  72. factorforge_cds-3.5.10/tests/test_nbfold_phase_c_benchmark.py +817 -0
  73. factorforge_cds-3.5.10/tests/test_nbfold_pipeline.py +897 -0
  74. factorforge_cds-3.5.10/tests/test_oct23_review.py +73 -0
  75. factorforge_cds-3.5.10/tests/test_onnx_adapter_contract.py +126 -0
  76. factorforge_cds-3.5.10/tests/test_plant_rna_guards.py +139 -0
  77. factorforge_cds-3.5.10/tests/test_policy_type_iis_targets.py +30 -0
  78. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_rule_registry.py +32 -0
  79. factorforge_cds-3.5.10/tests/test_scientific_web_397.py +168 -0
  80. factorforge_cds-3.5.10/tests/test_stemcell_3dp.py +255 -0
  81. factorforge_cds-3.5.10/tests/test_structural_pause.py +82 -0
  82. factorforge_cds-3.5.10/tests/test_training_logger.py +266 -0
  83. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_version_manifest.py +5 -2
  84. factorforge_cds-3.5.4/src/factorforge/engines/sllm/adapters.py +0 -193
  85. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/LICENSE +0 -0
  86. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/setup.cfg +0 -0
  87. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/__init__.py +0 -0
  88. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/__main__.py +0 -0
  89. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/analysis/__init__.py +0 -0
  90. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/analysis/feasibility.py +0 -0
  91. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/analysis/metrics.py +0 -0
  92. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/analysis/sequence_risks.py +0 -0
  93. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/benchmark/models.py +0 -0
  94. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/benchmark/runner.py +0 -0
  95. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/cli/__init__.py +0 -0
  96. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/cli/benchmark_cli.py +0 -0
  97. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/cli/legacy_cli.py +0 -0
  98. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/constraints/__init__.py +0 -0
  99. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/constraints/type_iis.py +0 -0
  100. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/core/host_model.py +0 -0
  101. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/core/interfaces/__init__.py +0 -0
  102. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/core/interfaces/exporter.py +0 -0
  103. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/core/interfaces/optimizer.py +0 -0
  104. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/core/interfaces/validator.py +0 -0
  105. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/core/reranker.py +0 -0
  106. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/core/slate_engine.py +0 -0
  107. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/core/slate_generator.py +0 -0
  108. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/nbenthamiana_codons.json +0 -0
  109. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/nbenthamiana_golden_set.json +0 -0
  110. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/ntabacum_codons.json +0 -0
  111. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/profiles/nbev11_cds_all_derived_codons.json +0 -0
  112. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/profiles/nbev11_cds_all_derived_filtered_stats.json +0 -0
  113. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/profiles/nbev11_cds_all_derived_manifest.json +0 -0
  114. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/profiles/nbev11_cds_hc_derived_codons.json +0 -0
  115. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/profiles/nbev11_cds_hc_derived_filtered_stats.json +0 -0
  116. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/profiles/nbev11_cds_hc_derived_manifest.json +0 -0
  117. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/profiles/qld183_v103_derived_codons.json +0 -0
  118. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/profiles/qld183_v103_derived_manifest.json +0 -0
  119. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/profiles/qld183_v103_filtered_stats.json +0 -0
  120. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/reference/reference_policy_manifest.json +0 -0
  121. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/templates/high_expression.json +0 -0
  122. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/templates/standard_expression.json +0 -0
  123. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/data/wolffia_globosa_codons.json +0 -0
  124. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/database.py +0 -0
  125. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/db/__init__.py +0 -0
  126. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/db/connector.py +0 -0
  127. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/design_review.py +0 -0
  128. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/discovery/__init__.py +0 -0
  129. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/discovery/acquisition.py +0 -0
  130. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/discovery/acquisition_logger.py +0 -0
  131. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/discovery/filter.py +0 -0
  132. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/discovery/generator.py +0 -0
  133. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/discovery/panel_builder.py +0 -0
  134. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/discovery/schemas.py +0 -0
  135. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/discovery/slate.py +0 -0
  136. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/discovery/traits.py +0 -0
  137. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/balanced_optimizer.py +0 -0
  138. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/dp_adapter.py +0 -0
  139. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/dp_v2.py +0 -0
  140. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/dp_v2_1.py +0 -0
  141. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/dp_v2_1_1.py +0 -0
  142. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/lm/__init__.py +0 -0
  143. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/lm/adapter.py +0 -0
  144. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/lm/diagnostics.py +0 -0
  145. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/lm/inference.py +0 -0
  146. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/lm/models/__init__.py +0 -0
  147. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/lm/models/mbart_codon.py +0 -0
  148. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/lm/tokenizer/control_tokenizer.py +0 -0
  149. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/__init__.py +0 -0
  150. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/codon_table_builder.py +0 -0
  151. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/construct_builder.py +0 -0
  152. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/exporter.py +0 -0
  153. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/optimizer.py +0 -0
  154. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/pipeline.py +0 -0
  155. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/rules/__init__.py +0 -0
  156. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/rules/domesticator.py +0 -0
  157. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/rules/reverse_translator.py +0 -0
  158. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/rules/rule_engine.py +0 -0
  159. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/scoring.py +0 -0
  160. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/scoring_ml.py +0 -0
  161. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/profile/validator.py +0 -0
  162. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/registry.py +0 -0
  163. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/automaton.py +0 -0
  164. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/compiler.py +0 -0
  165. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/data/__init__.py +0 -0
  166. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/data/corpus_builder.py +0 -0
  167. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/data/tokenizer.py +0 -0
  168. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/decoder.py +0 -0
  169. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/interfaces.py +0 -0
  170. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/model/__init__.py +0 -0
  171. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/model/arch.py +0 -0
  172. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/model/baselines.py +0 -0
  173. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/sllm/model/export_onnx.py +0 -0
  174. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/engines/targeted_remediator.py +0 -0
  175. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/evaluation/evaluator.py +0 -0
  176. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/evaluation/evidence_logger.py +0 -0
  177. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/evaluation/metrics.py +0 -0
  178. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/evaluation/models.py +0 -0
  179. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/io/fasta.py +0 -0
  180. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/io/validation.py +0 -0
  181. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/learning/__init__.py +0 -0
  182. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/learning/ranker.py +0 -0
  183. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/profiles/profile_snapshot.py +0 -0
  184. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/protein_risk/__init__.py +0 -0
  185. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/protein_risk/annotate.py +0 -0
  186. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/protein_risk/kd_scale.py +0 -0
  187. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/protein_risk/risk_classifier.py +0 -0
  188. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/protein_risk/sp_predict.py +0 -0
  189. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/protein_risk/tm_predict.py +0 -0
  190. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/registry/__init__.py +0 -0
  191. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/registry/method_registry.py +0 -0
  192. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/registry/model_registry.py +0 -0
  193. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/registry/registry_loader.py +0 -0
  194. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/registry/versioning.py +0 -0
  195. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/review/__init__.py +0 -0
  196. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/review/evaluation_integrity.py +0 -0
  197. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/rules/models.py +0 -0
  198. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/schemas/__init__.py +0 -0
  199. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/schemas/design_package.py +0 -0
  200. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/schemas/design_package.schema.json +0 -0
  201. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/schemas/evidence.py +0 -0
  202. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/schemas/run_config.schema.json +0 -0
  203. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/scoring/quantization.py +0 -0
  204. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/sops/config.py +0 -0
  205. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/utils/__init__.py +0 -0
  206. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/utils/construct_id.py +0 -0
  207. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/utils/exceptions.py +0 -0
  208. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/utils/restriction_sites.py +0 -0
  209. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/utils/sequence_identity.py +0 -0
  210. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/utils/sequence_validator.py +0 -0
  211. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/utils/validation.py +0 -0
  212. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/validation/__init__.py +0 -0
  213. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/validation/cli.py +0 -0
  214. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/validation/hub.py +0 -0
  215. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/validation/package_generator.py +0 -0
  216. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/validation_registry.py +0 -0
  217. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge/validation_report.py +0 -0
  218. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge_cds.egg-info/dependency_links.txt +0 -0
  219. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge_cds.egg-info/entry_points.txt +0 -0
  220. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/src/factorforge_cds.egg-info/top_level.txt +0 -0
  221. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_baselines.py +0 -0
  222. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_benchmark_cli_output_guard.py +0 -0
  223. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_benchmark_codon_table_metadata.py +0 -0
  224. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_benchmark_harness.py +0 -0
  225. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_benchmark_scoring.py +0 -0
  226. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_cai.py +0 -0
  227. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_codon_table_manifest.py +0 -0
  228. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_cross_engine_evaluation.py +0 -0
  229. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_database.py +0 -0
  230. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_database_configuration.py +0 -0
  231. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_db_connector.py +0 -0
  232. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_design_package_schema.py +0 -0
  233. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_design_package_semantics.py +0 -0
  234. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_design_package_serialization.py +0 -0
  235. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_design_review.py +0 -0
  236. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_docs_consistency.py +0 -0
  237. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_dp_v2_1_1.py +0 -0
  238. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_dp_v2_1_initiation.py +0 -0
  239. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_fasta_io.py +0 -0
  240. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_gc_content.py +0 -0
  241. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_host_profile_metadata.py +0 -0
  242. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_iupac_validation.py +0 -0
  243. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_learning_workflow_boundary.py +0 -0
  244. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_legacy_cli.py +0 -0
  245. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_lm_alpha_contract.py +0 -0
  246. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_math_v2_dp_optimality.py +0 -0
  247. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_no_raw_sequence_logging.py +0 -0
  248. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_openbio_missing_metric_contract.py +0 -0
  249. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_optional_postgres.py +0 -0
  250. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_parameter_registry.py +0 -0
  251. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_partial_dp_rescue.py +0 -0
  252. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_prepare_lm_dataset.py +0 -0
  253. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_protein_risk.py +0 -0
  254. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_public_surface_scanner.py +0 -0
  255. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_quantized_scoring.py +0 -0
  256. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_registry_production_sync.py +0 -0
  257. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_restriction_sites.py +0 -0
  258. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_sequence_validator.py +0 -0
  259. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_sllm_biological_pipeline.py +0 -0
  260. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_slm_decoder.py +0 -0
  261. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_slm_interface.py +0 -0
  262. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_sop_profile.py +0 -0
  263. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_suite_capability_compat.py +0 -0
  264. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_translation_integrity.py +0 -0
  265. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_validation_contract_compat.py +0 -0
  266. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_validation_registry.py +0 -0
  267. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_validation_report.py +0 -0
  268. {factorforge_cds-3.5.4 → factorforge_cds-3.5.10}/tests/test_worked_example.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: factorforge-cds
3
- Version: 3.5.4
3
+ Version: 3.5.10
4
4
  Summary: FactorForge - open-source CDS design and pre-synthesis sequence review by Eijex.
5
5
  Author-email: Eijex <eijex.lab@gmail.com>
6
6
  License-Expression: AGPL-3.0-only
@@ -22,6 +22,7 @@ Requires-Dist: pydantic>=2.0
22
22
  Provides-Extra: postgres
23
23
  Requires-Dist: psycopg2-binary>=2.9; extra == "postgres"
24
24
  Requires-Dist: sqlalchemy>=2.0; extra == "postgres"
25
+ Requires-Dist: eijex-db-core==0.1.2; extra == "postgres"
25
26
  Provides-Extra: dev
26
27
  Requires-Dist: jsonschema>=4.0; extra == "dev"
27
28
  Requires-Dist: pandas>=2.0; extra == "dev"
@@ -51,7 +52,7 @@ Dynamic: license-file
51
52
 
52
53
  FactorForge performs deterministic CDS design with CAI/GC metrics, PolyA-signal screening, and Golden Gate/MoClo-aware checks. It is positioned as a pre-synthesis review harness: it helps teams generate reproducible CDS candidates, inspect assembly-relevant sequence constraints, and package design metadata before downstream synthesis, cloning, or experimental review. Primary support: *N. benthamiana* (agroinfiltration). Experimental host context: Tobacco BY-2 (`--host by2`).
53
54
 
54
- FactorForge v3.5.4 uses independently versioned engines:
55
+ FactorForge v3.5.10 uses independently versioned engines:
55
56
 
56
57
  | Generation | Engine | Version | Availability |
57
58
  |---|---|---:|---|
@@ -89,6 +90,12 @@ Or use the **[web app](https://factorforge.eijex.com)** — no installation requ
89
90
 
90
91
  ## Repository Structure
91
92
 
93
+ Experimental codon-distribution and evidence-ledger modules in the development
94
+ checkout are scaffolds, not a validated laboratory policy or active learned
95
+ recommendation service. Computational checks do not establish synthesis readiness
96
+ or biological performance. Private inputs and collaborator packages must remain
97
+ outside public repositories and dashboards.
98
+
92
99
  The supported deterministic engines are the profile engine, stable DP v2, and
93
100
  the explicit DP v2.1.1 development candidate under:
94
101
 
@@ -127,7 +134,7 @@ FactorForge outputs are **in-silico only** and have not been experimentally vali
127
134
  ## Citing
128
135
 
129
136
  ```
130
- FactorForge v3.5.4 (2026). Open-source constraint-based CDS design and sequence review.
137
+ FactorForge v3.5.10 (2026). Open-source constraint-based CDS design and sequence review.
131
138
  Eijex. https://github.com/eijex/factorforge-cds
132
139
  ```
133
140
 
@@ -143,7 +150,10 @@ FactorForge design, CLI, Python API, and file export do not require a database.
143
150
  PostgreSQL persistence is an explicit Eijex integration path for retaining shared
144
151
  campaign and candidate identities; it is not enabled by default.
145
152
 
146
- Install `pip install "factorforge-cds[postgres]"` only when using that integration.
153
+ The extra pins `eijex-db-core==0.1.2`. Supply its approved wheel bundle using
154
+ `pip install --find-links PATH_TO_BUNDLE "factorforge-cds[postgres]"`; the shared
155
+ package is not assumed to have been published on PyPI. Standalone installation
156
+ does not require it.
147
157
  The deployment must also provide a compatible `eijex-db-core` package and set
148
158
  `FACTORFORGE_DATABASE_URL`. FactorForge contains no default database credentials and
149
159
  does not silently fall back to another backend. See [Persistence](docs/persistence.md).
@@ -176,3 +186,40 @@ GNU Affero General Public License v3.0 — see [LICENSE](LICENSE).
176
186
  - **Eijex MCP** — [mcp.eijex.com](https://mcp.eijex.com)
177
187
  - **Lab** — [www.eijex.com](https://www.eijex.com)
178
188
 
189
+
190
+ ## Testing status
191
+
192
+ The web UI now labels watermark as disabled and distinguishes the sequence-only baseline from experimental structure-conditioned testing. The local approved workflow supports explicit 1DP-only or paired 3DP mode. 3DP availability is local research testing; it is not a new public optimization endpoint or a biological-performance claim. See [web UI boundaries](web/README.md).
193
+
194
+ ## Direct 3DP browser testing (unreleased)
195
+
196
+ The FactorForge form supports explicit 1DP/3DP selection. 3DP uploads a PDB/mmCIF file, selects chain and one-based file model order, and requires reviewed one-based protein positions. The selected observed chain must exactly match the complete protein; partial or homologous structures require the retained local reviewed mapping workflow. Direct requests use `/api/optimize` with `design_mode=paired_3dp` and `structure_context={content,format,chain,model,positions,positions_reviewed,target_adaptiveness,penalty_weight}`.
197
+
198
+ Limits: 3–300 amino acids, structure content 250 KB, HTTP JSON body 1 MB. Both candidates use the configured codon reference, requested GC and canonical motif exclusions plus custom additions. Invalid inputs and infeasible candidates fail without a baseline fallback. Existing sequence-only settings and API requests remain supported. 3DP uses its explicit DP settings and does not apply Kozak, TpA, template or seed transformations. SOP checks are reported for both candidates; regeneration is manual and never silently changes mode. Watermark stays disabled.
199
+
200
+ This is stateless computational testing, with no external service dependencies or remote database recording. Those existing integrations remain available for later operational use. The structure file is not retained in the response or browser history; normal design results may be retained in local browser history. Submit only public-safe inputs. Structural conformity metrics are codon-weight proxies, not folding/expression measurements. These source changes are not deployed or a new package release.
201
+
202
+ ## Current public policy UI (2026-10-12)
203
+
204
+ Custom SOP management is paused. The built-in FactorForge default policy is applied; upload/export/preset/editing controls are hidden and disabled. Their code and previous browser configuration remain available for later reactivation through ENABLE_CUSTOM_SOP. Saved custom SOPs are ignored without deletion. 1DP/3DP mode selection and explicit structure inputs remain active. This supersedes the earlier public SOP upload/export instructions. Public API contracts are retained.
205
+
206
+ ### Scientific web observations
207
+
208
+ Direct 1DP/3DP browser testing reports sense-CDS RNA motif scans and available initiation-window MFE in results, downloadable reports and local history. Structure confidence observations can suggest positions for explicit acceptance and review; unsupported inputs do not invent positions. These checks do not establish expression, yield or folding benefits. The default policy remains active and custom SOP management remains paused. See `docs/experimental-structure.md` for the API and measurement boundary.
209
+
210
+ ### Local reviewed structure file workflow
211
+
212
+ `factorforge nbfold annotate` and `factorforge nbfold optimize` provide the experimental local Phase A/B workflow for exact-match structure files and an explicit user review manifest. See [NB-Fold documentation](docs/experimental-structure.md).
213
+
214
+ Web structure handling now requires exact-match uploaded PDB/mmCIF coordinates and explicit reviewed positions. Automatic external folding, artificial structure/confidence fallback, and auto-approval are disabled. Structure metrics are synthetic reconstruction checks; independent public-structure/DSSP validation remains open.
215
+
216
+ ### Experimental human-reference prototype
217
+
218
+ `factorforge.engines.stemcell_3dp.StemCell3DPOptimizer` is a local experimental interface using a generic human-frequency reference and provisional Eijex review criteria. It is not an MSC/iPSC-calibrated model or a laboratory-approved SOP. See [prototype boundaries](docs/model_cards/human-reference-prototype.md). It is not a new production web host.
219
+ # Local research candidate: DP v2.2
220
+
221
+ The opt-in Python `DPV220Optimizer` shares the v2.1.1 DP core and adds reviewed
222
+ position penalties. The experimental generic-human adapter uses this core;
223
+ existing plant web/NB-Fold routes retain their prior objective. See the
224
+ [model card](docs/model_cards/dp_v2_2.md) for usage, relaxation reporting and
225
+ engineering validation boundaries. This is not an expression or folding claim.
@@ -14,7 +14,7 @@
14
14
 
15
15
  FactorForge performs deterministic CDS design with CAI/GC metrics, PolyA-signal screening, and Golden Gate/MoClo-aware checks. It is positioned as a pre-synthesis review harness: it helps teams generate reproducible CDS candidates, inspect assembly-relevant sequence constraints, and package design metadata before downstream synthesis, cloning, or experimental review. Primary support: *N. benthamiana* (agroinfiltration). Experimental host context: Tobacco BY-2 (`--host by2`).
16
16
 
17
- FactorForge v3.5.4 uses independently versioned engines:
17
+ FactorForge v3.5.10 uses independently versioned engines:
18
18
 
19
19
  | Generation | Engine | Version | Availability |
20
20
  |---|---|---:|---|
@@ -52,6 +52,12 @@ Or use the **[web app](https://factorforge.eijex.com)** — no installation requ
52
52
 
53
53
  ## Repository Structure
54
54
 
55
+ Experimental codon-distribution and evidence-ledger modules in the development
56
+ checkout are scaffolds, not a validated laboratory policy or active learned
57
+ recommendation service. Computational checks do not establish synthesis readiness
58
+ or biological performance. Private inputs and collaborator packages must remain
59
+ outside public repositories and dashboards.
60
+
55
61
  The supported deterministic engines are the profile engine, stable DP v2, and
56
62
  the explicit DP v2.1.1 development candidate under:
57
63
 
@@ -90,7 +96,7 @@ FactorForge outputs are **in-silico only** and have not been experimentally vali
90
96
  ## Citing
91
97
 
92
98
  ```
93
- FactorForge v3.5.4 (2026). Open-source constraint-based CDS design and sequence review.
99
+ FactorForge v3.5.10 (2026). Open-source constraint-based CDS design and sequence review.
94
100
  Eijex. https://github.com/eijex/factorforge-cds
95
101
  ```
96
102
 
@@ -106,7 +112,10 @@ FactorForge design, CLI, Python API, and file export do not require a database.
106
112
  PostgreSQL persistence is an explicit Eijex integration path for retaining shared
107
113
  campaign and candidate identities; it is not enabled by default.
108
114
 
109
- Install `pip install "factorforge-cds[postgres]"` only when using that integration.
115
+ The extra pins `eijex-db-core==0.1.2`. Supply its approved wheel bundle using
116
+ `pip install --find-links PATH_TO_BUNDLE "factorforge-cds[postgres]"`; the shared
117
+ package is not assumed to have been published on PyPI. Standalone installation
118
+ does not require it.
110
119
  The deployment must also provide a compatible `eijex-db-core` package and set
111
120
  `FACTORFORGE_DATABASE_URL`. FactorForge contains no default database credentials and
112
121
  does not silently fall back to another backend. See [Persistence](docs/persistence.md).
@@ -139,3 +148,40 @@ GNU Affero General Public License v3.0 — see [LICENSE](LICENSE).
139
148
  - **Eijex MCP** — [mcp.eijex.com](https://mcp.eijex.com)
140
149
  - **Lab** — [www.eijex.com](https://www.eijex.com)
141
150
 
151
+
152
+ ## Testing status
153
+
154
+ The web UI now labels watermark as disabled and distinguishes the sequence-only baseline from experimental structure-conditioned testing. The local approved workflow supports explicit 1DP-only or paired 3DP mode. 3DP availability is local research testing; it is not a new public optimization endpoint or a biological-performance claim. See [web UI boundaries](web/README.md).
155
+
156
+ ## Direct 3DP browser testing (unreleased)
157
+
158
+ The FactorForge form supports explicit 1DP/3DP selection. 3DP uploads a PDB/mmCIF file, selects chain and one-based file model order, and requires reviewed one-based protein positions. The selected observed chain must exactly match the complete protein; partial or homologous structures require the retained local reviewed mapping workflow. Direct requests use `/api/optimize` with `design_mode=paired_3dp` and `structure_context={content,format,chain,model,positions,positions_reviewed,target_adaptiveness,penalty_weight}`.
159
+
160
+ Limits: 3–300 amino acids, structure content 250 KB, HTTP JSON body 1 MB. Both candidates use the configured codon reference, requested GC and canonical motif exclusions plus custom additions. Invalid inputs and infeasible candidates fail without a baseline fallback. Existing sequence-only settings and API requests remain supported. 3DP uses its explicit DP settings and does not apply Kozak, TpA, template or seed transformations. SOP checks are reported for both candidates; regeneration is manual and never silently changes mode. Watermark stays disabled.
161
+
162
+ This is stateless computational testing, with no external service dependencies or remote database recording. Those existing integrations remain available for later operational use. The structure file is not retained in the response or browser history; normal design results may be retained in local browser history. Submit only public-safe inputs. Structural conformity metrics are codon-weight proxies, not folding/expression measurements. These source changes are not deployed or a new package release.
163
+
164
+ ## Current public policy UI (2026-10-12)
165
+
166
+ Custom SOP management is paused. The built-in FactorForge default policy is applied; upload/export/preset/editing controls are hidden and disabled. Their code and previous browser configuration remain available for later reactivation through ENABLE_CUSTOM_SOP. Saved custom SOPs are ignored without deletion. 1DP/3DP mode selection and explicit structure inputs remain active. This supersedes the earlier public SOP upload/export instructions. Public API contracts are retained.
167
+
168
+ ### Scientific web observations
169
+
170
+ Direct 1DP/3DP browser testing reports sense-CDS RNA motif scans and available initiation-window MFE in results, downloadable reports and local history. Structure confidence observations can suggest positions for explicit acceptance and review; unsupported inputs do not invent positions. These checks do not establish expression, yield or folding benefits. The default policy remains active and custom SOP management remains paused. See `docs/experimental-structure.md` for the API and measurement boundary.
171
+
172
+ ### Local reviewed structure file workflow
173
+
174
+ `factorforge nbfold annotate` and `factorforge nbfold optimize` provide the experimental local Phase A/B workflow for exact-match structure files and an explicit user review manifest. See [NB-Fold documentation](docs/experimental-structure.md).
175
+
176
+ Web structure handling now requires exact-match uploaded PDB/mmCIF coordinates and explicit reviewed positions. Automatic external folding, artificial structure/confidence fallback, and auto-approval are disabled. Structure metrics are synthetic reconstruction checks; independent public-structure/DSSP validation remains open.
177
+
178
+ ### Experimental human-reference prototype
179
+
180
+ `factorforge.engines.stemcell_3dp.StemCell3DPOptimizer` is a local experimental interface using a generic human-frequency reference and provisional Eijex review criteria. It is not an MSC/iPSC-calibrated model or a laboratory-approved SOP. See [prototype boundaries](docs/model_cards/human-reference-prototype.md). It is not a new production web host.
181
+ # Local research candidate: DP v2.2
182
+
183
+ The opt-in Python `DPV220Optimizer` shares the v2.1.1 DP core and adds reviewed
184
+ position penalties. The experimental generic-human adapter uses this core;
185
+ existing plant web/NB-Fold routes retain their prior objective. See the
186
+ [model card](docs/model_cards/dp_v2_2.md) for usage, relaxation reporting and
187
+ engineering validation boundaries. This is not an expression or folding claim.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "factorforge-cds"
7
- version = "3.5.4"
7
+ version = "3.5.10"
8
8
  description = "FactorForge - open-source CDS design and pre-synthesis sequence review by Eijex."
9
9
  readme = "README.md"
10
10
  license = "AGPL-3.0-only"
@@ -30,6 +30,7 @@ dependencies = [
30
30
  postgres = [
31
31
  "psycopg2-binary>=2.9",
32
32
  "sqlalchemy>=2.0",
33
+ "eijex-db-core==0.1.2",
33
34
  ]
34
35
  dev = [
35
36
  "jsonschema>=4.0",
@@ -7,18 +7,18 @@ Usage:
7
7
  factorforge list-engines
8
8
  """
9
9
 
10
- from pathlib import Path
11
10
  import hashlib
12
11
  import json
13
12
  import sys
13
+ from pathlib import Path
14
14
 
15
15
  import click
16
16
 
17
17
  from factorforge import __version__
18
18
  from factorforge.analysis.feasibility import DEFAULT_CAI_TARGET
19
19
  from factorforge.engines import register_builtin_engines
20
- from factorforge.engines.registry import EngineRegistry
21
20
  from factorforge.engines.profile.utils import parse_fasta_records
21
+ from factorforge.engines.registry import EngineRegistry
22
22
 
23
23
  register_builtin_engines()
24
24
 
@@ -710,7 +710,10 @@ def evaluate_model(model_id, train_snapshot, eval_snapshot, input_sequence):
710
710
  mock_train_seqs = ["ATGGCTAAATGGTAA", "ATGCGTACGTGCTAG"]
711
711
  mock_eval_seqs = ["ATGCCCGGGAAATTT"]
712
712
 
713
- from factorforge.review.evaluation_integrity import DatasetLeakageAuditor, GenerationMemorizationAuditor
713
+ from factorforge.review.evaluation_integrity import (
714
+ DatasetLeakageAuditor,
715
+ GenerationMemorizationAuditor,
716
+ )
714
717
 
715
718
  # 2. Dataset Leakage Audit
716
719
  ds_auditor = DatasetLeakageAuditor(mock_train_seqs, mock_eval_seqs)
@@ -914,17 +917,22 @@ def audit(sequence_fasta, reference_codon_profile, exclude_region, output):
914
917
  Run generic sequence audit to report codon usage, CAI, GC, and AA distribution.
915
918
  """
916
919
  _configure_stdio()
917
- from factorforge.engines.profile.utils import parse_fasta_records
918
- from factorforge.analysis.metrics import (
919
- load_codon_usage_table, calculate_cai, calculate_gc, codon_usage_profile,
920
- translate_dna, calculate_synonymous_entropy, calculate_max_synonymous_share,
921
- calculate_reference_distance
922
- )
923
- from factorforge.engines.balanced_optimizer import STANDARD_GENETIC_CODE
924
-
925
920
  import hashlib
926
921
  import json
927
922
  from pathlib import Path
923
+
924
+ from factorforge.analysis.metrics import (
925
+ calculate_cai,
926
+ calculate_gc,
927
+ calculate_max_synonymous_share,
928
+ calculate_reference_distance,
929
+ calculate_synonymous_entropy,
930
+ codon_usage_profile,
931
+ load_codon_usage_table,
932
+ translate_dna,
933
+ )
934
+ from factorforge.engines.balanced_optimizer import STANDARD_GENETIC_CODE
935
+ from factorforge.engines.profile.utils import parse_fasta_records
928
936
 
929
937
  fasta_records = parse_fasta_records(Path(sequence_fasta).read_text(encoding='utf-8'))
930
938
  if not fasta_records:
@@ -988,6 +996,13 @@ def audit(sequence_fasta, reference_codon_profile, exclude_region, output):
988
996
  else:
989
997
  click.echo(json.dumps(results, indent=2))
990
998
 
999
+
1000
+ from factorforge.nbfold.cli import nbfold_cli
1001
+
1002
+ cli.add_command(nbfold_cli)
1003
+
1004
+
991
1005
  if __name__ == "__main__":
992
1006
  cli()
993
1007
 
1008
+
@@ -0,0 +1,27 @@
1
+ """FactorForge Closed-Loop Codon Evidence Foundation Package."""
2
+
3
+ from factorforge.closed_loop.contracts import (
4
+ ConstructRecord,
5
+ ConstructSetRecord,
6
+ ExperimentRecord,
7
+ MeasurementRecord,
8
+ PolicyRecord,
9
+ )
10
+ from factorforge.closed_loop.ledger import EvidenceLedger
11
+ from factorforge.closed_loop.readiness import (
12
+ ModelRecommendationGate,
13
+ ReadinessEvaluator,
14
+ ReadinessStatus,
15
+ )
16
+
17
+ __all__ = [
18
+ "ConstructRecord",
19
+ "ConstructSetRecord",
20
+ "EvidenceLedger",
21
+ "ExperimentRecord",
22
+ "MeasurementRecord",
23
+ "ModelRecommendationGate",
24
+ "PolicyRecord",
25
+ "ReadinessEvaluator",
26
+ "ReadinessStatus",
27
+ ]
@@ -0,0 +1,103 @@
1
+ """Data contracts and schemas for Closed-Loop DBTL Lineage."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import math
8
+ from datetime import datetime, timezone
9
+
10
+ from pydantic import BaseModel, Field, model_validator
11
+
12
+
13
+ class PolicyRecord(BaseModel):
14
+ """Metadata record of an approved codon distribution policy."""
15
+
16
+ policy_id: str
17
+ canonical_sha256: str
18
+ target_distribution: dict[str, dict[str, float]]
19
+ region_definition: str = "mature_chain"
20
+ feedback_source_id: str = "unspecified"
21
+ created_at: str = Field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
22
+
23
+
24
+ class ConstructRecord(BaseModel):
25
+ """Immutable sequence identity record for a designed construct."""
26
+
27
+ construct_id: str
28
+ cds_sha256: str
29
+ protein_sha256: str
30
+ chain: str # "LC" or "HC"
31
+ watermark_pair_id: str
32
+ watermark_applied: bool
33
+ achieved_distribution: dict[str, dict[str, float]]
34
+ policy_id: str
35
+ engine_version: str = "FactorForge-v3.3.0"
36
+
37
+
38
+ class ConstructSetRecord(BaseModel):
39
+ """Co-expressed pair of Light Chain and Heavy Chain constructs."""
40
+
41
+ construct_set_id: str
42
+ light_construct_id: str
43
+ heavy_construct_id: str
44
+ watermark_applied: bool
45
+ description: str = ""
46
+
47
+
48
+ class ExperimentRecord(BaseModel):
49
+ """Wet-lab or benchmark experiment metadata."""
50
+
51
+ experiment_id: str
52
+ construct_set_id: str
53
+ host: str = "Nicotiana benthamiana"
54
+ expression_system: str = "Agroinfiltration (Transient Leaf Expression)"
55
+ batch_id: str
56
+ experiment_date: str
57
+ protocol_version: str = "unspecified"
58
+
59
+
60
+ class MeasurementRecord(BaseModel):
61
+ """Single empirical or synthetic readout record."""
62
+
63
+ measurement_id: str
64
+ experiment_id: str
65
+ construct_set_id: str
66
+ biological_replicate_id: str
67
+ technical_replicate_id: str
68
+ measurement_type: str # "protein_yield", "mrna_abundance", "functional_binding"
69
+ value: float | None
70
+ unit: str # "mg/L", "relative_fold", "%"
71
+ qc_status: str = "PASS" # "PASS", "FAIL", "FLAGGED"
72
+ is_synthetic: bool = (
73
+ False # CRITICAL: If True, flagged as test_only and excluded from real training
74
+ )
75
+ tag: str = "empirical"
76
+ notes: str = ""
77
+ recorded_at: str = Field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
78
+
79
+ @model_validator(mode="after")
80
+ def validate_measurement(self):
81
+ if self.value is not None and not math.isfinite(self.value):
82
+ raise ValueError("Measurement value must be finite or null")
83
+ if self.is_synthetic:
84
+ self.tag = "test_only"
85
+ if self.qc_status not in {"PASS", "FAIL", "FLAGGED"}:
86
+ raise ValueError("Unknown QC status")
87
+ return self
88
+
89
+ @property
90
+ def record_hash(self) -> str:
91
+ payload = {
92
+ "measurement_id": self.measurement_id,
93
+ "experiment_id": self.experiment_id,
94
+ "construct_set_id": self.construct_set_id,
95
+ "biological_replicate_id": self.biological_replicate_id,
96
+ "technical_replicate_id": self.technical_replicate_id,
97
+ "measurement_type": self.measurement_type,
98
+ "value": self.value,
99
+ "unit": self.unit,
100
+ "is_synthetic": self.is_synthetic,
101
+ }
102
+ encoded = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")
103
+ return hashlib.sha256(encoded).hexdigest()
@@ -0,0 +1,222 @@
1
+ """Append-only Evidence Ledger for ValidationHub / FactorForge closed loop."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import os
8
+ from datetime import datetime, timezone
9
+ from pathlib import Path
10
+
11
+ from factorforge.closed_loop.contracts import (
12
+ ConstructRecord,
13
+ ConstructSetRecord,
14
+ ExperimentRecord,
15
+ MeasurementRecord,
16
+ PolicyRecord,
17
+ )
18
+ from factorforge.closed_loop.readiness import (
19
+ ReadinessEvaluator,
20
+ ReadinessReport,
21
+ )
22
+
23
+
24
+ class EvidenceLedger:
25
+ """Local file-based append-only registry storing closed-loop DBTL evidence."""
26
+
27
+ def __init__(self, ledger_dir: Path | None = None):
28
+ if ledger_dir is None:
29
+ ledger_dir = Path(__file__).resolve().parents[3] / "data" / "evidence_ledger"
30
+ self.ledger_dir = Path(ledger_dir)
31
+ self.ledger_dir.mkdir(parents=True, exist_ok=True)
32
+
33
+ self.policies_file = self.ledger_dir / "policies.jsonl"
34
+ self.constructs_file = self.ledger_dir / "constructs.jsonl"
35
+ self.construct_sets_file = self.ledger_dir / "construct_sets.jsonl"
36
+ self.experiments_file = self.ledger_dir / "experiments.jsonl"
37
+ self.measurements_file = self.ledger_dir / "measurements.jsonl"
38
+
39
+ def _append_jsonl(self, file_path: Path, record: dict):
40
+ identity_field = {
41
+ "policies.jsonl": "policy_id",
42
+ "constructs.jsonl": "construct_id",
43
+ "construct_sets.jsonl": "construct_set_id",
44
+ "experiments.jsonl": "experiment_id",
45
+ "measurements.jsonl": "measurement_id",
46
+ }[file_path.name]
47
+ for existing in self._read_jsonl(file_path):
48
+ if existing.get(identity_field) == record[identity_field]:
49
+ if existing == record:
50
+ return # Same record is idempotent, not another observation.
51
+ raise ValueError(
52
+ "Conflicting identity; preserve the original and use an explicit new revision"
53
+ )
54
+ with open(file_path, "a", encoding="utf-8") as f:
55
+ f.write(json.dumps(record, ensure_ascii=False) + "\n")
56
+
57
+ def _read_jsonl(self, file_path: Path) -> list[dict]:
58
+ if not file_path.exists():
59
+ return []
60
+ records = []
61
+ with open(file_path, "r", encoding="utf-8") as f:
62
+ for line in f:
63
+ line = line.strip()
64
+ if line:
65
+ records.append(json.loads(line))
66
+ return records
67
+
68
+ def register_policy(self, record: PolicyRecord):
69
+ self._append_jsonl(self.policies_file, record.model_dump())
70
+
71
+ def register_construct(self, record: ConstructRecord):
72
+ self._append_jsonl(self.constructs_file, record.model_dump())
73
+
74
+ def register_construct_set(self, record: ConstructSetRecord):
75
+ self._append_jsonl(self.construct_sets_file, record.model_dump())
76
+
77
+ def register_experiment(self, record: ExperimentRecord):
78
+ self._append_jsonl(self.experiments_file, record.model_dump())
79
+
80
+ def record_measurement(self, record: MeasurementRecord):
81
+ self._append_jsonl(self.measurements_file, record.model_dump())
82
+
83
+ def list_measurements(self, include_synthetic: bool = True) -> list[MeasurementRecord]:
84
+ raw = self._read_jsonl(self.measurements_file)
85
+ measurements = [MeasurementRecord(**r) for r in raw]
86
+ if not include_synthetic:
87
+ return [m for m in measurements if not m.is_synthetic]
88
+ return measurements
89
+
90
+ def get_readiness(self) -> ReadinessReport:
91
+ all_measurements = self.list_measurements(include_synthetic=True)
92
+ raw_experiments = self._read_jsonl(self.experiments_file)
93
+ experiments = {e["experiment_id"]: ExperimentRecord(**e) for e in raw_experiments}
94
+ all_measurements = [
95
+ m
96
+ if m.is_synthetic or self.verify_lineage(m.measurement_id)["lineage_intact"]
97
+ else m.model_copy(update={"qc_status": "FLAGGED"})
98
+ for m in all_measurements
99
+ ]
100
+ return ReadinessEvaluator.evaluate(all_measurements, experiments=experiments)
101
+
102
+ def verify_lineage(self, measurement_id: str) -> dict[str, object]:
103
+ """Verify unbroken provenance & referential consistency:
104
+ Measurement -> Experiment -> ConstructSet -> Construct -> Policy."""
105
+ measurements = {m["measurement_id"]: m for m in self._read_jsonl(self.measurements_file)}
106
+ experiments = {e["experiment_id"]: e for e in self._read_jsonl(self.experiments_file)}
107
+ construct_sets = {
108
+ s["construct_set_id"]: s for s in self._read_jsonl(self.construct_sets_file)
109
+ }
110
+ constructs = {c["construct_id"]: c for c in self._read_jsonl(self.constructs_file)}
111
+ policies = {p["policy_id"]: p for p in self._read_jsonl(self.policies_file)}
112
+
113
+ if measurement_id not in measurements:
114
+ raise KeyError(f"Measurement '{measurement_id}' not found in ledger")
115
+
116
+ m = measurements[measurement_id]
117
+ exp_id = m.get("experiment_id")
118
+ set_id = m.get("construct_set_id")
119
+
120
+ exp = experiments.get(exp_id)
121
+ cset = construct_sets.get(set_id)
122
+
123
+ lc_construct = constructs.get(cset.get("light_construct_id")) if cset else None
124
+ hc_construct = constructs.get(cset.get("heavy_construct_id")) if cset else None
125
+
126
+ policy_id = lc_construct.get("policy_id") if lc_construct else None
127
+ pol = policies.get(policy_id) if policy_id else None
128
+
129
+ violations: list[str] = []
130
+
131
+ # 1. Existence validations
132
+ if exp is None:
133
+ violations.append(f"Referenced experiment '{exp_id}' does not exist in ledger.")
134
+ if cset is None:
135
+ violations.append(f"Referenced construct_set '{set_id}' does not exist in ledger.")
136
+ if lc_construct is None:
137
+ violations.append("Referenced light chain construct does not exist in ledger.")
138
+ if hc_construct is None:
139
+ violations.append("Referenced heavy chain construct does not exist in ledger.")
140
+ if pol is None:
141
+ violations.append(f"Referenced policy '{policy_id}' does not exist in ledger.")
142
+
143
+ # 2. Referential integrity validations
144
+ if exp and cset and exp.get("construct_set_id") != set_id:
145
+ violations.append(
146
+ f"Referential mismatch: Measurement points to construct_set '{set_id}' "
147
+ f"but Experiment '{exp_id}' points to '{exp.get('construct_set_id')}'"
148
+ )
149
+
150
+ if lc_construct and hc_construct:
151
+ lc_pol = lc_construct.get("policy_id")
152
+ hc_pol = hc_construct.get("policy_id")
153
+ if lc_pol != hc_pol:
154
+ violations.append(
155
+ f"Policy mismatch between chains: LC is linked to '{lc_pol}' but HC is linked to '{hc_pol}'"
156
+ )
157
+
158
+ lineage_intact = len(violations) == 0
159
+
160
+ return {
161
+ "measurement_id": measurement_id,
162
+ "lineage_intact": lineage_intact,
163
+ "violations": violations,
164
+ "is_synthetic": m.get("is_synthetic", False),
165
+ "experiment": exp,
166
+ "construct_set": cset,
167
+ "light_construct": lc_construct,
168
+ "heavy_construct": hc_construct,
169
+ "policy": pol,
170
+ }
171
+
172
+ def sync_to_gcs(
173
+ self,
174
+ bucket_name: str,
175
+ destination_folder: str = "validationhub/ledger_v0",
176
+ gcp_key_path: str | None = None,
177
+ ) -> dict[str, str]:
178
+ """Sync append-only ledger snapshot with atomic manifest to Google Cloud Storage."""
179
+ from google.cloud import storage
180
+
181
+ if gcp_key_path:
182
+ os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = gcp_key_path
183
+
184
+ client = storage.Client()
185
+ bucket = client.bucket(bucket_name)
186
+
187
+ # Generate atomic ledger manifest with SHA256 checksums
188
+ manifest_files = {}
189
+ target_files = [
190
+ self.policies_file,
191
+ self.constructs_file,
192
+ self.construct_sets_file,
193
+ self.experiments_file,
194
+ self.measurements_file,
195
+ ]
196
+
197
+ for file_path in target_files:
198
+ if file_path.exists():
199
+ content = file_path.read_bytes()
200
+ manifest_files[file_path.name] = {
201
+ "sha256": hashlib.sha256(content).hexdigest(),
202
+ "size_bytes": len(content),
203
+ }
204
+
205
+ manifest = {
206
+ "manifest_version": "0.2",
207
+ "snapshot_timestamp": datetime.now(timezone.utc).isoformat(),
208
+ "factorforge_version": "3.5.4",
209
+ "files": manifest_files,
210
+ }
211
+ manifest_file = self.ledger_dir / "ledger_manifest.json"
212
+ manifest_file.write_text(json.dumps(manifest, indent=2), encoding="utf-8")
213
+
214
+ uploaded = {}
215
+ for file_path in target_files + [manifest_file]:
216
+ if file_path.exists():
217
+ blob_name = f"{destination_folder}/{file_path.name}"
218
+ blob = bucket.blob(blob_name)
219
+ blob.upload_from_filename(str(file_path))
220
+ uploaded[file_path.name] = f"gs://{bucket_name}/{blob_name}"
221
+
222
+ return uploaded