factorforge-cds 3.2.2__tar.gz → 3.2.4__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 (100) hide show
  1. {factorforge_cds-3.2.2/src/factorforge_cds.egg-info → factorforge_cds-3.2.4}/PKG-INFO +10 -9
  2. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/README.md +8 -7
  3. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/pyproject.toml +2 -2
  4. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/__init__.py +1 -1
  5. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/analysis/feasibility.py +2 -2
  6. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/cli/main.py +8 -1
  7. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/__init__.py +1 -1
  8. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/__init__.py +1 -1
  9. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/construct_builder.py +5 -2
  10. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/optimizer.py +15 -1
  11. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/rules/reverse_translator.py +1 -1
  12. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/rules/rule_engine.py +2 -2
  13. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/scoring.py +1 -1
  14. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/validation/cli.py +3 -3
  15. factorforge_cds-3.2.4/src/factorforge/validation_registry.py +322 -0
  16. factorforge_cds-3.2.4/src/factorforge/validation_report.py +90 -0
  17. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4/src/factorforge_cds.egg-info}/PKG-INFO +10 -9
  18. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge_cds.egg-info/SOURCES.txt +5 -0
  19. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_benchmark_codon_table_metadata.py +1 -1
  20. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_codon_table_manifest.py +1 -1
  21. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_docs_consistency.py +15 -4
  22. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_host_profile_metadata.py +1 -1
  23. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_registry_production_sync.py +2 -2
  24. factorforge_cds-3.2.4/tests/test_validation_contract_compat.py +51 -0
  25. factorforge_cds-3.2.4/tests/test_validation_registry.py +103 -0
  26. factorforge_cds-3.2.4/tests/test_validation_report.py +130 -0
  27. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/LICENSE +0 -0
  28. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/setup.cfg +0 -0
  29. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/__main__.py +0 -0
  30. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/analysis/__init__.py +0 -0
  31. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/analysis/metrics.py +0 -0
  32. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/cli/__init__.py +0 -0
  33. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/cli/legacy_cli.py +0 -0
  34. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/core/interfaces/__init__.py +0 -0
  35. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/core/interfaces/exporter.py +0 -0
  36. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/core/interfaces/optimizer.py +0 -0
  37. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/core/interfaces/validator.py +0 -0
  38. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/data/nbenthamiana_codons.json +0 -0
  39. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/data/nbenthamiana_golden_set.json +0 -0
  40. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/data/ntabacum_codons.json +0 -0
  41. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/data/templates/high_expression.json +0 -0
  42. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/data/templates/standard_expression.json +0 -0
  43. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/data/wolffia_globosa_codons.json +0 -0
  44. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/database.py +0 -0
  45. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/codon_table_builder.py +0 -0
  46. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/exporter.py +0 -0
  47. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/pipeline.py +0 -0
  48. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/rules/__init__.py +0 -0
  49. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/rules/domesticator.py +0 -0
  50. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/scoring_ml.py +0 -0
  51. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/utils.py +0 -0
  52. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/profile/validator.py +0 -0
  53. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/engines/registry.py +0 -0
  54. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/io/__init__.py +0 -0
  55. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/io/fasta.py +0 -0
  56. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/io/validation.py +0 -0
  57. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/protein_risk/__init__.py +0 -0
  58. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/protein_risk/annotate.py +0 -0
  59. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/protein_risk/kd_scale.py +0 -0
  60. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/protein_risk/risk_classifier.py +0 -0
  61. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/protein_risk/sp_predict.py +0 -0
  62. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/protein_risk/tm_predict.py +0 -0
  63. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/registry/__init__.py +0 -0
  64. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/registry/registry_loader.py +0 -0
  65. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/schemas/__init__.py +0 -0
  66. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/schemas/design_package.py +0 -0
  67. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/schemas/design_package.schema.json +0 -0
  68. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/utils/__init__.py +0 -0
  69. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/utils/construct_id.py +0 -0
  70. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/utils/exceptions.py +0 -0
  71. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/utils/restriction_sites.py +0 -0
  72. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/utils/sequence_validator.py +0 -0
  73. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/utils/validation.py +0 -0
  74. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/validation/__init__.py +0 -0
  75. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge/validation/package_generator.py +0 -0
  76. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge_cds.egg-info/dependency_links.txt +0 -0
  77. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge_cds.egg-info/entry_points.txt +0 -0
  78. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge_cds.egg-info/requires.txt +0 -0
  79. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/src/factorforge_cds.egg-info/top_level.txt +0 -0
  80. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_baselines.py +0 -0
  81. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_benchmark_regression.py +0 -0
  82. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_benchmark_scoring.py +0 -0
  83. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_benchmark_smoke.py +0 -0
  84. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_cai.py +0 -0
  85. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_database.py +0 -0
  86. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_design_package_schema.py +0 -0
  87. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_design_package_semantics.py +0 -0
  88. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_design_package_serialization.py +0 -0
  89. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_fasta_io.py +0 -0
  90. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_gc_content.py +0 -0
  91. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_iupac_validation.py +0 -0
  92. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_legacy_cli.py +0 -0
  93. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_no_raw_sequence_logging.py +0 -0
  94. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_openbio_missing_metric_contract.py +0 -0
  95. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_parameter_registry.py +0 -0
  96. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_protein_risk.py +0 -0
  97. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_restriction_sites.py +0 -0
  98. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_sequence_validator.py +0 -0
  99. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_translation_integrity.py +0 -0
  100. {factorforge_cds-3.2.2 → factorforge_cds-3.2.4}/tests/test_worked_example.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: factorforge-cds
3
- Version: 3.2.2
4
- Summary: FactorForge - open-source constraint-based CDS design engine by Eijex.
3
+ Version: 3.2.4
4
+ Summary: FactorForge - open-source CDS design and pre-synthesis sequence review engine by Eijex.
5
5
  Author-email: Eijex <eijex.lab@gmail.com>
6
6
  License-Expression: AGPL-3.0-only
7
7
  Project-URL: Homepage, https://factorforge.eijex.com
@@ -33,19 +33,19 @@ Dynamic: license-file
33
33
 
34
34
  # FactorForge
35
35
 
36
- **Open-source constraint-based CDS design engine for sequence-level CDS design, with primary support for *Nicotiana benthamiana* (Tobacco BY-2: experimental).**
36
+ **Open-source constraint-based CDS design and pre-synthesis sequence review engine for plant CDS workflows, with primary support for *Nicotiana benthamiana* (Tobacco BY-2: experimental).**
37
37
 
38
38
  [![License](https://img.shields.io/badge/license-AGPL--3.0-blue.svg)](LICENSE)
39
39
  [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
40
40
  [![PyPI](https://img.shields.io/pypi/v/factorforge-cds.svg)](https://pypi.org/project/factorforge-cds/)
41
41
  [![CI](https://github.com/eijex/factorforge-cds/actions/workflows/ci.yml/badge.svg)](https://github.com/eijex/factorforge-cds/actions/workflows/ci.yml)
42
42
  [![codecov](https://codecov.io/gh/eijex/factorforge-cds/branch/main/graph/badge.svg)](https://codecov.io/gh/eijex/factorforge-cds)
43
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.20640931.svg)](https://doi.org/10.5281/zenodo.20640931)
43
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.20407330.svg)](https://doi.org/10.5281/zenodo.20407330)
44
44
  [![Web App](https://img.shields.io/badge/web-factorforge.eijex.com-brightgreen.svg)](https://factorforge.eijex.com)
45
45
 
46
- FactorForge performs profile-guided CDS design with CAI/GC metrics, PolyA-signal screening, and Golden Gate/MoClo-aware checks. Primary support: *N. benthamiana* (agroinfiltration). Experimental host context: Tobacco BY-2 (`--host by2`).
46
+ FactorForge performs profile-guided 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`).
47
47
 
48
- **→ [Full Documentation](https://eijex.github.io/factorforge-cds/)**
48
+ **→ [Full Documentation](https://eijex.github.io/factorforge-cds/)** · **[Roadmap](https://eijex.github.io/factorforge-cds/roadmap/)**
49
49
 
50
50
  ---
51
51
 
@@ -86,14 +86,14 @@ and are not imported by the installed package or exposed as supported engines.
86
86
 
87
87
  ## ⚠️ Validation Status
88
88
 
89
- FactorForge outputs are **in-silico only** and have not been experimentally validated in wet-lab conditions. See [Validation](https://eijex.github.io/factorforge-cds/validation/) and [VALIDATION.md](VALIDATION.md).
89
+ FactorForge outputs are **in-silico only** and have not been experimentally validated in wet-lab conditions. These checks support reviewability and reproducibility; they do not guarantee expression, yield, synthesis acceptance, folding, glycosylation, regulatory approval, or downstream biological performance. See [Validation](https://eijex.github.io/factorforge-cds/validation/) and [VALIDATION.md](VALIDATION.md).
90
90
 
91
91
  ---
92
92
 
93
93
  ## Citing
94
94
 
95
95
  ```
96
- FactorForge v3.2.2 (2026). Open-source constraint-based CDS design engine.
96
+ FactorForge v3.2.4 (2026). Open-source constraint-based CDS design engine.
97
97
  Eijex. https://github.com/eijex/factorforge-cds
98
98
  ```
99
99
 
@@ -114,8 +114,9 @@ GNU Affero General Public License v3.0 — see [LICENSE](LICENSE).
114
114
  ## Get in Touch
115
115
 
116
116
  - **Docs** — [eijex.github.io/factorforge-cds](https://eijex.github.io/factorforge-cds/)
117
- - **Wet-lab Results** — Public-safe validation summaries are welcome. [Share Wet-lab Results (Form)](https://docs.google.com/forms/d/e/1FAIpQLSeSx-wYvF6YwHhSPdLMl-L44frCugdm25X_eDz50OaqTD66qA/viewform) or [Share Wet-lab Results (GitHub)](https://github.com/eijex/factorforge-cds/issues/new?template=wet_lab_result.yml) (public-safe summaries only). Do not submit raw sequences, confidential construct details, internal batch IDs, patient data, private contact information, exact process parameters, or confidential partner/customer data. See [VALIDATION.md](VALIDATION.md) before submitting.
117
+ - **Wet-lab Feedback** — Public-safe feedback summaries are welcome via [Share Wet-lab Feedback (GitHub)](https://github.com/eijex/factorforge-cds/issues/new?template=wet_lab_result.yml). Do not submit raw sequences, confidential construct details, internal batch IDs, patient data, private contact information, exact process parameters, or confidential partner/customer data. Email `eijex.lab@gmail.com` for private or sensitive summaries. See [VALIDATION.md](VALIDATION.md) before submitting.
118
118
  - **GitHub Issues** — bugs, features: [github.com/eijex/factorforge-cds/issues](https://github.com/eijex/factorforge-cds/issues)
119
119
  - **Email** — eijex.lab@gmail.com
120
120
  - **FactorForge** — [factorforge.eijex.com](https://factorforge.eijex.com)
121
+ - **Eijex MCP** — [mcp.eijex.com](https://mcp.eijex.com)
121
122
  - **Lab** — [www.eijex.com](https://www.eijex.com)
@@ -1,18 +1,18 @@
1
1
  # FactorForge
2
2
 
3
- **Open-source constraint-based CDS design engine for sequence-level CDS design, with primary support for *Nicotiana benthamiana* (Tobacco BY-2: experimental).**
3
+ **Open-source constraint-based CDS design and pre-synthesis sequence review engine for plant CDS workflows, with primary support for *Nicotiana benthamiana* (Tobacco BY-2: experimental).**
4
4
 
5
5
  [![License](https://img.shields.io/badge/license-AGPL--3.0-blue.svg)](LICENSE)
6
6
  [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
7
7
  [![PyPI](https://img.shields.io/pypi/v/factorforge-cds.svg)](https://pypi.org/project/factorforge-cds/)
8
8
  [![CI](https://github.com/eijex/factorforge-cds/actions/workflows/ci.yml/badge.svg)](https://github.com/eijex/factorforge-cds/actions/workflows/ci.yml)
9
9
  [![codecov](https://codecov.io/gh/eijex/factorforge-cds/branch/main/graph/badge.svg)](https://codecov.io/gh/eijex/factorforge-cds)
10
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.20640931.svg)](https://doi.org/10.5281/zenodo.20640931)
10
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.20407330.svg)](https://doi.org/10.5281/zenodo.20407330)
11
11
  [![Web App](https://img.shields.io/badge/web-factorforge.eijex.com-brightgreen.svg)](https://factorforge.eijex.com)
12
12
 
13
- FactorForge performs profile-guided CDS design with CAI/GC metrics, PolyA-signal screening, and Golden Gate/MoClo-aware checks. Primary support: *N. benthamiana* (agroinfiltration). Experimental host context: Tobacco BY-2 (`--host by2`).
13
+ FactorForge performs profile-guided 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`).
14
14
 
15
- **→ [Full Documentation](https://eijex.github.io/factorforge-cds/)**
15
+ **→ [Full Documentation](https://eijex.github.io/factorforge-cds/)** · **[Roadmap](https://eijex.github.io/factorforge-cds/roadmap/)**
16
16
 
17
17
  ---
18
18
 
@@ -53,14 +53,14 @@ and are not imported by the installed package or exposed as supported engines.
53
53
 
54
54
  ## ⚠️ Validation Status
55
55
 
56
- FactorForge outputs are **in-silico only** and have not been experimentally validated in wet-lab conditions. See [Validation](https://eijex.github.io/factorforge-cds/validation/) and [VALIDATION.md](VALIDATION.md).
56
+ FactorForge outputs are **in-silico only** and have not been experimentally validated in wet-lab conditions. These checks support reviewability and reproducibility; they do not guarantee expression, yield, synthesis acceptance, folding, glycosylation, regulatory approval, or downstream biological performance. See [Validation](https://eijex.github.io/factorforge-cds/validation/) and [VALIDATION.md](VALIDATION.md).
57
57
 
58
58
  ---
59
59
 
60
60
  ## Citing
61
61
 
62
62
  ```
63
- FactorForge v3.2.2 (2026). Open-source constraint-based CDS design engine.
63
+ FactorForge v3.2.4 (2026). Open-source constraint-based CDS design engine.
64
64
  Eijex. https://github.com/eijex/factorforge-cds
65
65
  ```
66
66
 
@@ -81,8 +81,9 @@ GNU Affero General Public License v3.0 — see [LICENSE](LICENSE).
81
81
  ## Get in Touch
82
82
 
83
83
  - **Docs** — [eijex.github.io/factorforge-cds](https://eijex.github.io/factorforge-cds/)
84
- - **Wet-lab Results** — Public-safe validation summaries are welcome. [Share Wet-lab Results (Form)](https://docs.google.com/forms/d/e/1FAIpQLSeSx-wYvF6YwHhSPdLMl-L44frCugdm25X_eDz50OaqTD66qA/viewform) or [Share Wet-lab Results (GitHub)](https://github.com/eijex/factorforge-cds/issues/new?template=wet_lab_result.yml) (public-safe summaries only). Do not submit raw sequences, confidential construct details, internal batch IDs, patient data, private contact information, exact process parameters, or confidential partner/customer data. See [VALIDATION.md](VALIDATION.md) before submitting.
84
+ - **Wet-lab Feedback** — Public-safe feedback summaries are welcome via [Share Wet-lab Feedback (GitHub)](https://github.com/eijex/factorforge-cds/issues/new?template=wet_lab_result.yml). Do not submit raw sequences, confidential construct details, internal batch IDs, patient data, private contact information, exact process parameters, or confidential partner/customer data. Email `eijex.lab@gmail.com` for private or sensitive summaries. See [VALIDATION.md](VALIDATION.md) before submitting.
85
85
  - **GitHub Issues** — bugs, features: [github.com/eijex/factorforge-cds/issues](https://github.com/eijex/factorforge-cds/issues)
86
86
  - **Email** — eijex.lab@gmail.com
87
87
  - **FactorForge** — [factorforge.eijex.com](https://factorforge.eijex.com)
88
+ - **Eijex MCP** — [mcp.eijex.com](https://mcp.eijex.com)
88
89
  - **Lab** — [www.eijex.com](https://www.eijex.com)
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "factorforge-cds"
7
- version = "3.2.2"
8
- description = "FactorForge - open-source constraint-based CDS design engine by Eijex."
7
+ version = "3.2.4"
8
+ description = "FactorForge - open-source CDS design and pre-synthesis sequence review engine by Eijex."
9
9
  readme = "README.md"
10
10
  license = "AGPL-3.0-only"
11
11
  license-files = ["LICENSE"]
@@ -4,7 +4,7 @@ FactorForge - Codon Optimization Platform
4
4
  profile: constraint-aware rule/profile engine
5
5
  """
6
6
 
7
- __version__ = "3.2.2"
7
+ __version__ = "3.2.4"
8
8
  __author__ = "Eijex"
9
9
 
10
10
  # Auto-register engines (safe when running from source tree)
@@ -15,7 +15,7 @@ from factorforge.analysis.metrics import (
15
15
 
16
16
 
17
17
  # Defaults calibrated to nbenthamiana profile engine output distribution
18
- # (analysis 004, n=49): avg CAI=0.76, avg GC=60.1% (range 55-71%).
18
+ # (internal benchmark, n=49): avg CAI=0.76, avg GC=60.1% (range 55-71%).
19
19
  # DEFAULT_CAI_TARGET=0.82 aligns with industry practice (>0.8) and is achievable.
20
20
  # Exported as named constants so tests/test_registry_production_sync.py can
21
21
  # strictly compare them against the registry (single source of truth).
@@ -110,7 +110,7 @@ def analyze_feasibility(
110
110
  codon weights.
111
111
 
112
112
  See module-level DEFAULT_CAI_TARGET / DEFAULT_GC_LOW / DEFAULT_GC_HIGH for
113
- the calibration rationale (analysis 004, n=49).
113
+ the calibration rationale (internal benchmark, n=49).
114
114
  """
115
115
  protein = "".join(protein_sequence.upper().split()).rstrip("*")
116
116
  if not protein:
@@ -161,7 +161,7 @@ def list_engines():
161
161
  @click.option(
162
162
  "--objective",
163
163
  default="feasibility_best",
164
- type=click.Choice(["feasibility_best", "gc_target", "high_cai"], case_sensitive=False),
164
+ type=click.Choice(["feasibility_best"], case_sensitive=False),
165
165
  help="DP objective",
166
166
  )
167
167
  @click.option("--gc-min", type=float, default=55.0, help="Minimum target GC percentage")
@@ -212,6 +212,13 @@ def optimize(
212
212
  if host_was_explicit and engine == "dp" and internal_host != "nbenthamiana":
213
213
  engine = "profile"
214
214
 
215
+ if host_was_explicit and internal_host != "nbenthamiana":
216
+ if profile == "high_cai" or "high_cai" in (compare_profile_list or []):
217
+ raise click.UsageError(
218
+ "high_cai requires the N. benthamiana golden-set reference "
219
+ "and is not available for non-default hosts."
220
+ )
221
+
215
222
  if compare_profile_list:
216
223
  if engine == "dp" and _engine_option_was_explicitly_set():
217
224
  raise click.UsageError("--compare-profiles cannot be used with --engine dp.")
@@ -13,7 +13,7 @@ def register_builtin_engines() -> None:
13
13
  "profile",
14
14
  RuleBasedOptimizer,
15
15
  metadata={
16
- "version": "3.2.2",
16
+ "version": "3.2.4",
17
17
  "engine_type": "profile_rule_based",
18
18
  "role": "stable_profile_engine",
19
19
  "stable": True,
@@ -5,7 +5,7 @@ Production system (2026)
5
5
  Plant-specific rule-based optimization
6
6
  """
7
7
 
8
- __version__ = "3.2.2"
8
+ __version__ = "3.2.4"
9
9
 
10
10
  from .optimizer import RuleBasedOptimizer
11
11
  from .pipeline import OptimizationPipeline
@@ -19,10 +19,13 @@ if TYPE_CHECKING:
19
19
  class ConstructBuilder:
20
20
  """Assemble constructs from JSON templates."""
21
21
 
22
- def __init__(self, template_dir: Path) -> None:
22
+ def __init__(self, template_dir: Path | None = None) -> None:
23
23
  """
24
24
  Args:
25
- template_dir: Directory containing construct templates.
25
+ template_dir: Directory containing construct templates. Optional —
26
+ omit when only using template-independent methods such as
27
+ check_internal_overhang_collisions() or validate_overhangs(),
28
+ which do not read from disk.
26
29
  """
27
30
  self.template_dir = template_dir
28
31
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import logging
5
6
  from typing import Any
6
7
 
7
8
  from factorforge.core.interfaces import OptimizationResult, OptimizerEngine
@@ -12,12 +13,14 @@ from .rules.rule_engine import RuleEngine
12
13
  from .scoring import calculate_composite_score, compute_mfe_evidence
13
14
  from .validator import InputValidator
14
15
 
16
+ logger = logging.getLogger(__name__)
17
+
15
18
 
16
19
  class RuleBasedOptimizer(OptimizerEngine):
17
20
  """Profile-based rule optimization engine."""
18
21
 
19
22
  name = "Profile-based"
20
- version = "3.2.2"
23
+ version = "3.2.4"
21
24
 
22
25
  def __init__(self, codon_table_path: str | None = None) -> None:
23
26
  """
@@ -93,6 +96,17 @@ class RuleBasedOptimizer(OptimizerEngine):
93
96
  f"Unknown profile: {profile_value}. Supported profiles: {supported}"
94
97
  ) from exc
95
98
 
99
+ if (
100
+ self._codon_table_path is None
101
+ and host != "nbenthamiana"
102
+ and profile_value == "high_cai"
103
+ ):
104
+ logger.warning(
105
+ "high_cai is anchored to the N. benthamiana golden set and "
106
+ "ignores the requested host=%s; output is host-invariant by design.",
107
+ host,
108
+ )
109
+
96
110
  if self._codon_table_path is not None or host == "nbenthamiana":
97
111
  # An injected design table (benchmark source-profile runs) is
98
112
  # authoritative: it already encodes the host it was derived from.
@@ -370,7 +370,7 @@ class ReverseTranslator:
370
370
  Balanced profile: CAI first, GC balanced
371
371
 
372
372
  - Preferred codon ratio: 70%
373
- - Target GC: 55-65% (benchmark analysis 004: avg output 60.1%)
373
+ - Target GC: 55-65% (internal benchmark: avg output 60.1%)
374
374
  """
375
375
  target_gc_min = kwargs.get("target_gc_min", 55)
376
376
  target_gc_max = kwargs.get("target_gc_max", 65)
@@ -361,7 +361,7 @@ class RuleEngine:
361
361
  by the scoring band (GC_OPT_MIN/MAX, ~55-65%) and the API/DP gc_min/gc_max
362
362
  constraints. The wide 25-75% band intentionally flags only synthesis-hostile
363
363
  local windows; narrowing it toward the global optimum would raise false
364
- positives against the engine's own output distribution (analysis 004: 55-71%).
364
+ positives against the engine's own output distribution (internal benchmark: 55-71%).
365
365
 
366
366
  Args:
367
367
  seq: DNA sequence
@@ -704,7 +704,7 @@ class RuleEngine:
704
704
  Reduce CpG and TpA dinucleotide density via greedy synonymous substitution.
705
705
 
706
706
  Modes:
707
- aggressive: dinucleotide reduction only; no CAI check (Job 044 behaviour).
707
+ aggressive: dinucleotide reduction only; no CAI check.
708
708
  balanced: dinucleotide reduction first; rollback each pass if final CAI
709
709
  drops below cai_floor.
710
710
  cai_preserving: rollback each pass if CAI drops more than max_cai_drop
@@ -12,7 +12,7 @@ from typing import Any
12
12
  logger = logging.getLogger(__name__)
13
13
 
14
14
  # GC band for N. benthamiana codon-optimized sequences.
15
- # Benchmark (analysis 004, n=49): balanced profile output average GC% = 60.1%
15
+ # Benchmark (internal, n=49): balanced profile output average GC% = 60.1%
16
16
  # (range 55-71%). The genome-wide average (~42%) reflects all genes, not the
17
17
  # high-expression codon table which exhibits 3rd-position GC bias.
18
18
  # These constants define the acceptable band — sequences within [GC_OPT_MIN, GC_OPT_MAX]
@@ -24,7 +24,7 @@ def _sequence_hash(args: argparse.Namespace) -> str:
24
24
  def main() -> None:
25
25
  parser = argparse.ArgumentParser(
26
26
  prog="factorforge-validate",
27
- description="Generate a structured validation package from wet-lab results.",
27
+ description="Generate a structured public-safe wet-lab feedback package.",
28
28
  )
29
29
  parser.add_argument(
30
30
  "--construct-id",
@@ -58,12 +58,12 @@ def main() -> None:
58
58
  parser.add_argument(
59
59
  "--comparison",
60
60
  required=True,
61
- choices=["FactorForge better", "Equivalent", "Worse", "Not compared"],
61
+ choices=["Improved", "Equivalent", "Reduced", "Inconclusive", "No control", "Not reported"],
62
62
  )
63
63
  parser.add_argument(
64
64
  "--expression-level",
65
65
  default=None,
66
- choices=["High", "Medium", "Low", "Not detected", "Not measured"],
66
+ choices=["Detected", "Not detected", "Weak", "Strong", "Inconclusive", "Not reported"],
67
67
  )
68
68
  parser.add_argument("--notes", default=None)
69
69
  parser.add_argument("--institution", default=None)
@@ -0,0 +1,322 @@
1
+ """Runtime validation-check registry — single source of truth for check_id,
2
+ display metadata, and per-execution-path enforcement.
3
+
4
+ Frozen reference: validation_contract_v1.yaml, factorforge commit
5
+ 4a8be9f053797d5f54154afcbda732eaaf79f8ae (v3.2.3). This module is the
6
+ runtime source of truth; the contract file is a pinned manuscript snapshot
7
+ of what this registry's predecessor behavior was.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import Any
13
+
14
+ VALIDATION_REGISTRY_VERSION = "1.0"
15
+
16
+ VALIDATION_CHECKS: tuple[dict[str, Any], ...] = (
17
+ # --- Domain B: Configured Constraints -----------------------------------
18
+ {
19
+ "check_id": "global_gc_range",
20
+ "display_name": "Global GC% target band",
21
+ "primary_domain": "configured_constraint",
22
+ "order": 1,
23
+ "default_enabled": True,
24
+ "enforcement_per_path": {
25
+ "bare_optimizer": "metric_only",
26
+ "pipeline_default": "metric_only",
27
+ "benchmark_scoring": "component_of_multi_constraint_pass_soft",
28
+ },
29
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
30
+ "claim_boundary": (
31
+ "Configured optimization target, not a pass/fail biological-risk scanner. "
32
+ "Only gates in the benchmark scoring path."
33
+ ),
34
+ },
35
+ # --- Domain C: Advisory Sequence Scans (RuleEngine, 9 scanners) ---------
36
+ {
37
+ "check_id": "polya",
38
+ "display_name": "PolyA-like motifs",
39
+ "primary_domain": "advisory_scan",
40
+ "order": 2,
41
+ "default_enabled": True,
42
+ "enforcement_per_path": {
43
+ "bare_optimizer": "advisory_only",
44
+ "pipeline_default": "advisory_only",
45
+ "benchmark_scoring": "not_included",
46
+ },
47
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
48
+ "claim_boundary": "Advisory finding, not a guarantee of expression impact.",
49
+ },
50
+ {
51
+ "check_id": "are",
52
+ "display_name": "AU-rich elements (ARE)",
53
+ "primary_domain": "advisory_scan",
54
+ "order": 3,
55
+ "default_enabled": True,
56
+ "enforcement_per_path": {
57
+ "bare_optimizer": "advisory_only",
58
+ "pipeline_default": "advisory_only",
59
+ "benchmark_scoring": "not_included",
60
+ },
61
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
62
+ "claim_boundary": "Advisory finding.",
63
+ },
64
+ {
65
+ "check_id": "at_runs",
66
+ "display_name": "AT-rich runs",
67
+ "primary_domain": "advisory_scan",
68
+ "order": 4,
69
+ "default_enabled": True,
70
+ "enforcement_per_path": {
71
+ "bare_optimizer": "advisory_only",
72
+ "pipeline_default": "advisory_only",
73
+ "benchmark_scoring": "not_included",
74
+ },
75
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
76
+ "claim_boundary": "Advisory finding.",
77
+ },
78
+ {
79
+ "check_id": "homopolymers",
80
+ "display_name": "Homopolymer runs (synthesis risk)",
81
+ "primary_domain": "advisory_scan",
82
+ "order": 5,
83
+ "default_enabled": True,
84
+ "enforcement_per_path": {
85
+ "bare_optimizer": "advisory_only",
86
+ "pipeline_default": "advisory_only",
87
+ "benchmark_scoring": "not_included",
88
+ },
89
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
90
+ "claim_boundary": (
91
+ "Synthesis-difficulty advisory, distinct from the separate expression-stability "
92
+ "homopolymer threshold used in the unrelated/archived utils/validation.py path."
93
+ ),
94
+ },
95
+ {
96
+ "check_id": "repeats",
97
+ "display_name": "Tandem / perfect repeats",
98
+ "primary_domain": "advisory_scan",
99
+ "order": 6,
100
+ "default_enabled": True,
101
+ "enforcement_per_path": {
102
+ "bare_optimizer": "advisory_only",
103
+ "pipeline_default": "advisory_only",
104
+ "benchmark_scoring": "not_included",
105
+ },
106
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
107
+ "claim_boundary": "Advisory finding.",
108
+ },
109
+ {
110
+ "check_id": "gc_extremes",
111
+ "display_name": "Local GC extremes (sliding window)",
112
+ "primary_domain": "advisory_scan",
113
+ "order": 7,
114
+ "default_enabled": True,
115
+ "enforcement_per_path": {
116
+ "bare_optimizer": "advisory_only",
117
+ "pipeline_default": "advisory_only",
118
+ "benchmark_scoring": "not_included",
119
+ },
120
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
121
+ "claim_boundary": "Local synthesis-hostile GC extremes, NOT the global GC optimization target.",
122
+ },
123
+ {
124
+ "check_id": "splice_sites",
125
+ "display_name": "Cryptic splice-site-like motifs",
126
+ "primary_domain": "advisory_scan",
127
+ "order": 8,
128
+ "default_enabled": True,
129
+ "enforcement_per_path": {
130
+ "bare_optimizer": "advisory_only",
131
+ "pipeline_default": "advisory_only",
132
+ "benchmark_scoring": "not_included",
133
+ },
134
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
135
+ "claim_boundary": (
136
+ "Advisory pattern-match finding, low severity by default — not a validated "
137
+ "splicing prediction."
138
+ ),
139
+ },
140
+ {
141
+ "check_id": "dinucleotides",
142
+ "display_name": "CpG / TpA dinucleotide density",
143
+ "primary_domain": "advisory_scan",
144
+ "order": 9,
145
+ "default_enabled": True,
146
+ "enforcement_per_path": {
147
+ "bare_optimizer": "advisory_only",
148
+ "pipeline_default": "advisory_only",
149
+ "benchmark_scoring": "not_included",
150
+ },
151
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
152
+ "claim_boundary": "Advisory finding.",
153
+ },
154
+ {
155
+ "check_id": "rare_codon_runs",
156
+ "display_name": "Rare-codon runs",
157
+ "primary_domain": "advisory_scan",
158
+ "order": 10,
159
+ "default_enabled": True,
160
+ "enforcement_per_path": {
161
+ "bare_optimizer": "advisory_only",
162
+ "pipeline_default": "advisory_only",
163
+ "benchmark_scoring": "not_included",
164
+ },
165
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
166
+ "claim_boundary": "Advisory finding, not a validated translation-rate measurement.",
167
+ },
168
+ # --- Domain D: Assembly Review -------------------------------------------
169
+ {
170
+ "check_id": "restriction_sites",
171
+ "display_name": "Restriction Site Check (Type IIS)",
172
+ "primary_domain": "assembly_review",
173
+ "order": 11,
174
+ "default_enabled": True,
175
+ "enforcement_per_path": {
176
+ "bare_optimizer": "not_checked",
177
+ "pipeline_default": "hard_fail_raise_if_unfixable",
178
+ "benchmark_scoring": "component_of_assembly_pass_soft",
179
+ },
180
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": None}},
181
+ "claim_boundary": (
182
+ "Same biological check enforced at TWO different strengths: production pipeline "
183
+ "raises and halts; benchmark scoring records a soft boolean."
184
+ ),
185
+ },
186
+ {
187
+ "check_id": "moclo_overhang",
188
+ "display_name": "MoClo Level-0 overhang validity",
189
+ "primary_domain": "assembly_review",
190
+ "order": 12,
191
+ "default_enabled": False,
192
+ "enforcement_per_path": {
193
+ "bare_optimizer": "not_checked",
194
+ "pipeline_default": "opt_in_non_gating",
195
+ "benchmark_scoring": "not_included",
196
+ },
197
+ "presentation": {"web": {"visible": True, "default_status_when_not_executed": "NOT_RUN"}},
198
+ "claim_boundary": (
199
+ "MUST be described as a non-gating, opt-in advisory check. It is not run by "
200
+ "default, and even when run it never blocks a result — unlike restriction_sites, "
201
+ "which can halt the pipeline."
202
+ ),
203
+ },
204
+ # --- Domain A: Sequence Integrity (hard, gates pipeline via raise) ------
205
+ {
206
+ "check_id": "aa_identity",
207
+ "display_name": "Amino-acid identity",
208
+ "primary_domain": "integrity",
209
+ "order": 13,
210
+ "default_enabled": True,
211
+ "enforcement_per_path": {
212
+ "bare_optimizer": "not_checked",
213
+ "pipeline_default": "hard_fail_raise",
214
+ "benchmark_scoring": "component_of_biological_pass_soft",
215
+ },
216
+ "presentation": {"web": {"visible": False, "default_status_when_not_executed": None}},
217
+ "claim_boundary": "Hard structural validity check, not a biological-risk prediction.",
218
+ },
219
+ {
220
+ "check_id": "internal_stop",
221
+ "display_name": "Internal stop codons",
222
+ "primary_domain": "integrity",
223
+ "order": 14,
224
+ "default_enabled": True,
225
+ "enforcement_per_path": {
226
+ "bare_optimizer": "not_checked",
227
+ "pipeline_default": "hard_fail_raise_via_final_validation",
228
+ "benchmark_scoring": "component_of_biological_pass_soft",
229
+ },
230
+ "presentation": {"web": {"visible": False, "default_status_when_not_executed": None}},
231
+ "claim_boundary": "Hard structural validity check.",
232
+ },
233
+ {
234
+ "check_id": "invalid_codon",
235
+ "display_name": "Invalid / partial codons",
236
+ "primary_domain": "integrity",
237
+ "order": 15,
238
+ "default_enabled": True,
239
+ "enforcement_per_path": {
240
+ "bare_optimizer": "not_checked",
241
+ "pipeline_default": "hard_fail_raise_via_final_validation",
242
+ "benchmark_scoring": "component_of_biological_pass_soft",
243
+ },
244
+ "presentation": {"web": {"visible": False, "default_status_when_not_executed": None}},
245
+ "claim_boundary": "Hard structural validity check.",
246
+ },
247
+ {
248
+ "check_id": "frame_length",
249
+ "display_name": "Reading-frame / length consistency",
250
+ "primary_domain": "integrity",
251
+ "order": 16,
252
+ "default_enabled": True,
253
+ "enforcement_per_path": {
254
+ "bare_optimizer": "not_checked",
255
+ "pipeline_default": "implicit_validator_stage",
256
+ "benchmark_scoring": "component_of_biological_pass_soft",
257
+ },
258
+ "presentation": {"web": {"visible": False, "default_status_when_not_executed": None}},
259
+ "claim_boundary": "Hard structural validity check.",
260
+ },
261
+ {
262
+ "check_id": "custom_forbidden_motifs",
263
+ "display_name": "User-configured forbidden motifs",
264
+ "primary_domain": "configured_constraint",
265
+ "order": 17,
266
+ "default_enabled": False,
267
+ "enforcement_per_path": {
268
+ "bare_optimizer": "not_wired",
269
+ "pipeline_default": "not_wired",
270
+ "benchmark_scoring": "not_wired",
271
+ },
272
+ "presentation": {"web": {"visible": False, "default_status_when_not_executed": None}},
273
+ "claim_boundary": (
274
+ "MUST NOT be described as an active product feature. Implemented in a "
275
+ "legacy/archived code path, not connected to the current optimize()/pipeline()/"
276
+ "CLI/API surface at the pinned commit."
277
+ ),
278
+ },
279
+ )
280
+
281
+ REVIEW_CONTRACT_CHECK_IDS: tuple[str, ...] = (
282
+ "polya",
283
+ "are",
284
+ "at_runs",
285
+ "homopolymers",
286
+ "repeats",
287
+ "gc_extremes",
288
+ "splice_sites",
289
+ "dinucleotides",
290
+ "rare_codon_runs",
291
+ "restriction_sites",
292
+ "moclo_overhang",
293
+ )
294
+
295
+ PUBLIC_VALIDATION_BADGE_IDS: tuple[str, ...] = ("global_gc_range",) + REVIEW_CONTRACT_CHECK_IDS
296
+
297
+ LEGACY_VALIDATION_FIELD_MAP: dict[str, str] = {
298
+ "polya": "polya",
299
+ "gc": "global_gc_range",
300
+ # validation.moclo carries the Type IIS restriction-site result, NOT
301
+ # moclo_overhang.
302
+ "moclo": "restriction_sites",
303
+ }
304
+
305
+ _CHECKS_BY_ID: dict[str, dict[str, Any]] = {check["check_id"]: check for check in VALIDATION_CHECKS}
306
+
307
+
308
+ def get_check(check_id: str) -> dict[str, Any]:
309
+ """Return the registry entry for `check_id`.
310
+
311
+ Raises:
312
+ KeyError: If `check_id` is not in the registry.
313
+ """
314
+ return _CHECKS_BY_ID[check_id]
315
+
316
+
317
+ def public_badge_checks() -> list[dict[str, Any]]:
318
+ """Return the 12 public-badge checks, sorted by registry `order`."""
319
+ return sorted(
320
+ (check for check in VALIDATION_CHECKS if check["check_id"] in PUBLIC_VALIDATION_BADGE_IDS),
321
+ key=lambda check: check["order"],
322
+ )