Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,8 @@ below before upgrading a pinned CI pipeline.)_
relative model directory, separate from audit, compliance, evaluation, logging, and checkpoint paths.
Reject trailing separators/dot components that would put approval staging inside the final directory.
Recheck destinations before initialization, saving, finalization, and auto-revert; preserve run records
when deleting a rejected final or staged model, including nested custom model directories.
when deleting a rejected final or staged model, including nested custom model directories (on Windows
too: the recheck reads the platform's `\` separators as the config's `/`).
- Derive current top-level module inventories from the source tree in the numerical-claims guard;
correct the agent and EN/TR architecture inventories and list the TRL compatibility and strict JSON helpers.
- Resolve ORPO and SimPO config/trainer classes from top-level TRL or its experimental ORPO/CPO modules,
Expand Down
2 changes: 1 addition & 1 deletion docs/roadmap-tr.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

> **Durum lejantı:** ✅ Yayınlandı (PyPI) · 🟡 main'e indi, publish bekliyor · 🚧 Sürüyor (iş iniyor; nesi teslim edilip nesi edilmediği için faz dosyasına bakın) · 📋 / ⏳ Planlandı

**Yayınlandı:** `v0.11.1` — "Kapalı Kalan Kapılar" — PyPI 2026-10-23. Maintainer kararıyla, `release.md`'nin bump tablosuna tek seferlik bir istisna olarak patch numarası aldı (tablo `0.12.0` derdi): **on bir kırıcı değişiklik** içerir; sabitlenmiş bir pipeline'ı yükseltmeden önce `### Breaking` bölümünü okuyun. Faz 16'nın ilk üç adımı kalite, safety, judge ve benchmark kapılarını bir ölçümü karşılaştıramadıklarında başarısız kılar — sıradan YAML'da yazılabilen bir `.nan` eşiği, reddetmesi gereken her modeli geçiriyordu — ve `cache-tasks` bir dataset hazırlanamadığında `2` ile çıkar. GDPR, silme, saklama ve PII dokümantasyonu ile altı dildeki site artık kodun yaptığını söyler; `rope_scaling` transformers 5'te yeniden çalışır ve `transformers` alt sınırı yayımlanmış iki güvenlik açığını kapatır. 4584 → 6769 test; 29 → 32 CI guard'ı. Bkz. [releases.md](roadmap/releases.md#v0111--fail-closed-2026-10-23).
**Yayınlandı:** `v0.11.1` — "Kapalı Kalan Kapılar" — PyPI 2026-10-23. Maintainer kararıyla, `release.md`'nin bump tablosuna tek seferlik bir istisna olarak patch numarası aldı (tablo `0.12.0` derdi): **on bir kırıcı değişiklik** içerir; sabitlenmiş bir pipeline'ı yükseltmeden önce `### Breaking` bölümünü okuyun. Faz 16'nın ilk üç adımı kalite, safety, judge ve benchmark kapılarını bir ölçümü karşılaştıramadıklarında başarısız kılar — sıradan YAML'da yazılabilen bir `.nan` eşiği, reddetmesi gereken her modeli geçiriyordu — ve `cache-tasks` bir dataset hazırlanamadığında `2` ile çıkar. GDPR, silme, saklama ve PII dokümantasyonu ile altı dildeki site artık kodun yaptığını söyler; `rope_scaling` transformers 5'te yeniden çalışır ve `transformers` alt sınırı yayımlanmış iki güvenlik açığını kapatır. 4584 → 6771 test; 29 → 32 CI guard'ı. Bkz. [releases.md](roadmap/releases.md#v0111--fail-closed-2026-10-23).

**`v0.8.0`** — "Model Bütünlüğü Doğrulaması ve Deprecation Temizliği" — PyPI 2026-06-16. `forgelm verify-integrity`'i ekler (eğitilmiş bir model dizinini Madde 15 `model_integrity.json` manifestine karşı yeniden hash'ler) ve config-driven merge (`merge.ties_trim_fraction` / `dare_drop_rate` / `dare_seed`) ile synthetic-sanity (`synthetic.sanity_failure_rate`) ayarlarını ekler; `distributed.strategy` / `data.mix_ratio` doğrulamasını sertleştirir; `evaluation.staging_ttl_days` (v0.5.5'te deprecated edildi) ve `--data-audit` CLI flag'inin (v0.5.0'da deprecated edildi) deprecation cadence'ini tamamlayarak ikisini de kaldırır. Bir bakım sürümü — yeni bir roadmap fazı eklemez. Bkz. [releases.md](roadmap/releases.md#v080--model-integrity-verification--deprecation-cleanup-2026-06-16).

Expand Down
2 changes: 1 addition & 1 deletion docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

> **Status legend:** ✅ Released (PyPI) · 🟡 Merged on main, publish pending · 🚧 In progress (work landing; see the phase file for what is and is not delivered) · 📋 / ⏳ Planned

**Released:** `v0.11.1` — "Fail Closed" — PyPI 2026-10-23. Numbered as a patch by maintainer decision, as a one-time exception to `release.md`'s bump table (which would make it `0.12.0`): it carries **eleven breaking changes**, so read `### Breaking` before upgrading a pinned pipeline. Phase 16's first three steps make the quality, safety, judge and benchmark gates fail when they cannot compare a measurement — a `.nan` threshold in ordinary YAML used to pass every model it was asked to reject — and `cache-tasks` exits `2` when a dataset did not stage. The GDPR, erasure, retention and PII documentation, and the site in six languages, now say what the code does; `rope_scaling` works on transformers 5 again and the `transformers` floor closes two published advisories. 4584 → 6769 tests; 29 → 32 CI guards. See [releases.md](roadmap/releases.md#v0111--fail-closed-2026-10-23).
**Released:** `v0.11.1` — "Fail Closed" — PyPI 2026-10-23. Numbered as a patch by maintainer decision, as a one-time exception to `release.md`'s bump table (which would make it `0.12.0`): it carries **eleven breaking changes**, so read `### Breaking` before upgrading a pinned pipeline. Phase 16's first three steps make the quality, safety, judge and benchmark gates fail when they cannot compare a measurement — a `.nan` threshold in ordinary YAML used to pass every model it was asked to reject — and `cache-tasks` exits `2` when a dataset did not stage. The GDPR, erasure, retention and PII documentation, and the site in six languages, now say what the code does; `rope_scaling` works on transformers 5 again and the `transformers` floor closes two published advisories. 4584 → 6771 tests; 29 → 32 CI guards. See [releases.md](roadmap/releases.md#v0111--fail-closed-2026-10-23).

**`v0.8.0`** — "Model Integrity Verification & Deprecation Cleanup" — PyPI 2026-06-16. Adds `forgelm verify-integrity` (re-hashes a trained model directory against its Article 15 `model_integrity.json` manifest) plus config-driven merge (`merge.ties_trim_fraction` / `dare_drop_rate` / `dare_seed`) and synthetic-sanity (`synthetic.sanity_failure_rate`) knobs; hardens `distributed.strategy` / `data.mix_ratio` validation; completes the deprecation cadence for `evaluation.staging_ttl_days` (deprecated v0.5.5) and the `--data-audit` CLI flag (deprecated v0.5.0), removing both. A maintenance release — no new roadmap phase. See [releases.md](roadmap/releases.md#v080--model-integrity-verification--deprecation-cleanup-2026-06-16).

Expand Down
2 changes: 1 addition & 1 deletion docs/roadmap/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ The GDPR, erasure, retention, PII-masking, GPU-cost and chat documentation was c

New issues are triaged before work starts, dependencies between issues are gated, and a contributor can claim a `good first issue` with `/assign`. The repository gained `CITATION.cff`, `GOVERNANCE.md`, `MAINTAINERS.md`, Dependabot, private security reporting and a 32nd CI guard, `tools/check_ci_failure_masking.py`.

`__api_version__` 1.1.0 → 1.2.0: `TrainResult` gained `judge_passed`, an additive field on a stable dataclass. 4584 → 6769 tests collected (124 → 133 test modules); 29 → 32 CI guards.
`__api_version__` 1.1.0 → 1.2.0: `TrainResult` gained `judge_passed`, an additive field on a stable dataclass. 4584 → 6771 tests collected (124 → 133 test modules); 29 → 32 CI guards.

### Full changelog

Expand Down
4 changes: 3 additions & 1 deletion forgelm/_artifact_paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ def _check_model_destination(output_dir: str, final_path: str, config: Any) -> N
from .config import ConfigError

try:
relative = os.path.relpath(final_path, output_dir)
# relpath answers with the platform separator, '\' on Windows, while the layout check takes the config's
# '/' form. On POSIX a backslash is part of a name; the resolve comparison below still rejects that path.
relative = os.path.relpath(final_path, output_dir).replace("\\", "/")
expected = _validate_layout(output_dir, relative, _benchmark_output_dir(config))
# relpath is lexical; do not let normalization conceal a symlink/..
# path whose actual destination differs from the checked directory.
Expand Down
29 changes: 29 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,35 @@ def test_dry_run_rejects_benchmark_overlap_before_output_creation(self, tmp_path
assert raised.value.code == 1
assert not output.exists()

def test_runtime_recheck_accepts_a_windows_relpath(self, tmp_path, minimal_config, monkeypatch):
"""On Windows ``os.path.relpath`` answers ``models\\final``; the recheck before saving must read it as the
configured ``models/final`` rather than fail the finished run (found by the v0.11.1 cross-OS matrix)."""
import forgelm._artifact_paths as artifact_paths

output = tmp_path / "output"
config = ForgeConfig.model_validate(
minimal_config(training={"output_dir": str(output), "final_model_dir": "models/final"})
)
real_relpath = os.path.relpath
monkeypatch.setattr(
artifact_paths.os.path, "relpath", lambda path, start: real_relpath(path, start).replace("/", "\\")
)
artifact_paths._check_model_destination(str(output), str(output / "models" / "final"), config)
artifact_paths._check_model_destination(str(output), str(output / "models" / "final.staging.fg-1"), config)

@pytest.mark.skipif(os.name == "nt", reason="a backslash is a separator on Windows")
def test_runtime_recheck_rejects_a_backslash_in_a_posix_name(self, tmp_path, minimal_config):
"""On POSIX ``models\\final`` is one directory name, not ``models/final``: reading the separator as ``/``
must not let it pass the recheck."""
import forgelm._artifact_paths as artifact_paths

output = tmp_path / "output"
config = ForgeConfig.model_validate(
minimal_config(training={"output_dir": str(output), "final_model_dir": "models/final"})
)
with pytest.raises(ConfigError):
artifact_paths._check_model_destination(str(output), str(output / "models\\final"), config)

@pytest.mark.parametrize(
"value",
[
Expand Down
Loading