Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3399c0e
docs(roadmap): archive Phase 15 standalone doc + sync stale references
cemililik May 14, 2026
c8e9446
docs(roadmap): refresh Phase 14 doc — v0.7.0 target + acceptance crit…
cemililik May 14, 2026
a01308c
feat(phase-14): multi-stage training pipeline chains (SFT → DPO → GRPO)
cemililik May 14, 2026
0d58f1b
fix: PR #53 review-response — Phase 14 blocking + significant + nitpick
cemililik May 14, 2026
b8512f0
fix: PR #53 Gemini-inline-comment review-response
cemililik May 14, 2026
b3c6a45
fix: PR #53 Codacy + SonarCloud Quality Gate
cemililik May 14, 2026
a65d3c9
refactor: PR #53 SonarCloud cognitive complexity (python:S3776)
cemililik May 14, 2026
dc2da46
fix: PR #53 review-response — 6 findings (verify-then-fix)
cemililik May 14, 2026
6a6ca60
fix(docs): mermaid syntax error in LoRA/QLoRA/DoRA decision diagram
cemililik May 14, 2026
034abd4
fix(docs): quote mermaid node labels with special characters
cemililik May 14, 2026
0ab3384
refactor: PR #53 SonarCloud follow-up — run() complexity + try/except…
cemililik May 14, 2026
cd9f416
fix: PR #53 final-review-round — 2 blocking + 1 significant + 3 nitpicks
cemililik May 14, 2026
96be857
fix: PR #53 final-review-round — SonarCloud S5754 follow-up
cemililik May 14, 2026
2c6c741
Merge pull request #53 from cemililik/feat/phase-14-pipeline-chains
cemililik May 14, 2026
d404092
docs+site: surface Phase 14 pipelines across README, manuals, marketi…
cemililik May 14, 2026
9f81265
chore: prepare v0.7.0 release
cemililik May 14, 2026
a54dc16
fix: PR #54 release-review — 7 valid findings + CI module-size unblock
cemililik May 14, 2026
277eebc
fix: sync deprecation test with v0.8.0 removal target
cemililik May 15, 2026
edafe7a
fix: PR #54 review pass 3 — 5 valid findings (markdownlint + test list)
cemililik May 15, 2026
d3ed8cd
fix: PR #54 release review — 10 of 14 findings (3 blockers + 5 HIGH +…
cemililik May 15, 2026
462999a
fix: ruff I001 + format on pipeline CLI/orchestrator tests
cemililik May 15, 2026
36200e0
fix: nightly CI + 4 review findings (3 valid + 1 skipped)
cemililik May 15, 2026
846a460
fix: pipeline pre-flight try/except bandit B112 (DEBUG log)
cemililik May 15, 2026
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
25 changes: 23 additions & 2 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,23 @@ jobs:
# breakage early. The notify-failure job dedups against existing
# 'nightly-failure' issues to bound noise (see also: testing.md
# CI gates discussion). Do NOT add `|| true` here.
#
# This list MUST mirror ``pyproject.toml`` ``[project].dependencies``
# because the next step (``pip install -e . --no-deps``) does not
# install transitive deps. When a new runtime dependency lands in
# pyproject, add it here too or the matrix job will crash in
# ``import forgelm`` before any test runs. Each entry below maps
# 1:1 to a pyproject line; the comment after each call out the
# source-of-truth.
run: |
pip install --upgrade pip
pip install torch transformers peft datasets accelerate trl pydantic pyyaml tensorboard huggingface_hub requests
# Core: torch / transformers / peft / datasets / accelerate /
# trl / pydantic / pyyaml / tensorboard / huggingface_hub /
# requests / requests-toolbelt (the last needed by
# forgelm._http for HostHeaderSSLAdapter; SSRF DNS-rebinding
# hardening, issue #14, v0.6.0).
pip install torch transformers peft datasets accelerate trl \
pydantic pyyaml tensorboard huggingface_hub requests requests-toolbelt
pip install pytest pytest-cov ruff

- name: Install ForgeLM (editable, no deps — already installed above)
Expand Down Expand Up @@ -201,6 +215,12 @@ jobs:
python-version: "3.10"

- name: Install minimum dependency versions
# This list MUST mirror the documented minimums in
# ``pyproject.toml`` ``[project].dependencies`` because the
# next step (``pip install -e . --no-deps``) does not install
# transitive deps. When a new runtime dependency lands in
# pyproject, add it here too or the job will crash in ``import
# forgelm`` before any test runs.
run: |
pip install --upgrade pip
# Install TRL first (most restrictive), let pip resolve transitive deps
Expand All @@ -210,7 +230,8 @@ jobs:
"peft==0.11.0" \
"pydantic==2.0.0" \
"pyyaml==6.0.1" \
"tensorboard==2.15.0"
"tensorboard==2.15.0" \
"requests-toolbelt==1.0.0"
pip install pytest pytest-cov

- name: Install ForgeLM
Expand Down
4 changes: 3 additions & 1 deletion .markdownlint.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
"//1": "MD051 (link-fragments-valid): docs use SPA hash-router routes like `#/data/audit` for in-app navigation; markdownlint's anchor-resolution doesn't understand SPA conventions and would flag every cross-reference.",
"//2": "MD014 (commands-show-output): shell examples in operator docs deliberately show only the command (`$ forgelm audit ...`) without sample output — output snippets rot quickly across versions and would force a doc update on every CLI banner change.",
"//3": "MD013 (line-length): bilingual (EN+TR) reference + design docs intentionally carry long lines for paragraph-style explanations, table cells, and prose with long inline links. The 80-col limit is a code-style holdover that hurts readability of documentation; the project's bilingual_parity guard already enforces structural alignment, and the rest of the prose stays human-readable at any reasonable width.",
"//4": "MD025 (single-h1): docs/usermanuals/<lang>/<section>/<page>.md pages use a YAML frontmatter `title:` AND a body `# Heading` by design — the frontmatter title feeds the sidebar nav and SPA page title, the body H1 is the visible page heading. Every page in docs/usermanuals/ follows this pattern; disabling MD025 keeps the established docs convention intact.",
"default": true,
"MD051": false,
"MD014": false,
"MD013": false
"MD013": false,
"MD025": false
}
146 changes: 144 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,148 @@ All notable changes to ForgeLM are documented here.

## [Unreleased]

_(v0.6.1 dev cycle — entries will land here as PRs merge.)_
_(v0.7.1 dev cycle — entries will land here as PRs merge.)_

## [0.7.0] — 2026-05-14

Comment thread
coderabbitai[bot] marked this conversation as resolved.
Phase 14 (Multi-Stage Pipeline Chains) closes the "operators have to write
shell wrappers to chain SFT → DPO → GRPO" gap that's lived in the issue
queue since v0.4. One YAML, one CLI invocation, one Annex IV manifest for
the whole chain — including auto-chained inputs, per-stage gates,
crash-safe resume, and 7 new pipeline-scoped audit events that join on a
single top-level `run_id`. The release also lands a critical SSRF
hardening for outbound webhook / judge / synthetic destinations
(issue [#14](https://github.com/cemililik/ForgeLM/issues/14)).
Single-stage configs reach `forgelm/trainer.py` byte-identical to
v0.6.0; the orchestrator module is never imported when no `pipeline:`
block is present.

### Added (Phase 14 — Multi-Stage Pipeline Chains)

- **`pipeline:` config block** at the root of `ForgeConfig` chains
one or more training stages (typically SFT → DPO → GRPO) into one
config-driven run. New Pydantic models `PipelineStage` and
`PipelineConfig` enforce stage-name uniqueness, `^[a-z0-9_]{1,32}$`
identifier shape, **at least 1 stage** (`min_length=1` — single-stage
ergonomics are still better served by omitting the `pipeline:`
block, but the schema accepts a 1-element pipeline so an operator
can iterate up to a multi-stage chain without re-shaping the YAML),
and explicit-`trainer_type` audit-clarity validation per stage. Section-wholesale inheritance:
`model` / `lora` / `training` / `data` / `evaluation` blocks
inherit from the root if omitted or fully replace it when set.
`distributed` / `webhook` / `compliance` / `risk_assessment` /
`monitoring` / `retention` / `synthetic` / `merge` / `auth` are
root-only and rejected per-stage with `EXIT_CONFIG_ERROR (1)`.
- **`forgelm/cli/_pipeline.py` orchestrator** drives the chain
end-to-end. Auto-chains each stage's `model.name_or_path` to the
previous stage's output, persists state atomically to
`<pipeline.output_dir>/pipeline_state.json` after every transition,
and emits 7 new audit events: `pipeline.started`,
`pipeline.stage_started`, `pipeline.stage_completed`,
`pipeline.stage_gated` (when a stage exits
`EXIT_AWAITING_APPROVAL` — review-cycle F-N-1),
`pipeline.stage_reverted`, `pipeline.force_resume` (operator-
approved stale-config override — review-cycle F-B-2), and
`pipeline.completed`. Every entry's top-level `run_id` is pinned
to the pipeline run id (review-cycle final-round F-B-1). Existing
`training.*` per-stage events from `ForgeTrainer` are preserved —
pre-existing Slack / Teams dashboards filtering on `training.failure`
keep working unchanged.
- **CLI flags** `--stage <name>` (single-stage filter for audit /
re-run), `--resume-from <name>` (stage-boundary resume),
`--force-resume` (stale-config-hash override), and `--input-model
<path>` (auto-chain escape hatch, recorded with `input_source:
cli_override` in the audit log).
- **`--dry-run` multi-stage validation** — when the config carries a
`pipeline:` block, dry-run validates every stage's merged config +
the chain-integrity assertion (stage N's auto-chained input is
under stage N-1's `output_dir`). Errors are collected before
exiting (à la `pytest --collectonly`).
- **Pipeline Annex IV manifest** — `compliance/pipeline_manifest.json`
at `<pipeline.output_dir>` indexes per-stage `training_manifest.json`
files into one verifiable chain artefact, carrying
`pipeline_run_id` + `pipeline_config_hash` (SHA-256 of the YAML
bytes) for reproducibility. `forgelm verify-annex-iv --pipeline
<run_dir>` walks the index, checks chain integrity, and asserts
every referenced per-stage manifest exists on disk.
- **Webhook notifications** — `WebhookNotifier.notify_pipeline_started`,
`notify_pipeline_completed`, and `notify_pipeline_reverted`
mirror the orchestrator's audit events; gated by the existing
`notify_on_start` / `notify_on_success` / `notify_on_failure`
config flags so operators silencing per-stage events also silence
the pipeline-level pings.
- **Bilingual operator guide** — new `docs/guides/pipeline.md` +
`docs/guides/pipeline-tr.md` (canonical "first pipeline" walkthrough,
inheritance matrix, CLI semantics, Annex IV verifier flow,
Limitations section). `config_template.yaml` gains a commented-out
`pipeline:` example block.

### Changed (Phase 14)

- **Backward compatibility preserved.** A config file without a
`pipeline:` key reaches `forgelm/trainer.py` byte-identically to
v0.6.0; the orchestrator module is never imported.
- `compliance.py` exports four new symbols: `generate_pipeline_manifest`
(called by the orchestrator after every transition),
`export_pipeline_manifest` (atomic write to
`<pipeline.output_dir>/compliance/pipeline_manifest.json`),
`verify_pipeline_manifest(manifest: dict) -> List[str]` (in-memory
structural + chain-integrity check, returns a list of human-readable
violations — empty when valid), and `verify_pipeline_manifest_at_path
(pipeline_dir: str) -> List[str]` (disk-backed wrapper used by the
`forgelm verify-annex-iv --pipeline <dir>` CLI mode). The shared
validator lives in private helper `_verify_manifest_payload` so the
in-memory and disk-bound entry points cannot drift.

### Fixed (Phase 14 review-response — PR #53)

Addresses the consolidated reviewer-pass findings (3 blocking +
4 significant + Gemini's 3 inline comments) against the initial Phase
14 merge candidate:

- **F-B-1** — `forgelm --config pipeline.yaml --dry-run` now reaches
the pipeline orchestrator's per-stage validator instead of the
legacy single-stage dry-run path; the `_dispatch.py` ordering was
inverted (no-train-mode ran before the pipeline branch).
- **F-B-2** — `--force-resume` now emits a `pipeline.force_resume`
audit event carrying `old_config_hash` + `new_config_hash` so
compliance reviewers can distinguish an operator-approved override
from a normal resume (was previously a WARNING log only —
invisible in the append-only JSONL stream).
- **F-B-3** — pipeline manifest verifier now compares every chain
stage against its **immediate** predecessor, not the most-recent
stage with an `output_model`. Pre-fix, a manifest where stage N-1
failed without saving an `output_model` could appear to chain
stage N from stage N-2, masking the broken link.
- **F-F-1 / F-G-3 (Gemini)** — auto-chain existence guard now
checks the resolved model directory itself, not its parent — used
to accept `./stage1/` even when `./stage1/final_model` was
missing.
- **F-F-2** — `--input-model ""` (empty string) is normalised to
`None` at dispatch time so it no longer slips past the truthy
guard and silently overwrites the auto-chained model path with an
empty string.
- **F-F-3** — `_validate_resume_state` now returns its refusal
through the normal `run()` flow instead of `sys.exit`-ing mid-method,
so every refusal path emits the same audit-log finalisation and
the test surface uses one uniform `assert code == EXIT_CONFIG_ERROR`
shape.
- **F-S-2 / F-N-2** — verifier surfaces stages still in `running`
status on a finalised manifest as a `chain_integrity_violation`
candidate (a tell of a crashed orchestrator). Also `_load_state_file`
catches `KeyError` / `TypeError` / `ValueError` / `AttributeError`
around `_deserialise_state` so a tampered state file produces an
actionable config error rather than a Python traceback.
- **F-N-1** — gated stages now emit a dedicated
`pipeline.stage_gated` audit event (was `pipeline.stage_completed`
with a `gate_decision=approval_pending` sub-field). Lets
dashboard / SIEM filters distinguish the gate flow on the event
name alone.
- **F-G-1 (Gemini)** — pipeline dry-run now flags `training.output_dir`
collisions across stages (two stages writing to the same dir would
silently overwrite each other's checkpoints + per-stage Annex IV
manifests). Covers both the explicit-override and inherited-from-
root collision cases.

### Security

Expand Down Expand Up @@ -1932,7 +2073,8 @@ Major release: ForgeLM goes from a basic SFT fine-tuning tool to a full-stack LL
- Basic evaluation checks (max loss, baseline comparison)
- Auto-revert on quality degradation

[Unreleased]: https://github.com/cemililik/ForgeLM/compare/v0.6.0...HEAD
[Unreleased]: https://github.com/cemililik/ForgeLM/compare/v0.7.0...HEAD
[0.7.0]: https://github.com/cemililik/ForgeLM/compare/v0.6.0...v0.7.0
[0.6.0]: https://github.com/cemililik/ForgeLM/compare/v0.5.7...v0.6.0
[0.5.7]: https://github.com/cemililik/ForgeLM/compare/v0.5.6...v0.5.7
[0.5.6]: https://github.com/cemililik/ForgeLM/compare/v0.5.5...v0.5.6
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ See the [Quick Start Guide](docs/guides/quickstart.md) for a complete walkthroug
| [Document Ingestion](docs/guides/ingestion.md) ([Türkçe](docs/guides/ingestion-tr.md)) | Raw PDF/DOCX/EPUB → SFT-ready JSONL |
| [Dataset Audit](docs/guides/data_audit.md) ([Türkçe](docs/guides/data_audit-tr.md)) | Length, language, dedup, cross-split leakage, PII |
| [Alignment (DPO/SimPO/KTO/GRPO)](docs/guides/alignment.md) | Complete post-training stack |
| [Multi-Stage Pipelines](docs/guides/pipeline.md) ([Türkçe](docs/guides/pipeline-tr.md)) | Chain SFT → DPO → GRPO in one config-driven run |
| [CI/CD Pipeline Integration](docs/guides/cicd_pipeline.md) | GitHub Actions, GitLab CI, Docker |
| [Enterprise Deployment](docs/guides/enterprise_deployment.md) | Docker, air-gapped, multi-GPU |
| [Safety & Compliance](docs/guides/safety_compliance.md) | EU AI Act, safety evaluation |
Expand Down
30 changes: 30 additions & 0 deletions config_template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,33 @@ data:
# ephemeral_artefact_retention_days: 90 # compliance bundles + audit reports
# raw_documents_retention_days: 90 # ingested raw docs (PDF/DOCX/EPUB/TXT/MD)
# enforce: "log_only" # "log_only" | "warn_on_excess" | "block_on_excess"

# Phase 14 — Multi-stage training pipeline chains (SFT → DPO → GRPO).
# Uncomment the ``pipeline:`` block below to run multiple training stages
# back-to-back; each stage's input model is auto-chained to the previous
# stage's output_dir/final_model. Stages inherit unset config blocks
# from the root (above). See docs/guides/pipeline.md.
# pipeline:
# output_dir: "./pipeline_run" # pipeline-level dir (state + manifest live here)
# stages:
# - name: sft_stage
# training:
# trainer_type: "sft"
# output_dir: "./pipeline_run/stage1_sft"
# num_train_epochs: 3
# data:
# dataset_name_or_path: "./data/sft.jsonl"
# - name: dpo_stage
# training:
# trainer_type: "dpo"
# output_dir: "./pipeline_run/stage2_dpo"
# num_train_epochs: 1
# dpo_beta: 0.1
# data:
# dataset_name_or_path: "./data/preferences.jsonl"
# - name: grpo_stage
# training:
# trainer_type: "grpo"
# output_dir: "./pipeline_run/stage3_grpo"
# data:
# dataset_name_or_path: "./data/math_prompts.jsonl"
2 changes: 1 addition & 1 deletion docs/guides/ingestion-tr.md
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ Wave 3 backlog'undadır.
> (akademik posterler, geniş oluklu regülasyon yayınları) güvenilirdir
> ama yayın-kalite iki-kolonlu makaleleri kaçırır. Histogram-tabanlı
> bimodal-mode refactor Wave 3 takipi olarak izlenmektedir (bkz.
> [`docs/roadmap/phase-15-ingestion-reliability.md`](../roadmap/phase-15-ingestion-reliability.md)
> [Faz 15 arşivi](../roadmap/completed-phases.md#phase-15-ingestion-pipeline-reliability-v060)
> Wave 3 — multi-column layout extraction).

### Markdown-bilen splitter — `--strategy markdown` (Faz 12)
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/ingestion.md
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ is on the Wave 3 backlog.
> wide-gutter regulatory publications) but misses publication-grade
> two-column papers. A histogram-based bimodal-mode refactor is tracked
> as a Wave 3 follow-up (see
> [`docs/roadmap/phase-15-ingestion-reliability.md`](../roadmap/phase-15-ingestion-reliability.md)
> [Phase 15 archive](../roadmap/completed-phases.md#phase-15-ingestion-pipeline-reliability-v060)
> Wave 3 — multi-column layout extraction).

### Markdown-aware splitter — `--strategy markdown` (Phase 12)
Expand Down
Loading
Loading