Skip to content

feat(wave-4): Faz 22 + 23 + 26 + 30 — ISO 27001 / SOC 2 alignment + QMS bilingual + final-docs partial - #33

Merged
cemililik merged 13 commits into
developmentfrom
closure/wave4-integration
May 6, 2026
Merged

cemililik merged 13 commits into
developmentfrom
closure/wave4-integration

Conversation

@cemililik

@cemililik cemililik commented May 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Wave 4 closure-plan sweep: 4 phases consolidated on closure/wave4-integration.

  • Faz 22 — ISO 27001 / SOC 2 Type II alignment design (docs/analysis/code_reviews/iso27001-soc2-alignment-202605052315.md, ~865 lines, 93 Annex A controls + 5 SOC 2 categories mapped, 10-row Decision Log + 10-question deployer FAQ).
  • Faz 23 — ISO/SOC 2 alignment implementation: pip-audit + bandit CI/nightly; new tools/check_pip_audit.py + tools/check_bandit.py; [security] optional extra in pyproject.toml; 4 new QMS docs (encryption_at_rest, access_control, risk_treatment_plan, statement_of_applicability); deployer guide (EN+TR); 3 new reference docs (iso27001 / soc2 / supply_chain_security, EN+TR); README + CHANGELOG updates; 16 new supply-chain tests.
  • Faz 26 — QMS bilingual mirror: 6 existing QMS TR mirrors + 4 new-Faz-23 QMS TR mirrors; full rewrite of compliance_summary.md (H1 + scope blockquote + line-anchor cleanup); tools/check_anchor_resolution.py advisory-mode-default markdown link checker; 21 new tests.
  • Faz 30 partial — Tier 1 ghost-feature drift fixes (Nightly CI failure — 2026-04-26 #8/021/022/024/025); stat-block update; closure-plan sync. Remaining Faz 30 items (sample-audit user-facing doc completion, Feat/site multilang user guide #16/018/019/020, tools/check_cli_help_consistency.py, anchor-strict CI wire-up) explicitly deferred — see CHANGELOG for the deferral list.

No behaviour change. Wave 4 ships docs, supply-chain CI tooling, and 4 new QMS / 6 new doc-pair files. Zero CLI subcommand additions; zero Pydantic schema changes; no wizard / notebook integration needed.

Türkçe özet

Wave 4 dört fazlık ISO 27001 / SOC 2 uyum dalını + QMS bilingual sweep'i + Faz 30 final-doc pass'ının partial ilk turunu kapatıyor.

  • Faz 22 — Tasarım dosyası. ForgeLM'in yazılım olarak ISO sertifika alamayacağı gerçeğini açıkça belirten, ama deployer'ın kendi ISO 27001 + SOC 2 Type II denetiminde ForgeLM'in ürettiği audit-trail / change-control / data-lineage / supply-chain kanıtlarını nasıl kullanabileceğini 93 ISO Annex A kontrolü + 5 SOC 2 kategorisi üzerinde uçtan uca eşleştiren ~865 satırlık tasarım dökümanı.
  • Faz 23 — Implementation. pip-audit + bandit nightly + CI gate'leri. SBOM zaten Wave 2'de shipped (CycloneDX 1.5); Faz 23 onun üzerine determinism contract testi ekledi. 4 yeni QMS dokümanı (encryption-at-rest, access control, risk treatment plan, statement of applicability) + 1 yeni deployer cookbook + 3 yeni reference tablo. Hepsi EN+TR. Bilingual parity 9 → 13 doc çiftine yükseldi.
  • Faz 26 — QMS bilingual + compliance_summary cleanup. Wave 0 dönemindeki 6 QMS dokümanının TR mirror'ları + Faz 23'te eklenen 4 yeni QMS'in TR mirror'ları (toplam 10 yeni TR dosyası). compliance_summary.md tamamen yeniden yazıldı: H1 + scope blockquote eklendi, 11 stale forgelm/x.py#L33 line anchor'ı symbol-name reference'a geçti, "50 prompts × 3 categories" → "140 × 6" güncellendi. Yeni tools/check_anchor_resolution.py markdown anchor + relative-link guard'ı (advisory-mode default + --strict opt-in) + 21 regression test.
  • Faz 30 — Final docs partial. En kritik 5 ghost-feature drift düzeltmesi (verify-log → verify-audit, FORGELM_RESUME_TOKEN kaldırma, FORGELM_CACHE_DIR → HF_HOME, q6_k removal, chat slash command alignment) + testing.md stat block güncellemesi (48 → 67 module). Faz 30'un kalan büyük kısmı (17-row user-facing doc triplet completion, kalan ghost-feature drift, yeni CLI consistency checker tool) explicit olarak Faz 30 follow-up'a ertelendi — closure plan'da ve CHANGELOG'da listelendi.

Behaviour change YOK. Wave 4 yalnızca docs + supply-chain CI tooling + 4 yeni QMS + 6 yeni doc-pair gönderiyor. CLI subcommand eklenmedi; Pydantic schema değişmedi; wizard / notebook entegrasyonu gerekmiyor.

Test plan

  • ruff format + ruff check clean across forgelm/, tests/, tools/.
  • pytest tests/ — 1397 passed, 14 skipped (was 1374 → +23 net: 16 supply-chain + 21 anchor checker - 14 displaced).
  • python3 tools/check_bilingual_parity.py --strict → 13/13 OK (was 9/9; added 4 new pairs).
  • python3 tools/check_anchor_resolution.py (advisory) → 36 broken-link warnings unchanged from pre-Faz-26 baseline; will shrink to 0 in Faz 30 follow-up.
  • forgelm --config config_template.yaml --dry-run → green.
  • python3 tools/generate_sbom.py → emits valid CycloneDX 1.5 JSON.
  • Closure plan synced to ✅ Wave 4 (PR pending) for Faz 22/23/26/30.

Files

  • 5 new code/tool files (tools/check_pip_audit.py, tools/check_bandit.py, tools/check_anchor_resolution.py, tests/test_supply_chain_security.py, tests/test_check_anchor_resolution.py).
  • 1 new design doc (docs/analysis/code_reviews/iso27001-soc2-alignment-202605052315.md, 865 lines).
  • 4 new QMS docs (EN) + 10 new QMS TR mirrors (4 new-Faz-23 + 6 existing-QMS).
  • 1 new guide pair (deployer cookbook EN+TR).
  • 3 new reference pairs (iso27001 / soc2 / supply_chain_security EN+TR).
  • 5 modified usermanual EN+TR pairs (audit-log, human-oversight, chat, gguf-export, project-layout) for ghost-feature drift.
  • pyproject.toml, README.md, CHANGELOG.md, docs/standards/testing.md, docs/qms/sop_*.md, docs/qms/README.md, docs/reference/compliance_summary.md, tools/check_bilingual_parity.py, .github/workflows/ci.yml, .github/workflows/nightly.yml, docs/analysis/code_reviews/closure-plan-202604300906.md.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added ISO 27001 / SOC 2 Type II compliance alignment tooling and evidence artifacts.
    • Integrated supply-chain security scanning (pip-audit and bandit in CI/nightly workflows).
  • Documentation

    • Expanded compliance guides: ISO/SOC 2 deployer audit cookbook, risk treatment plans, and QMS templates.
    • Added comprehensive bilingual documentation (English/Turkish) for governance, access control, and encryption.
    • Enhanced GDPR erasure guidance with audit salt and identifier-hashing clarifications.
  • Chores

    • Automated anchor-link resolution verification across documentation.
    • Refined bilingual parity checks for new compliance and reference materials.

cemililik and others added 6 commits May 5, 2026 23:23
…lines)

Faz 22 deliverable: docs/analysis/code_reviews/iso27001-soc2-alignment-202605052315.md.
Single design dosyası; no code or behaviour change.

Scope:
- §3 Full ISO 27001:2022 Annex A control mapping — all 93 controls
  scored across A.5 organisational (37) + A.6 people (8) + A.7
  physical (14) + A.8 technological (34).  Coverage tally:
  FL (full) 11 / FL-helps 50 / OOS 32.
- §4 Full SOC 2 Trust Services Criteria mapping — Common Criteria
  CC1.x–CC9.x (Security mandatory) + Availability A1.x +
  Processing Integrity PI1.x + Confidentiality C1.x + Privacy
  P1.x–P8.x.
- §5 Gap assessment: 15 items closed in Faz 23 (pip-audit, bandit,
  4 new QMS docs, 1 deployer guide, 2 reference tables, README
  section, CHANGELOG line, SBOM determinism test).
- §6 SBOM tooling — current state (Wave 2 era CycloneDX 1.5,
  pure-stdlib, integrated with publish.yml release tag) + Faz 23
  determinism test contract.
- §7 Vulnerability scanning — pip-audit nightly + bandit CI; both
  high-severity → fail, medium → warn, low → silent.
- §8 New QMS document outlines (encryption_at_rest, access_control,
  risk_treatment_plan, statement_of_applicability) — Faz 23 ships.
- §9–§10 Existing SOP expansion plans (incident_response,
  change_management) — adds ISO control mapping rows.
- §11 Deployer-side audit cookbook outline.
- §12 CI/CD integration plan (CI + nightly + publish + planned tools).
- §13 Faz 23 work breakdown — used as the canonical task list.
- §14 Acceptance criteria (length, control coverage, work
  breakdown, cited symbols).
- §15 Out-of-scope items (PCI/HIPAA/NIST CSF mappings, SPDX SBOM,
  pen-test, bug-bounty, FedRAMP).
- §16 Decision log — 10 material decisions captured (alignment-not-
  certified wording, CycloneDX-not-SPDX choice, security-extra
  packaging, bandit scope, EN-first-TR-in-Faz-26 sequencing, etc.).
- §17 Deployer FAQ — 10 anticipated audit-team questions answered.

Important framing decisions captured in §16 Decision Log:

- **D-22-01: Customer-facing wording is "alignment", never
  "certified" / "compliant".**  Software cannot be ISO certified;
  only organisations can.  Mis-wording invites regulator pushback.
- **D-22-02: SBOM stays CycloneDX 1.5 (Wave 2 emitter).**  SPDX
  conversion is one cyclonedx-py call away if a deployer requires it.
- **D-22-03: pip-audit + bandit ship as `[security]` optional
  extra**, not core dep — keeps install lean, CI installs explicitly.
- **D-22-05: New QMS docs ship EN-only in Faz 23; TR mirrors land
  in Faz 26** with the existing-QMS bilingual sweep — avoids
  cross-wave doc-pair churn.

Cited ForgeLM symbols verified against closure/wave4-integration
HEAD b87c872.  All 93 Annex A controls + 5 SOC 2 categories table-
mapped to real ForgeLM features.

Bilingual parity 9/9 OK (this file lives under docs/analysis/ which
is not in `_PAIRS`; doesn't introduce a TR mirror obligation).

Wave 4 phase plan: Faz 22 (this commit) → Faz 23 (impl, next) →
Faz 26 (QMS TR mirrors) → Faz 30 (final docs + site).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements Faz 23 of the closure plan per the Faz 22 design
(commit 93e0ddf).  Six work areas:

Supply-chain security tooling
=============================

* `pyproject.toml [project.optional-dependencies] security` —
  new opt-in extra with pip-audit>=2.7.0 + bandit[toml]>=1.7.0.
  Operators install via `pip install forgelm[security]` to run
  the same checks ForgeLM's nightly + CI workflows enforce.

* `tools/check_pip_audit.py` (new, 116 lines) — pip-audit JSON
  severity gate.  HIGH / CRITICAL → exit 1, MEDIUM → ::warning::,
  LOW / UNKNOWN silent.  Tier-normalises MODERATE → MEDIUM
  (advisory-feed synonym).

* `tools/check_bandit.py` (new, 88 lines) — bandit JSON severity
  gate.  HIGH → exit 1, MEDIUM → ::warning::, LOW silent.

* `tests/test_supply_chain_security.py` (new, 16 tests) —
  determinism contract for tools/generate_sbom.py (two
  invocations on the same env produce content-equal SBOMs modulo
  serialNumber + timestamp); CycloneDX 1.5 schema-required field
  presence; check_pip_audit + check_bandit severity-tiering on
  synthetic JSON fixtures.

* `.github/workflows/ci.yml` — bandit step on forgelm/ in the
  validate job, after the License check.

* `.github/workflows/nightly.yml` — new `supply-chain-security`
  job running pip-audit + bandit at 03:00 UTC; uploads
  pip-audit.json + bandit.json as artefacts; added to
  notify-failure deps so a failed scan opens an issue.

QMS additions (EN-only ships; TR mirrors land in Faz 26 per
design Decision D-22-05)
===================================================

* `docs/qms/encryption_at_rest.md` (new, ~210 lines) —
  substrate-side encryption guidance for 7 ForgeLM artefact
  classes (final/staging weights, audit log + manifest, salt
  file, training corpus, configs, Annex IV bundle); threat model
  + per-substrate recommendations + verification checklist.

* `docs/qms/access_control.md` (new, ~190 lines) — operator
  identity contract (`FORGELM_OPERATOR` resolution + namespaced
  ID form); FORGELM_AUDIT_SECRET rotation; CI runner identity
  binding for GitHub Actions / GitLab / Jenkins; OS-level
  isolation patterns; approval-gate identity separation.

* `docs/qms/risk_treatment_plan.md` (new, ~210 lines) —
  pre-populated 12-row ISO 27005 risk register with rows for
  every ForgeLM-introduced risk: training-data poisoning,
  supply-chain compromise, credential leak, audit-log tampering,
  memorisation residual, safety-classifier load failure,
  auto-revert false positives, webhook SSRF, webhook target
  compromise, ReDoS, cross-tool digest mismatch, unauthorised
  deployment.

* `docs/qms/statement_of_applicability.md` (new, ~150 lines) —
  93-control SoA matrix in QMS-style format.

* `docs/qms/sop_incident_response.md` — Wave 4 §4 expansion
  (security-incident playbook): audit-chain integrity violation,
  credential leak, supply-chain CVE, webhook compromise, GDPR
  Art. 15 / 17 DSAR procedures.  ISO 27001:2022 + SOC 2 control
  mapping in header.

* `docs/qms/sop_change_management.md` — Wave 4 §4 expansion
  (CI gates as formal change-control mechanism — 11-row table
  mapping each gate to ISO controls; Article 14 approval gate
  as Change Advisory Board substitute; configuration-drift
  detection via tools/regenerate_config_doc.py;  SBOM-drift
  detection via tools/generate_sbom.py determinism contract).

Operator guide + reference docs (EN+TR)
========================================

* `docs/guides/iso_soc2_deployer_guide.md` (+ `-tr.md`, ~280
  lines each) — deployer audit cookbook with 8 common
  audit-floor questions answered with the exact ForgeLM
  artefact + grep / jq command.  6 common pitfalls section.

* `docs/reference/iso27001_control_mapping.md` (+ `-tr.md`) —
  93-control × ForgeLM evidence reference table.

* `docs/reference/soc2_trust_criteria_mapping.md` (+ `-tr.md`)
  — 5-category × ForgeLM evidence reference table.

* `docs/reference/supply_chain_security.md` (+ `-tr.md`) — SBOM
  + pip-audit + bandit overview for compliance teams.

Cross-cutting
=============

* `README.md` — new "ISO 27001 / SOC 2 Type II Alignment"
  bullet under Enterprise & MLOps with explicit "alignment, not
  certified" framing (closes Faz 22 design Decision D-22-01).

* `tools/check_bilingual_parity.py::_PAIRS` — added 4 new pairs
  (deployer guide + 3 reference docs); registry now 13 pairs
  (was 9).

* `CHANGELOG.md` — Wave 4 entry under [Unreleased] documenting
  Faz 22 + Faz 23 deliverables.

Validation
==========

- ruff format + ruff check clean.
- pytest 1360 → 1376 (+16 supply-chain tests; net delta is
  the 16 new tests in test_supply_chain_security.py).
- python3 tools/check_bilingual_parity.py --strict → 13/13 OK.
- forgelm --config config_template.yaml --dry-run → green.
- python3 tools/generate_sbom.py → emits valid CycloneDX 1.5
  JSON; tools/check_pip_audit.py + check_bandit.py error paths
  exit 1 on missing/invalid input as designed.

Closure-plan reference: Faz 23 task list at
docs/analysis/code_reviews/closure-plan-202604300906.md:782-813.
Faz 22 design rationale at
docs/analysis/code_reviews/iso27001-soc2-alignment-202605052315.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…new)

Faz 26 part 1 — bilingual mirrors land for the QMS templates.

Closure-plan reference: Faz 26 task #1 (six existing QMS docs need
TR mirrors).  Per Faz 22 design Decision D-22-05, the four Faz 23
new QMS docs (encryption_at_rest, access_control,
risk_treatment_plan, statement_of_applicability) ship EN-only in
Faz 23 and pair their TR mirrors here in Faz 26.

This commit ships:

Existing-QMS TR mirrors (6 files, closure-plan task #1):
- README-tr.md
- roles_responsibilities-tr.md
- sop_model_training-tr.md
- sop_data_management-tr.md
- sop_incident_response-tr.md (Wave 4 §4 security-incident
  playbook included)
- sop_change_management-tr.md (Wave 4 §4 CI-gates-as-change-control
  table included)

New-Faz-23 QMS TR mirrors (1 of 4 — rest in part 2):
- encryption_at_rest-tr.md

EN-side delta:
- docs/qms/README.md — table extended with the 4 Wave-4 / Faz-23
  rows (Access Control, Encryption at Rest, Risk Treatment Plan,
  Statement of Applicability) so the index reflects the actual
  doc inventory.

Faz 26 part 2 follow-ups (next commit on this branch):
- access_control-tr.md
- risk_treatment_plan-tr.md
- statement_of_applicability-tr.md
- docs/reference/compliance_summary.md cleanup (H1 + scope
  blockquote, fix broken paths, anchor refresh)
- tools/check_anchor_resolution.py + tests + CI step

Bilingual parity unaffected (QMS docs are not in
tools/check_bilingual_parity.py::_PAIRS today; QMS-pair registration
will land alongside the anchor-resolution checker so the parity tool
guards QMS drift too).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…up + anchor checker

Implements Faz 26 of the closure plan.  Three work areas:

QMS bilingual mirrors (part 2: remaining 3 new-Faz-23 TR mirrors)
=================================================================

* docs/qms/access_control-tr.md (new) — Wave 4 / Faz 23 QMS doc TR mirror.
* docs/qms/risk_treatment_plan-tr.md (new) — TR mirror.
* docs/qms/statement_of_applicability-tr.md (new) — TR mirror.

Combined with part 1 (commit 8be6dab on this branch), all 10 QMS
docs now ship EN+TR pairs.

compliance_summary.md cleanup (Faz 26 task #3 + #4)
====================================================

* docs/reference/compliance_summary.md — full rewrite:
  - Added H1 + scope blockquote.
  - Removed all 11 stale ``forgelm/x.py#L33``-style line anchors;
    replaced with module-path + symbol-name references that
    survive refactors.
  - Updated "50 prompts × 3 categories" → "140 × 6" to match the
    Wave 1 v0.5.0 safety-prompt expansion.
  - Linked from docs/qms/README.md + docs/qms/README-tr.md (See
    also section).
  - Restructured around the EU AI Act + ISO + SOC 2 trio so the
    summary stays a useful index even after Faz 30's broader
    user-facing doc sweep.

Anchor resolution checker (Faz 26 task #5)
==========================================

* tools/check_anchor_resolution.py (new) — markdown link
  resolution guard.  Walks every *.md under docs/ (excluding the
  gitignored docs/analysis/ research tree by default) and
  validates:
  - repo-relative paths resolve to existing files;
  - cross-file anchors resolve against GFM-style header slugs;
  - self-anchors (#section) resolve in the same file;
  - line-number anchors on code files (#L42) are flagged as
    brittle (drift on every refactor);
  - external URLs / mailto / SPA hash-router fragments / tel /
    javascript skipped as out-of-scope.
* tests/test_check_anchor_resolution.py (new) — 21 tests pinning
  slugify behaviour, resolution paths (relative + anchor + skip
  patterns), and CLI surface (--strict, --quiet, --exclude).

CI integration policy
=====================

The closure plan calls for a CI gate, but the live tree currently
has 36 pre-existing broken links (mostly forgelm/data_audit.py
and forgelm/cli.py references that drifted when Faz 14 + Faz 15
split those modules into packages).  Strict-mode wire-up would
turn the build red on day one.

Decision: ship the tool with **advisory mode by default**
(WARN + exit 0) and **--strict opt-in** (FAIL + exit 1).  CI
wire-up to use --strict lands as part of Faz 30 after the
broken-link cleanup completes.

Operators / contributors can still run the tool locally:

    python3 tools/check_anchor_resolution.py            # advisory
    python3 tools/check_anchor_resolution.py --strict   # CI form

Validation
==========

- ruff format + ruff check clean.
- pytest 1376 → 1397 (+21 anchor-checker tests).
- python3 tools/check_bilingual_parity.py --strict → 13/13 OK.
- forgelm --config config_template.yaml --dry-run → green.

Closure-plan reference: Faz 26 task list at
docs/analysis/code_reviews/closure-plan-202604300906.md:879-902.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…sync

Faz 30 partial implementation: Tier 1 ghost-feature drift fixes +
stat-block updates + closure-plan post-merge sync.  Full Faz 30
sweep deferred to a follow-up commit (the closure plan's Faz 30
table A is 17 user-facing-feature rows; this commit closes the
high-impact subset and documents the deferred work.)

Tier 1 ghost-feature drift fixes (closure-plan task O subset)
=============================================================

* GH-8 `verify-log` → `verify-audit` rename in
  `usermanuals/{en,tr}/compliance/audit-log.md` (Phase 6 shipped
  as `verify-audit`; the doc still cited the pre-rename name).

* GH-21 `forgelm chat` slash commands aligned with parser
  (`forgelm chat --help` shows only `/reset`, `/save`,
  `/temperature`, `/system`, `/exit`):
  - removed `/load`, `/top_p`, `/max_tokens`, `/safety on|off`
  - `/quit` → `/exit`
  - "Saving and replaying" section reframed: `/save` is real;
    replay tooling is roadmapped for v0.6.0+ Pro CLI.
  EN+TR mirror.

* GH-22 `q6_k` quant level removed from
  `usermanuals/{en,tr}/deployment/gguf-export.md`.  The parser at
  `forgelm/cli/_parser.py:75-76` only supports
  `q2_k|q3_k_m|q4_k_m|q5_k_m|q8_0|f16`; `q6_k` was a fictional
  intermediate.  Added the `f16` (lossless) row that was missing.

* GH-24 `FORGELM_RESUME_TOKEN` env var removed from
  `usermanuals/{en,tr}/compliance/human-oversight.md`.  The "API
  self-service automation" block citing this env var was pure
  fiction (no resume endpoint, no JWT-signed approval webhook
  callback).  Replaced with the canonical CLI subcommand flow
  (`forgelm approve` / `reject` + `forgelm approvals --pending`)
  that actually exists, plus a v0.6.0+ Pro CLI roadmap callout
  for self-service automation.

* GH-25 `FORGELM_CACHE_DIR` env var removed from
  `usermanuals/{en,tr}/getting-started/project-layout.md`.
  ForgeLM does not introduce its own cache-dir override; the
  canonical pattern is `HF_HOME` (matches Phase 35 `cache-models`
  + `cache-tasks` subcommand expectations).

Stat-block updates (closure-plan task E)
========================================

* `docs/standards/testing.md` — "Current structure (48 test
  modules)" → "Current structure (67 test modules, one per feature
  area; ~1410 tests)".  Reflects the post-Wave-3 + Wave-4 test-
  suite size.

Closure-plan post-merge sync
============================

* `docs/analysis/code_reviews/closure-plan-202604300906.md`:
  - Faz 22, 23, 26, 30 status changed from `⏳ PENDING` to
    `✅ Wave 4 (PR pending)`.
  - Status legend gained a Wave 4 entry.
  - Added Wave 4 kapanış özeti naming the deliverables: 1 design
    doc (~865 lines), 4 new QMS docs, 6 existing-QMS TR mirrors,
    4 new-QMS TR mirrors, 1 new guide (deployer cookbook EN+TR),
    3 new reference docs (iso27001 / soc2 / supply_chain_security
    EN+TR), 3 new tools (check_pip_audit, check_bandit,
    check_anchor_resolution), `[security]` optional extra,
    nightly supply-chain-security job.
  - "Kalan iş" reframed: only Faz 33 release remains (post-wave),
    plus optional Faz 30 follow-up for the deferred items.

Deferred to Faz 30 follow-up
============================

The closure plan's Faz 30 task A is a 17-row feature × doc-triplet
table.  Many rows are already covered from Wave 1-3; the rest is a
focused doc-completion sweep that benefits from being its own
commit.  Specifically deferred:

- GH-16 `--export-bundle` → `--compliance-export` rename in QMS
  SOPs (CLI flag is correct in code; only doc references drift).
- GH-18 `kserve` / `triton` deploy targets removal from
  reference/cli.md.
- GH-19 chat reference table cleanup in reference/cli.md.
- GH-20 ingest reference table cleanup in reference/cli.md.
- Sample-audit user-facing doc triplet completion (closure-plan
  Faz 30 task A's 17-row table — verify each feature's
  EN+TR guide + reference + usermanual triplet).
- `tools/check_cli_help_consistency.py` addition + CI wire-up
  (closure-plan Faz 30 task J).
- Full-suite `tools/check_anchor_resolution.py --strict` CI
  wire-up (currently advisory mode; 36 broken links in tree
  pre-Faz 26 — sweep + wire-up together).

Validation
==========

- ruff format + ruff check clean.
- pytest 1397 passed, 14 skipped (no new tests; Faz 30 is doc-only).
- python3 tools/check_bilingual_parity.py --strict → 13/13 OK.
- python3 tools/check_anchor_resolution.py (advisory) → 36
  broken-link warnings unchanged from pre-Faz-26 baseline; will
  shrink to 0 in Faz 30 follow-up.
- forgelm --config config_template.yaml --dry-run → green.

Closure-plan reference: Faz 30 task list at
docs/analysis/code_reviews/closure-plan-202604300906.md:1203-1383.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown
ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @cemililik, your pull request is larger than the review limit of 150000 diff characters

@coderabbitai

coderabbitai Bot commented May 5, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5e624cbe-f282-4a03-bb77-31aa6f526ac9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch closure/wave4-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codacy-production

codacy-production Bot commented May 5, 2026 •

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 100 minor

Alerts:
⚠ 100 issues (≤ 0 issues of at least minor severity)

Results:
100 new issues

Category Results
CodeStyle 100 minor

View in Codacy

🟢 Metrics 220 complexity · 4 duplication

Metric Results
Complexity 220
Duplication 4

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Frozen at 8f69cf1 / PR #33.  Same 4-agent split as Wave 3
(code-correctness / privacy-security / standards-compliance /
test-rigour) per the established review cadence.

Critical framing rules baked into the prompt:

- D-22-01 enforcement: any "compliant" / "certified" wording
  found in the diff is a CRITICAL finding (alignment-vs-
  certified is the single most-impactful regression a reviewer
  can catch on this PR).
- D-22-02 enforcement: SBOM stays CycloneDX 1.5; any SPDX claim
  is a finding.
- Salt + HMAC chain are tamper-evidence, not non-repudiation —
  reject PKI-flavoured claims.
- Wave 4 explicitly defers some Faz 30 items (GH-16/018/019/020
  cli.md cleanup, sample-audit user-facing doc triplet, new
  check_cli_help_consistency tool, full-suite anchor-strict CI
  wire-up); reviewers should NOT flag those as Wave 4 omissions.

Severity bar matches Wave 3 calibration; deliverable structure
matches Wave 3 (one report per agent, saved as wave4-<agent>.md
under docs/analysis/code_reviews/).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements the ISO 27001 / SOC 2 Type II alignment for ForgeLM, including new security tooling (pip-audit, bandit), QMS documentation, and compliance guides. The review identified a missing registration of new QMS documents in the bilingual parity check and a syntax error in a jq command used for auditing segregation of duties. Both issues have been addressed with actionable feedback.

Comment on lines 66 to 79
("docs/guides/data_audit.md", "docs/guides/data_audit-tr.md"),
("docs/guides/gdpr_erasure.md", "docs/guides/gdpr_erasure-tr.md"),
("docs/guides/ingestion.md", "docs/guides/ingestion-tr.md"),
("docs/guides/iso_soc2_deployer_guide.md", "docs/guides/iso_soc2_deployer_guide-tr.md"),
# docs/reference/
("docs/reference/architecture.md", "docs/reference/architecture-tr.md"),
("docs/reference/audit_event_catalog.md", "docs/reference/audit_event_catalog-tr.md"),
("docs/reference/configuration.md", "docs/reference/configuration-tr.md"),
("docs/reference/data_preparation.md", "docs/reference/data_preparation-tr.md"),
("docs/reference/distributed_training.md", "docs/reference/distributed_training-tr.md"),
("docs/reference/iso27001_control_mapping.md", "docs/reference/iso27001_control_mapping-tr.md"),
("docs/reference/soc2_trust_criteria_mapping.md", "docs/reference/soc2_trust_criteria_mapping-tr.md"),
("docs/reference/supply_chain_security.md", "docs/reference/supply_chain_security-tr.md"),
("docs/reference/usage.md", "docs/reference/usage-tr.md"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This pull request introduces 10 new QMS documents with their Turkish translations, but they don't seem to be added to the _PAIRS tuple for the bilingual parity check. This means their structural parity won't be enforced by the CI.

The PR description mentions:

  • 6 existing QMS TR mirrors
  • 4 new-Faz-23 QMS TR mirrors

Please add these 10 new QMS document pairs to the _PAIRS tuple to ensure they are covered by the parity check.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absorbed in ffceaf7 — _PAIRS now registers all 10 QMS pairs (4 Faz-23 + 6 existing). python3 tools/check_bilingual_parity.py --strict now reports 23/23 OK. docs/standards/localization.md was also flipped to allow QMS bilingual mirrors (the standard had said "No (yet)" before this wave reversed the policy).

Comment thread docs/qms/access_control.md Outdated
Comment on lines +179 to +189
# Find approvals where trainer == approver (segregation violation)
forgelm verify-audit --output-dir ./outputs --json | jq '
.events[] |
select(.event == "human_approval.granted") |
.matching_training_event = (
[.|.run_id == .. .run_id and .event == "training.started"] | first
) |
select(.operator == .matching_training_event.operator) |
.'
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This jq query appears to be syntactically incorrect and will not work as intended. The expression [.|.run_id == .. .run_id ...] is not valid jq syntax.

To find approvals where the trainer is the same as the approver, you could use jq variables to store the context. Here is a corrected version of the command that should achieve your goal:

Suggested change
# Find approvals where trainer == approver (segregation violation)
forgelm verify-audit --output-dir ./outputs --json | jq '
.events[] |
select(.event == "human_approval.granted") |
.matching_training_event = (
[.|.run_id == .. .run_id and .event == "training.started"] | first
) |
select(.operator == .matching_training_event.operator) |
.'
```
forgelm verify-audit --output-dir ./outputs --json | jq '
.events as $all_events |
.events[] |
select(.event == "human_approval.granted") |
. as $approval_event |
.matching_training_event = (
$all_events[] | select(.run_id == $approval_event.run_id and .event == "training.started") | first
) |
select(.matching_training_event and .operator == .matching_training_event.operator)
'

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absorbed in ffceaf7 — the entire jq snippet was replaced with a --slurpfile-based two-pass that actually parses. Side-effect: the same commit also fixed the broken forgelm verify-audit --output-dir ./outputs --json invocation (those flags do not exist on the parser; positional log_path + --require-hmac is the shipping form).

cemililik and others added 4 commits May 6, 2026 01:19
Convergent absorption of code-correctness, privacy-security, standards,
and test-rigor reviews of `closure/wave4-integration` (HEAD 9a1738a),
plus PR #33 inline comments (Gemini) and Sonar findings on the same
PR. Wave 3 cadence: real bugs are fixed in the same round even when
out of strict scope.

HIGH (5)
- Design doc §3 coverage tally was off-by-2 (claimed FL 11 / FL-helps
  50 / OOS 32; row-by-row recount is 11 / 48 / 34). Corrected in
  design doc, FAQ Q1 ("~61" → 59 = 11 + 48), SoA EN+TR per-theme
  breakdown, ISO 27001 reference EN+TR header tally, and CHANGELOG.
- Design doc cited non-existent `compute_artefact_sha256`; the real
  symbol is `generate_model_integrity` (delegates to `_hash_file` in
  `forgelm/compliance.py:466-499`).
- Deployer guide cookbook (EN+TR) + access_control §6 (EN+TR) cited
  `forgelm verify-audit --output-dir ./outputs --json` — neither flag
  exists on the parser. Replaced with the shipping
  `forgelm verify-audit ./outputs/audit_log.jsonl --require-hmac` form
  + a `--slurpfile`-based jq pipeline that actually parses.
- access_control §3.4 (EN+TR) + RTP R-04 (EN+TR) misdescribed the HMAC
  chain key as the env secret XOR'd with `_resolve_salt`'s
  per-output-dir salt. The real derivation is
  `SHA-256(FORGELM_AUDIT_SECRET ‖ run_id)` per
  `forgelm/compliance.py:104-114`; the per-output-dir salt is a
  distinct concern that salts purge / reverse-pii identifier hashes
  and does NOT participate in chain-key derivation. Mirrored in the
  ISO A.8.24 row of the design doc + reference (EN+TR).
- access_control §3.4 (EN+TR) + deployer guide (EN+TR) advertised
  quarterly `FORGELM_AUDIT_SECRET` rotation. Rotation must occur
  *between* output-dir lifecycles — every entry's HMAC is bound to
  the secret live at emit time and `forgelm verify-audit
  --require-hmac` cannot verify a chain mixing secrets. Reframed to
  per-output-dir-lifecycle cadence with the procedure spelled out.

MEDIUM (8)
- `tools/check_pip_audit.py::_vuln_severity` was treating the OSV
  scoring-system label (`CVSS_V3`) as if it were a tier name, and
  missed the 2.6.x `aliases[].severity[]` shape its docstring
  promised. Added explicit score-type label set, CVSS-score → tier
  derivation per FIRST.org cut-points, 2.6.x aliases fallback, and
  a single-line summary annotation for UNKNOWN findings (was silent).
- `tools/check_bandit.py` was masking malformed `"results": null`
  reports via `or []`. Now distinguishes missing-key / null-value /
  list shape explicitly + emits a single summary annotation when
  bandit's documented UNDEFINED tier appears.
- `incident_response.md` lead-in (EN+TR) said "§6 covers" the
  security-incident playbook; the playbook is in §4. Fixed.
- `incident_response.md` (EN+TR) §4.1 step 3 + §4.4 step 2 cited
  non-existent `--until-line N` / `--replay-since <ts>` flags.
  Rewritten to use shipping primitives (positional log_path, manual
  `head -n N` bisect, jq filter-and-correlate).
- `risk_treatment_plan.md` (EN+TR) R-05 residual rating was Med×Med
  presented as a passive reduction. ForgeLM contributes a detection
  signal only; deployer accepts the High×Med residual via the §5
  acceptance log. Reframed honestly.
- `encryption_at_rest.md` (EN+TR) §3 had algorithm-break wholly
  out-of-scope. Promoted to "Long-horizon (>5 years) — partial
  coverage" per ISO A.8.24 algorithm-agility expectation; cites
  NIST SP 800-131A.
- `supply_chain_security.md` (EN+TR) cited ISO A.8.30 (outsourced
  development) as a control mapping for transitive PyPI deps. A.8.30
  addresses outsourced *system development*, not consuming
  open-source packages; A.5.21 + A.8.8 already cover the
  supply-chain story honestly. A.8.30 row dropped.
- `soc2_trust_criteria_mapping.md` (EN+TR) + design doc CC2.3 row
  conflated artefact production with communication channel. CC2.3
  evidence is the deployer's regulator-contact process; ForgeLM
  produces the Annex IV bundle + `compliance_report.json` artefacts.

Tooling + tests
- `tools/check_anchor_resolution.py`: extracted helpers
  `_normalise_heading_body`, `_resolve_pure_anchor`, `_locate_target`,
  `_resolve_anchor_against_target`, `_build_argparser`,
  `_resolve_excludes`, `_collect_broken`, `_report_broken` to land
  `_resolve_link` and `main` below Sonar's cognitive-complexity 15
  ceiling (was 17 each). Replaced the `(.+?)\s*#*\s*$` ATX-heading
  regex with `(.+)` + procedural trailing-whitespace + closing-hash
  trim to clear the python:S5852 ReDoS hotspot at line 57.
- `tools/check_bandit.py::main`: extracted `_load_report`,
  `_extract_results`, `_classify_issues` to land below the
  cognitive-complexity ceiling (was 17).
- `tools/check_bilingual_parity.py::_PAIRS`: registered the 10 QMS
  pairs (4 Faz-23 docs + 6 existing QMS files) so EN/TR drift is now
  CI-gated. Strict mode reports 23/23 OK.
- `docs/standards/localization.md` `docs/qms/*.md` row flipped from
  "No" to "Yes" to reflect the bilingual sweep.
- `tests/test_supply_chain_security.py`: added bandit UNDEFINED +
  null-results + missing-key tests, pip-audit UNKNOWN summary +
  CVSS-score derivation + 2.6.x aliases nested + list-form tier
  tests, SBOM serialNumber uniqueness test.
- `tests/test_check_anchor_resolution.py`: added apostrophe + backtick
  slug edge tests, ATX closing-hash normalisation test, tel: +
  javascript: skip-pattern fixtures, image-link parity tests, strict
  mode broken-anchor exit-1 test.

Other
- `forgelm/cli/subcommands/_doctor.py`: `FORGELM_RESUME_TOKEN`
  inline comment reworded from "Phase 13 future" to "reserved name —
  masked defensively even if unused today".
- `ghost-features-analysis-20260502.md` line 604: claim that
  `grep -rn "FORGELM_RESUME_TOKEN" forgelm/` returns no results
  corrected — there is one defensive secret-mask entry.
- `closure-plan-202604300906.md` Wave 4 summary: 6 → 10 yeni QMS
  TR mirror (4 Faz-23 pair + 6 mevcut QMS dosyası); test count
  1397 → 1411.

Validation
- `ruff format .` / `ruff check .` — clean.
- `python3 tools/check_bilingual_parity.py --strict` — 23/23 OK.
- `python3 -m pytest --no-cov -q` — 1414 passed, 14 skipped.
- `forgelm --config config_template.yaml --dry-run` — green.
- `python3 tools/check_anchor_resolution.py` (advisory) — 36
  pre-existing broken (Faz 30 follow-up scope per closure-plan
  §10 acceptance criteria).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…5852 hotspot

The first absorption round (ffceaf7) replaced ``(.+?)\s*#*\s*$`` with
``^(#{1,6}) +(.+)$`` to remove three adjacent variable-length matchers,
but Sonar's python:S5852 heuristic still flagged the new pattern: two
sequential ``+`` quantifiers (`` +`` then ``(.+)``) trip the rule even
though the leading ``{1,6}`` bound makes catastrophic backtracking
impossible.

Cleanest fix: drop the regex entirely. ATX heading parsing is now a
single linear-pass procedural function (``_parse_atx_heading``) — count
leading hashes (≤6), require a space, take the rest as body, hand off
to the existing ``_normalise_heading_body`` for closing-hash trim.
Worst-case runtime is linear in line length and there is no regex
surface left for the heuristic to misclassify.

Behaviour-equivalent: the 29 anchor-checker tests pass unchanged and
the advisory baseline stays at 36 broken links.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Companion to wave4-review-prompt.md. Targets the two absorption
commits ffceaf7 + 105285f that landed on PR #33 after the original
4-agent review completed. The prompt asks two complementary
questions:

1. Did the absorptions correctly fix the original findings (every
   CRITICAL / HIGH from the 4 prior reports + the 2 inline PR
   comments + 4 SonarCloud items)?
2. Did the absorptions themselves introduce defects?

8 scrutiny surfaces, ~50 enumerated F-W4FU checks:

- §A: §3 tally arithmetic (per-theme recount, FAQ Q1).
- §B: HMAC chain key reframing — `SHA-256(secret ‖ run_id)` vs the
  pre-absorption XOR-with-salt claim, propagated to access_control
  / RTP / ISO A.8.24 / design doc.
- §C: CLI cookbook fixes (verify-audit positional log_path; jq
  --slurpfile pipeline correctness end-to-end).
- §D: check_pip_audit CVSS_V3 type label + score-to-tier derivation
  (CVSSv2 cut-point caveat) + 2.6.x aliases nested fallback +
  UNKNOWN summary annotation.
- §E: check_bandit null-results / missing-key disambiguation +
  UNDEFINED summary annotation.
- §F: check_anchor_resolution _HEADING_RE elimination — procedural
  ATX parser corner cases (CommonMark §4.2 conformance, indented
  headings, closing-hash decoration) + helper-extraction behaviour
  invariance + Sonar S5852 hotspot resolution verification.
- §G: vacuous-test scan of the 17 new tests.
- §H: cross-cutting (doc drift, end-to-end verify-audit smoke,
  closure-plan honesty, ruff-format equivalence, backwards
  compatibility, gemini-code-assist inline reply audit).

.gitignore re-allows the new file alongside the prior planning
artefacts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Convergent absorption of the 4 wave4-followup review reports
(code-correctness, privacy-security, standards, test-rigor) on
absorption commits ffceaf7 + 105285f. Wave 3 cadence: real bugs
fixed in the same round, even out-of-strict-scope.

HIGH (5)
- F-W4FU-PS-01 / ST-01 (1/2) — `compliance_summary.md:90-92` still
  said "FORGELM_AUDIT_SECRET XOR'd against the per-output-dir salt".
  The Wave 4 round-1 absorption swept 4 of 6 HMAC-misdescription
  sites; reference summary (the customer-facing Article-12 contract
  surface) was missed. Reframed to cite `forgelm/compliance.py:104-114`
  with the per-output-dir-salt-is-distinct-primitive callout.
- F-W4FU-PS-03 / ST-01 (2/2) — `statement_of_applicability.md:132`
  + `-tr.md:133` A.8.24 row still said "per-output-dir salt + env
  XOR" without disambiguating chain key from identifier hash. SoA
  is the auditor-signed document; rewritten to mirror the corrected
  iso27001_control_mapping cell.
- F-W4FU-01 / PS-02 — `access_control.md` §6 segregation-of-duties
  jq cookbook (EN+TR) was non-runnable (`jq --slurpfile` rejects
  TSV; replaced flag-mismatch with format-mismatch) AND wrote
  operator identifiers to a world-readable `/tmp/trainers.tsv`
  (privacy leak on multi-tenant hosts, since §3.2 invites email
  identifiers). Replaced with a single-pass `jq -rs` form that
  joins trainers + approvals in-memory. End-to-end verified
  against a synthetic 4-entry chain: emits `r1\talice` (the
  segregation violation) at exit 0.
- F-W4FU-TR-01 — `test_aliases_nested_severity_2_6_shape` pinned a
  fictional pip-audit JSON shape. Test-rigor agent's wheel
  inspection of pip-audit 2.6.0–2.9.0 confirmed `aliases` is
  `set[str]` of identifier strings; no version emits a nested
  `severity` field. Dropped the entire CVSS-from-score derivation
  + aliases nested fallback + 4 fictional fixtures. `_vuln_severity`
  now returns UNKNOWN for every real pip-audit vuln; the UNKNOWN
  summary annotation is the operator-triage path. Kept a
  `test_hand_crafted_top_level_severity_string_honoured` to pin
  the documented escape hatch for non-pip-audit scanners that emit
  a top-level `severity: "HIGH"`.
- F-W4FU-TR-02 — `test_undefined_severity_summary_warning` would
  pass under the regression scenario the original review explicitly
  called out (per-finding `[UNDEFINED/LOW]` warning instead of
  summary). Tightened: pin the summary phrasing exactly + assert
  artefact path appears + negative assertion that `[UNDEFINED/LOW]`
  per-finding format MUST NOT appear.

MEDIUM (4)
- F-W4FU-PS-04 — CHANGELOG silent on rotation guidance reframing.
  Added Wave 4 "Migration notes" subsection covering quarterly →
  output-dir-lifecycle reframing with the failure-mode explanation.
- F-W4FU-PS-05 (+ cc-04) — pip-audit/bandit UNKNOWN+UNDEFINED
  summary annotations now include the artefact path so an SRE on
  the GitHub Actions run summary can grep without walking the
  workflow YAML.
- F-W4FU-PS-06 — §8 "lifecycle boundary" verification checklist
  bullet was a term of art; reframed to give the auditor a concrete
  signal (KMS rotation event must pair with a fresh
  `audit_log.manifest.json` genesis pin in the same timestamp
  window). Mirror in TR.
- F-W4FU-TR-05 (+ cc-07) — `_parse_atx_heading` registered empty
  slug for all-hash headings (`## ##` → "" body after closing-hash
  strip). Added post-`_normalise_heading_body` empty guard +
  pinned in `test_atx_all_hashes_rejected`.

LOW / NIT (4)
- F-W4FU-cc-05 — CHANGELOG missing bandit `null`-results behaviour
  change line. Added under Migration notes subsection.
- F-W4FU-PS-07 — `gdpr_erasure.md` (EN+TR) line 41 mentions
  identifier-salt XOR; added bridging sentence pointing readers to
  `access_control.md` §3.4 + `forgelm/compliance.py:104-114` so the
  XOR-vs-not-XOR asymmetry across docs is explained.
- F-W4FU-TR-06 — `test_strict_mode_exits_one_on_broken_anchor`
  did not pin the broken-link reason. Tightened to assert
  `"anchor"` substring so a regression that printed the wrong
  reason class would fail.
- F-W4FU-TR-09 — Pinned `_normalise_heading_body("foo###") == "foo"`
  to lock current off-spec-but-defensible behaviour against silent
  drift.
- F-W4FU-ST-NIT-01 — `iso27001_control_mapping.md:125` (+ TR) A.8.24
  row now cites `forgelm/compliance.py:104-114` for symmetry with
  the other 3 reframed locations.
- F-W4FU-TR-08 — `_parse_atx_heading` docstring now explicitly notes
  the indented-heading CommonMark §4.2 divergence (intentional;
  pre-rewrite regex was column-anchored too).

Validation
- `ruff format .` / `ruff check .` — clean.
- `python3 tools/check_bilingual_parity.py --strict` — 23/23 OK.
- `python3 -m pytest --no-cov -q` — 1413 passed, 14 skipped.
  (Net -1 from round 1: dropped 4 fictional pip-audit tests, added
  3 — 1 hand-crafted-severity, 1 ATX-empty-rejected, 1 ATX-no-space
  closing-hash, plus the UNDEFINED tightening doesn't add a test.)
- Cookbook end-to-end: `jq -rs` snippet from `access_control.md` §6
  emits `r1\talice` against a 4-entry synthetic chain with one
  segregation violation; exit 0. Fix verified live.
- `forgelm verify-audit --help` confirms the cookbook syntax:
  positional `log_path` + `--require-hmac` + `--hmac-secret-env`;
  no `--output-dir`, no `--json`.
- `python3 tools/check_anchor_resolution.py` (advisory) — 36
  pre-existing baseline (Faz 30 follow-up scope).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/standards/testing.md (1)

8-37: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Directory tree is stale relative to the updated module count.

The header now claims 67 test modules but the "Current structure" tree still lists only 23 test_*.py files. The new modules added in this wave (e.g., test_supply_chain_security.py, test_check_anchor_resolution.py) are not reflected. A contributor counting tree entries will get 23, not 67, and the discrepancy undermines the doc as a reference.

The tree should either enumerate the missing modules or note explicitly that it shows a representative subset.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/standards/testing.md` around lines 8 - 37, The header "Current structure
(67 test modules, one per feature area; ~1410 tests)" is inconsistent with the
listed tree block; update docs/standards/testing.md so the "Current structure"
either enumerates the missing test files (e.g., add entries like
test_supply_chain_security.py, test_check_anchor_resolution.py and any other new
test_*.py modules) to match the stated count, or change the heading and add a
clear note that the shown tree is a representative subset rather than a full
listing; locate the header string "Current structure (67 test modules, one per
feature area; ~1410 tests)" and the following code block to make this change.
🟡 Minor comments (13)
docs/usermanuals/en/deployment/gguf-export.md-28-29 (1)

28-29: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Line 118 uses incorrect flag --quant fp16 instead of --quant f16.

The quantisation table (line 28) correctly shows f16 at 13 GB, but the "Direct conversion" example (line 118) incorrectly uses --quant fp16. The codebase only recognizes f16; using fp16 will fail. Additionally, the section states ~14 GB for a 7B model versus 13 GB in the table—a minor variance, but both should reflect the same lossless format.

Change line 118 from --quant fp16 to --quant f16 for consistency with the table and correctness against the codebase.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/usermanuals/en/deployment/gguf-export.md` around lines 28 - 29, Replace
the incorrect quant flag used in the "Direct conversion" example by changing the
flag value `--quant fp16` to the recognized `--quant f16` (ensure the example
command uses `--quant f16`), and update the size mention to match the
quantisation table's lossless `f16` entry (change "~14 GB" to "13 GB") so the
example and the table are consistent; look for the example command and size text
that reference `--quant fp16` and "~14 GB" and edit them accordingly.
docs/analysis/code_reviews/ghost-features-analysis-20260502.md-604-604 (1)

604-604: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Internal contradiction with GH-1 “no _doctor.py” claim

Line 604 now says _doctor.py exists, but Line 110 still states there is no _doctor.py. Please reconcile these statements (or explicitly time-scope Line 604) so the report remains self-consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/analysis/code_reviews/ghost-features-analysis-20260502.md` at line 604,
The document has contradictory statements about _doctor.py (Line 604 shows
forgelm/cli/subcommands/_doctor.py exists referencing FORGELM_RESUME_TOKEN,
while Line 110 claims no _doctor.py); update the GH-001 claim or the Line 604
wording so they match: either change the GH-001 assertion (the _doctor.py file
exists but only contains a defensive secret-mask entry for FORGELM_RESUME_TOKEN
and does not read the env var) or add a clear time-scope/clarifier at Line 604
stating this is a defensive mask-only reference to avoid future accidental
exposure; ensure you reference the file name forgelm/cli/subcommands/_doctor.py
and the symbol FORGELM_RESUME_TOKEN in the revised sentence so the reader sees
they refer to the same artifact.
docs/usermanuals/tr/compliance/human-oversight.md-83-83 (1)

83-83: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Unify audit event naming across this document.

This line introduces dotted event names (human_approval.granted / human_approval.rejected) while other sections in the same file still use underscore variants (e.g., human_approval_granted, human_approval_request). Please standardize to one canonical event schema to avoid operator confusion and mismatched grep/automation queries in runbooks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/usermanuals/tr/compliance/human-oversight.md` at line 83, The document
mixes dotted and underscored audit event names (e.g., human_approval.granted /
human_approval.rejected vs human_approval_granted and human_approval_request);
pick a single canonical schema (either dotted or underscored), then update all
occurrences to that form—including the examples in this sentence (replace
human_approval.granted / human_approval.rejected to the chosen form) and any
other mentions of human_approval_granted or human_approval_request to maintain
consistency across the file and ensure grep/automation queries work reliably.
docs/guides/iso_soc2_deployer_guide.md-262-265 (1)

262-265: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Overstated verifier contract around manifest sidecar (Line 263).

This says forgelm verify-audit requires audit_log.manifest.json, but the verifier checks the sidecar when present rather than hard-requiring it. Please soften wording to “required for truncate-and-resume detection/higher assurance” to match runtime behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/guides/iso_soc2_deployer_guide.md` around lines 262 - 265, The wording
overstates the verifier's requirement: change the sentence that says "`forgelm
verify-audit` requires `audit_log.manifest.json`" to a softer statement that the
manifest sidecar (`audit_log.manifest.json`) is not strictly required but is
necessary for truncate-and-resume detection and provides higher assurance;
update the text around "Back BOTH up." to reflect that the verifier will check
the sidecar when present and that backing up both files is recommended for full
tamper-detection coverage.
docs/qms/statement_of_applicability.md-154-158 (1)

154-158: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Internal section reference appears wrong (Line 154).

The text says “Row-by-row recount of §3.1–§3.4,” but the control tables are in §2.1–§2.4. Please correct the section pointer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/qms/statement_of_applicability.md` around lines 154 - 158, Replace the
incorrect internal section reference "Row-by-row recount of §3.1–§3.4" with the
correct pointer "Row-by-row recount of §2.1–§2.4" (search for the exact string
"§3.1–§3.4" in the document); update any adjacent mentions that reference "§3"
coverage tallies to "§2" if they were intended to point to the control tables,
and run a quick scan for other mismatched §3/§2 references to ensure consistency
with the control tables in §2.1–§2.4.
docs/qms/sop_incident_response-tr.md-10-12 (1)

10-12: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Duplicate phrase in purpose statement (Line 10-12).

“güvenlik olaylarını” is repeated in the same sentence. Removing one occurrence will improve clarity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/qms/sop_incident_response-tr.md` around lines 10 - 12, Remove the
duplicated phrase "güvenlik olaylarını" in the purpose sentence so it reads
smoothly; update the sentence containing "Dağıtılan fine-tuned modeller için
güvenlik olaylarını, model arızalarını, **güvenlik olaylarını** ve düzeltici
eylemleri yönetme prosedürünü tanımla." to a single instance (e.g., "Dağıtılan
fine-tuned modeller için güvenlik olaylarını, model arızalarını ve düzeltici
eylemleri yönetme prosedürünü tanımla.") and leave the Wave 4 / Faz 23 reference
unchanged.
docs/guides/iso_soc2_deployer_guide.md-149-152 (1)

149-152: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Incorrect internal symbol name in evidence explanation (Line 151).

The text cites forgelm.compliance._fingerprint_local_file, but the implementation evidence exposed here is _hash_file in forgelm/compliance.py. Please update the symbol reference to avoid dead/stale pointers in audit docs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/guides/iso_soc2_deployer_guide.md` around lines 149 - 152, Update the
docs to reference the correct internal symbol: replace the stale mention of
forgelm.compliance._fingerprint_local_file with the actual implementation symbol
forgelm.compliance._hash_file in the evidence explanation so auditors are
pointed to the correct function; ensure the surrounding sentence still reads
naturally after the substitution.
docs/qms/README-tr.md-9-17 (1)

9-17: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

TR README links should target TR template files.

In this Turkish index, links currently point to English filenames (no -tr suffix). If TR mirrors exist, these should resolve to *-tr.md targets to preserve localization parity and avoid context switching for TR readers.

As per coding guidelines, docs/**/*.md must follow localization standards in docs/standards/localization.md.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/qms/README-tr.md` around lines 9 - 17, The Turkish README currently
links to English filenames (e.g. "sop_model_training.md",
"sop_data_management.md", "roles_responsibilities.md" etc.); update each link to
the corresponding Turkish mirror by appending the "-tr" suffix (e.g.
"sop_model_training-tr.md", "sop_data_management-tr.md",
"roles_responsibilities-tr.md") for all entries that have TR templates, and if a
TR file does not exist, add a brief TODO comment or create a redirect page;
follow the localization rules in docs/standards/localization.md to ensure
consistent naming and fallbacks.
tools/check_anchor_resolution.py-44-52 (1)

44-52: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fenced code blocks are not stripped before link extraction — likely false positives once --strict lands in Faz 30.

_extract_links runs _LINK_RE over every line of every Markdown file, including the contents of ``` fenced code blocks and indented code blocks. Documentation that contains literal [text](href) examples inside a code fence (e.g. how-to snippets in docs/standards/, deployer cookbook examples that quote a markdown link as data, or test fixtures embedded in docs) will be reported as broken targets even though they are illustrative content, not real links.

In advisory mode this is just noise on top of the documented 36 pre-existing broken links, but the design doc §12 commits CI to flip this gate to strict in Faz 30. Recommend stripping fenced code spans (and optionally inline-code spans) before link extraction so the strict-mode false-positive count stays at zero.

📝 Sketch of a code-fence stripper for `_extract_links`
 def _extract_links(source: Path) -> Iterable[Link]:
     try:
         text = source.read_text(encoding="utf-8")
     except OSError:
         return
+    in_fence = False
+    fence_marker = ""
     for line_no, line in enumerate(text.splitlines(), start=1):
+        stripped = line.lstrip()
+        if stripped.startswith("```") or stripped.startswith("~~~"):
+            marker = stripped[:3]
+            if not in_fence:
+                in_fence, fence_marker = True, marker
+            elif stripped.startswith(fence_marker):
+                in_fence, fence_marker = False, ""
+            continue
+        if in_fence:
+            continue
         for match in _LINK_RE.finditer(line):
             text_part = match.group(1)
             href_part = match.group(2).strip()
             if not href_part:
                 continue
             yield Link(source=source, line=line_no, text=text_part, href=href_part)

Inline-code spans (`[foo](bar)`) can be dropped via a simple replace of `...` runs with placeholders before _LINK_RE.finditer if false positives there matter for Faz 30.

Also applies to: 205-217

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/check_anchor_resolution.py` around lines 44 - 52, _extract_links
currently runs _LINK_RE across every line including fenced and indented code
blocks, causing false-positive links; modify _extract_links to skip content
inside fenced code blocks by tracking an in_fence boolean and the fence_marker
(''' or ```) toggled when a line starts with a fence marker, and continue (skip)
lines while in_fence is True; additionally, before running _LINK_RE.finditer on
a line, strip or replace inline code spans (backtick-delimited runs) with
placeholders so patterns like `[text](href)` inside inline code are ignored;
ensure you still yield Link(source=source, line=line_no, text=text_part,
href=href_part) only for matches found outside fences and stripped inline-code.
tools/check_anchor_resolution.py-309-350 (1)

309-350: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

--exclude help text contradicts the actual default at lines 346–349.

The argparse help on lines 315–319 advertises the default exclude set as analysis/ and code_reviews/, but _resolve_excludes only seeds ("analysis",) when no --exclude is passed. The code_reviews/-path comment on lines 342–344 also reads as "we deliberately do NOT exclude code_reviews/", confirming the help text is the wrong half of the contract.

A second, related rough edge: because --exclude uses action="append" with default=None, a single --exclude foo replaces the default analysis exclusion rather than augmenting it (a user expecting "add to defaults" silently re-includes the gitignored research tree). Consider either documenting this behaviour in the help, or having _resolve_excludes always union with the analysis default.

📝 Proposed fix to align the help text with the default
     parser.add_argument(
         "--exclude",
         type=str,
         action="append",
         default=None,
         help=(
-            "Directory (relative to scope-dir) to skip.  Repeatable.  "
-            "Default exclude list strips ``analysis/`` (gitignored research "
-            "tree referencing local-only paths) and ``code_reviews/`` "
-            "(internal review docs).  Pass empty list to scan everything."
+            "Directory (relative to scope-dir) to skip.  Repeatable.  "
+            "Default excludes ``analysis/`` only (gitignored research tree "
+            "referencing local-only paths); ``code_reviews/`` is intentionally "
+            "scanned despite line-anchored drift risk.  Passing --exclude "
+            "REPLACES the default; use --exclude analysis --exclude <other> "
+            "to extend it."
         ),
     )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/check_anchor_resolution.py` around lines 309 - 350, Help text for the
--exclude argument is inconsistent with _resolve_excludes: update
parser.add_argument(...) for "--exclude" and _resolve_excludes(scope_dir,
exclude_arg) so defaults and behaviour match — pick one: either (A) change the
help text to say only "analysis/" is excluded by default, or (B) make the code
actually exclude both "analysis" and "code_reviews" by default and treat any
passed --exclude values as additions rather than replacements; to implement
option B, set a defaults tuple like defaults = ("analysis","code_reviews"), then
in _resolve_excludes always union tuple(exclude_arg or ()) with defaults (so a
provided list augments rather than replaces), resolve each with (scope_dir /
spec).resolve(), and leave parser.add_argument(action="append", default=None)
as-is or change default to None (no code change needed if you union correctly).
.github/workflows/nightly.yml-266-273 (1)

266-273: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

actions/upload-artifact@v5 is two major versions behind the current stable release.

The marketplace shows @v7.0.1 as the current stable version. Using @v5 misses security patches and improvements from v6 and v7. This is a new addition to the file and should use the latest stable version.

⚙️ Suggested update
-        uses: actions/upload-artifact@v5
+        uses: actions/upload-artifact@v7
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/nightly.yml around lines 266 - 273, The workflow step
named "Upload security scan artifacts" is using an outdated action reference
"uses: actions/upload-artifact@v5"; update that uses line to point to the
current stable release (e.g., actions/upload-artifact@v7 or the latest tag) so
the pipeline benefits from security fixes and improvements, leaving the rest of
the step (name, if: always(), with:name/path) unchanged.
docs/reference/compliance_summary.md-91-94 (1)

91-94: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Residual line-anchor compliance.py:104-114 contradicts the document's own "line-stable" principle.

The document's "Evidence locations" section (line 167) explicitly explains that #L33-style anchors were replaced because they "drifted as the codebase evolved" — yet line 93 embeds exactly that pattern. Any refactor moving the HMAC-key-derivation block will silently stale this reference, which is the problem the rewrite was meant to solve. The same stale-anchor appears in docs/qms/access_control-tr.md:83.

🔧 Proposed fix — use symbol-name form consistently
-  `SHA-256(FORGELM_AUDIT_SECRET ‖ run_id)` (see
-  `forgelm/compliance.py:104-114`).
+  `SHA-256(FORGELM_AUDIT_SECRET ‖ run_id)` (see
+  `forgelm.compliance.AuditLogger` — search for `_derive_run_key` or
+  `FORGELM_AUDIT_SECRET`).

Apply the same substitution in docs/qms/access_control-tr.md:83.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/compliance_summary.md` around lines 91 - 94, Replace the
brittle line-number anchor "forgelm/compliance.py:104-114" with the stable
symbol-name that implements the per-run signing key derivation (the
HMAC/key-derivation function or constant in forgelm/compliance.py that computes
SHA-256(FORGELM_AUDIT_SECRET ‖ run_id)); update the reference in
docs/reference/compliance_summary.md and make the same substitution in
docs/qms/access_control-tr.md:83 so both documents point to the named
function/constant rather than a numeric line range.
docs/reference/supply_chain_security-tr.md-190-192 (1)

190-192: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use TR QMS links in the TR reference page.

Line 190–Line 192 currently link to EN QMS pages even though -tr.md mirrors exist. This breaks language continuity for Turkish readers.

Suggested link fix
-- [`../qms/risk_treatment_plan.md`](../qms/risk_treatment_plan.md) — pre-populated risk register.
-- [`../qms/sop_change_management.md`](../qms/sop_change_management.md) — change management runbook.
-- [`../qms/sop_incident_response.md`](../qms/sop_incident_response.md) — incident response runbook.
+- [`../qms/risk_treatment_plan-tr.md`](../qms/risk_treatment_plan-tr.md) — pre-populated risk register.
+- [`../qms/sop_change_management-tr.md`](../qms/sop_change_management-tr.md) — change management runbook.
+- [`../qms/sop_incident_response-tr.md`](../qms/sop_incident_response-tr.md) — incident response runbook.

As per coding guidelines docs/**/*.md: “Documentation must follow docs/standards/localization.md standards.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/supply_chain_security-tr.md` around lines 190 - 192, The three
links on the Turkish supply_chain_security-tr.md reference English QMS files;
update the link targets to the Turkish mirror filenames (replace
../qms/risk_treatment_plan.md, ../qms/sop_change_management.md,
../qms/sop_incident_response.md with their TR equivalents
../qms/risk_treatment_plan-tr.md, ../qms/sop_change_management-tr.md,
../qms/sop_incident_response-tr.md) so language continuity is preserved and
ensure the change follows docs/standards/localization.md conventions.
🧹 Nitpick comments (2)
tests/test_check_anchor_resolution.py (1)

32-38: ⚡ Quick win

_load_tool() re-executes the module on every test call — cache it instead.

Each of the 21+ test methods calls _load_tool(), which creates a fresh module object and runs exec_module (recompiling every regex and constant). Since check_anchor_resolution.py has no mutable module-level state, there is no isolation benefit — only overhead.

♻️ Suggested refactor — module-level constant (or session fixture)
+# Load once at module import time; the tool has no mutable top-level state.
+_TOOL = _load_tool()
+
+
 class TestSlugifyHeading:
     def test_lowercases_and_dashes_spaces(self):
-        tool = _load_tool()
-        assert tool._slugify_heading("Hello World") == "hello-world"
+        assert _TOOL._slugify_heading("Hello World") == "hello-world"
 
     def test_strips_punctuation(self):
-        tool = _load_tool()
-        assert tool._slugify_heading("Section 1.2: Why?") == "section-12-why"
+        assert _TOOL._slugify_heading("Section 1.2: Why?") == "section-12-why"

Apply the same substitution throughout all test classes. If true per-test isolation is ever needed (e.g., the tool gains module-level caches), convert to a @pytest.fixture(scope="session").

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_check_anchor_resolution.py` around lines 32 - 38, The helper
_load_tool currently creates and execs a fresh module every call causing
unnecessary recompilation; modify it to cache the loaded module (e.g., store the
imported module in a module-level variable like _LOADED_TOOL and return that on
subsequent calls) or replace usages with a pytest fixture scoped to "session"
that loads the module once, referencing the existing _load_tool function name in
edits and update all test usages to call the cached loader or the new
session-scoped fixture to avoid repeated spec.loader.exec_module invocations.
tools/check_bandit.py (1)

94-106: 💤 Low value

_format_issue called unconditionally — result discarded for LOW and UNDEFINED issues.

line = _format_issue(issue) runs for every issue before the if/elif severity dispatch, so LOW issues (which are silent) and UNDEFINED issues (where only the count is incremented) both pay the format cost with the result thrown away.

⚙️ Suggested fix — move format call inside the branches that use it
     for issue in results:
         if not isinstance(issue, dict):
             continue
         severity = (issue.get("issue_severity") or _UNDEFINED).upper()
-        line = _format_issue(issue)
         if severity == _HIGH:
+            line = _format_issue(issue)
             high.append(line)
         elif severity == _MED:
+            line = _format_issue(issue)
             medium.append(line)
         elif severity == _UNDEFINED:
             undefined_count += 1
         # LOW is silent; the raw JSON remains in artefacts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/check_bandit.py` around lines 94 - 106, The loop currently calls
_format_issue(issue) for every result even when only LOW or UNDEFINED severities
don't use the formatted line; to fix, remove the unconditional line =
_format_issue(issue) and instead call _format_issue(issue) only inside the
branches that need it (when severity == _HIGH append to high and when severity
== _MED append to medium), leaving the undefined_count increment for _UNDEFINED
and keeping LOW silent; update the branch logic around severity (using _HIGH,
_MED, _UNDEFINED, and LOW) to avoid unnecessary formatting work.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/qms/risk_treatment_plan.md`:
- Around line 59-60: The RTP currently lists non-shipped features as active
treatments (e.g., "forgelm doctor", "forgelm purge", "forgelm reverse-pii");
update the markdown so each of those entries is clearly marked as a planned
control with an explicit status/version (e.g., "Planned — vX.Y / in development
/ ETA YYYY-MM") or remove them and replace with only currently available
controls (e.g., SBOM, pip-audit, pinned pyproject bounds); ensure you edit the
relevant table rows containing "forgelm doctor", "forgelm purge", and "forgelm
reverse-pii" to reflect the change.

In `@docs/qms/sop_change_management.md`:
- Around line 97-103: Update the CAB flow to use the shipped staging path and
retention key names: replace occurrences of staging_model.<run_id> with
final_model.staging.<run_id> in the approval/promote steps (so the CI training
output and promotion target match the shipped contract), and replace
evaluation.approval_retention_days with retention.staging_ttl_days for the
retention/expiry reference; ensure these exact identifiers
(final_model.staging.<run_id> and retention.staging_ttl_days) appear in the
steps describing staging, approval, and retention.

In `@docs/reference/iso27001_control_mapping.md`:
- Around line 28-29: The ISO 27001 control mapping lists non-shipped commands as
implemented evidence; update the table entries so only shipped
commands/artifacts are presented as evidence or explicitly annotate non-shipped
items as "planned" or "not yet released". Locate rows referencing commands like
`forgelm doctor`, `forgelm doctor --offline`, `forgelm reverse-pii`, and
`forgelm purge` and either remove them from the implemented-evidence cells
(replace with actual shipped artifacts like
`compliance_report.json`/`training_manifest.yaml`) or append a clear marker such
as "(planned)" and optionally move planned items to a separate "Planned
controls" column/section to avoid audit-facing misrepresentation.

In `@docs/reference/soc2_trust_criteria_mapping-tr.md`:
- Around line 40-55: The Turkish mapping contains commands presented as active
evidence though they don't exist in the current release; update entries
referencing commands like `forgelm safety-eval`, `forgelm verify-gguf`, `forgelm
purge`, `forgelm reverse-pii`, and `forgelm doctor` by replacing them with
verifiable current-release evidence (e.g., actual log/event names, docs pages,
SOP IDs) or explicitly annotate each such command with a clear “planned / not in
v0.5.5” note; ensure you edit the rows for CC4.1, CC7.2, CC6.5/6.6, CC? (lines
called out 40, 54, 68-69, 89-90, 100-101) so the mapping only claims
capabilities that are demonstrable in the present version.

In `@docs/reference/soc2_trust_criteria_mapping.md`:
- Around line 40-55: Several table rows map SOC 2 controls to non-shipped CLI
commands (e.g., forgelm safety-eval, forgelm verify-gguf, forgelm purge, forgelm
reverse-pii, forgelm doctor) which overstates coverage; update each offending
cell so it either references only shipped evidence or is clearly annotated as
"planned / not available in v0.5.5". Locate the entries mentioning forgelm
safety-eval, forgelm verify-gguf, forgelm purge, forgelm reverse-pii, and
forgelm doctor and replace the command text with the actual shipped alternative
evidence (logs, events, SOPs, CI tools) or append "— planned / not available in
v0.5.5" to the cell so reviewers know it is not yet shipped.

In `@docs/reference/supply_chain_security.md`:
- Around line 89-94: The documented severity policy is stale: update the wording
that currently reads "LOW / UNKNOWN → silent" to reflect that UNKNOWN is treated
as a warning-summary path; change it to something like "LOW → silent; UNKNOWN →
`::warning::` annotation (warning-summary path)" in the Severity policy section
(the block listing HIGH/CRITICAL, MEDIUM/MODERATE, LOW/UNKNOWN) and mirror the
same change in the TR copy so runtime behavior and docs remain in lockstep.

In `@docs/usermanuals/en/compliance/human-oversight.md`:
- Around line 75-80: Update the CLI examples to match the shipped positional
syntax: remove the non-existent "forgelm approvals" example and change the
approve/reject examples to use a positional <run-id> and the correct flags
(e.g., forgelm approve <run-id> --output-dir <dir> --comment "..." and forgelm
reject <run-id> --output-dir <dir> --comment "..."); ensure every occurrence
(including the similar block at line 83) is updated so examples reference the
actual commands "forgelm approve" and "forgelm reject" rather than "--run-id" or
the non-shipped "forgelm approvals".

In `@README.md`:
- Line 57: Update the README wording for the "HMAC-chained audit log" to
explicitly state that HMAC integrity depends on the presence and secure
management of the FORGELM_AUDIT_SECRET environment variable (i.e., HMAC chaining
is active only when FORGELM_AUDIT_SECRET is set), and recommend ensuring the
secret is configured and rotated appropriately so auditors won’t misinterpret
the guarantee.

---

Outside diff comments:
In `@docs/standards/testing.md`:
- Around line 8-37: The header "Current structure (67 test modules, one per
feature area; ~1410 tests)" is inconsistent with the listed tree block; update
docs/standards/testing.md so the "Current structure" either enumerates the
missing test files (e.g., add entries like test_supply_chain_security.py,
test_check_anchor_resolution.py and any other new test_*.py modules) to match
the stated count, or change the heading and add a clear note that the shown tree
is a representative subset rather than a full listing; locate the header string
"Current structure (67 test modules, one per feature area; ~1410 tests)" and the
following code block to make this change.

---

Minor comments:
In @.github/workflows/nightly.yml:
- Around line 266-273: The workflow step named "Upload security scan artifacts"
is using an outdated action reference "uses: actions/upload-artifact@v5"; update
that uses line to point to the current stable release (e.g.,
actions/upload-artifact@v7 or the latest tag) so the pipeline benefits from
security fixes and improvements, leaving the rest of the step (name, if:
always(), with:name/path) unchanged.

In `@docs/analysis/code_reviews/ghost-features-analysis-20260502.md`:
- Line 604: The document has contradictory statements about _doctor.py (Line 604
shows forgelm/cli/subcommands/_doctor.py exists referencing
FORGELM_RESUME_TOKEN, while Line 110 claims no _doctor.py); update the GH-001
claim or the Line 604 wording so they match: either change the GH-001 assertion
(the _doctor.py file exists but only contains a defensive secret-mask entry for
FORGELM_RESUME_TOKEN and does not read the env var) or add a clear
time-scope/clarifier at Line 604 stating this is a defensive mask-only reference
to avoid future accidental exposure; ensure you reference the file name
forgelm/cli/subcommands/_doctor.py and the symbol FORGELM_RESUME_TOKEN in the
revised sentence so the reader sees they refer to the same artifact.

In `@docs/guides/iso_soc2_deployer_guide.md`:
- Around line 262-265: The wording overstates the verifier's requirement: change
the sentence that says "`forgelm verify-audit` requires
`audit_log.manifest.json`" to a softer statement that the manifest sidecar
(`audit_log.manifest.json`) is not strictly required but is necessary for
truncate-and-resume detection and provides higher assurance; update the text
around "Back BOTH up." to reflect that the verifier will check the sidecar when
present and that backing up both files is recommended for full tamper-detection
coverage.
- Around line 149-152: Update the docs to reference the correct internal symbol:
replace the stale mention of forgelm.compliance._fingerprint_local_file with the
actual implementation symbol forgelm.compliance._hash_file in the evidence
explanation so auditors are pointed to the correct function; ensure the
surrounding sentence still reads naturally after the substitution.

In `@docs/qms/README-tr.md`:
- Around line 9-17: The Turkish README currently links to English filenames
(e.g. "sop_model_training.md", "sop_data_management.md",
"roles_responsibilities.md" etc.); update each link to the corresponding Turkish
mirror by appending the "-tr" suffix (e.g. "sop_model_training-tr.md",
"sop_data_management-tr.md", "roles_responsibilities-tr.md") for all entries
that have TR templates, and if a TR file does not exist, add a brief TODO
comment or create a redirect page; follow the localization rules in
docs/standards/localization.md to ensure consistent naming and fallbacks.

In `@docs/qms/sop_incident_response-tr.md`:
- Around line 10-12: Remove the duplicated phrase "güvenlik olaylarını" in the
purpose sentence so it reads smoothly; update the sentence containing "Dağıtılan
fine-tuned modeller için güvenlik olaylarını, model arızalarını, **güvenlik
olaylarını** ve düzeltici eylemleri yönetme prosedürünü tanımla." to a single
instance (e.g., "Dağıtılan fine-tuned modeller için güvenlik olaylarını, model
arızalarını ve düzeltici eylemleri yönetme prosedürünü tanımla.") and leave the
Wave 4 / Faz 23 reference unchanged.

In `@docs/qms/statement_of_applicability.md`:
- Around line 154-158: Replace the incorrect internal section reference
"Row-by-row recount of §3.1–§3.4" with the correct pointer "Row-by-row recount
of §2.1–§2.4" (search for the exact string "§3.1–§3.4" in the document); update
any adjacent mentions that reference "§3" coverage tallies to "§2" if they were
intended to point to the control tables, and run a quick scan for other
mismatched §3/§2 references to ensure consistency with the control tables in
§2.1–§2.4.

In `@docs/reference/compliance_summary.md`:
- Around line 91-94: Replace the brittle line-number anchor
"forgelm/compliance.py:104-114" with the stable symbol-name that implements the
per-run signing key derivation (the HMAC/key-derivation function or constant in
forgelm/compliance.py that computes SHA-256(FORGELM_AUDIT_SECRET ‖ run_id));
update the reference in docs/reference/compliance_summary.md and make the same
substitution in docs/qms/access_control-tr.md:83 so both documents point to the
named function/constant rather than a numeric line range.

In `@docs/reference/supply_chain_security-tr.md`:
- Around line 190-192: The three links on the Turkish
supply_chain_security-tr.md reference English QMS files; update the link targets
to the Turkish mirror filenames (replace ../qms/risk_treatment_plan.md,
../qms/sop_change_management.md, ../qms/sop_incident_response.md with their TR
equivalents ../qms/risk_treatment_plan-tr.md,
../qms/sop_change_management-tr.md, ../qms/sop_incident_response-tr.md) so
language continuity is preserved and ensure the change follows
docs/standards/localization.md conventions.

In `@docs/usermanuals/en/deployment/gguf-export.md`:
- Around line 28-29: Replace the incorrect quant flag used in the "Direct
conversion" example by changing the flag value `--quant fp16` to the recognized
`--quant f16` (ensure the example command uses `--quant f16`), and update the
size mention to match the quantisation table's lossless `f16` entry (change "~14
GB" to "13 GB") so the example and the table are consistent; look for the
example command and size text that reference `--quant fp16` and "~14 GB" and
edit them accordingly.

In `@docs/usermanuals/tr/compliance/human-oversight.md`:
- Line 83: The document mixes dotted and underscored audit event names (e.g.,
human_approval.granted / human_approval.rejected vs human_approval_granted and
human_approval_request); pick a single canonical schema (either dotted or
underscored), then update all occurrences to that form—including the examples in
this sentence (replace human_approval.granted / human_approval.rejected to the
chosen form) and any other mentions of human_approval_granted or
human_approval_request to maintain consistency across the file and ensure
grep/automation queries work reliably.

In `@tools/check_anchor_resolution.py`:
- Around line 44-52: _extract_links currently runs _LINK_RE across every line
including fenced and indented code blocks, causing false-positive links; modify
_extract_links to skip content inside fenced code blocks by tracking an in_fence
boolean and the fence_marker (''' or ```) toggled when a line starts with a
fence marker, and continue (skip) lines while in_fence is True; additionally,
before running _LINK_RE.finditer on a line, strip or replace inline code spans
(backtick-delimited runs) with placeholders so patterns like `[text](href)`
inside inline code are ignored; ensure you still yield Link(source=source,
line=line_no, text=text_part, href=href_part) only for matches found outside
fences and stripped inline-code.
- Around line 309-350: Help text for the --exclude argument is inconsistent with
_resolve_excludes: update parser.add_argument(...) for "--exclude" and
_resolve_excludes(scope_dir, exclude_arg) so defaults and behaviour match — pick
one: either (A) change the help text to say only "analysis/" is excluded by
default, or (B) make the code actually exclude both "analysis" and
"code_reviews" by default and treat any passed --exclude values as additions
rather than replacements; to implement option B, set a defaults tuple like
defaults = ("analysis","code_reviews"), then in _resolve_excludes always union
tuple(exclude_arg or ()) with defaults (so a provided list augments rather than
replaces), resolve each with (scope_dir / spec).resolve(), and leave
parser.add_argument(action="append", default=None) as-is or change default to
None (no code change needed if you union correctly).

---

Nitpick comments:
In `@tests/test_check_anchor_resolution.py`:
- Around line 32-38: The helper _load_tool currently creates and execs a fresh
module every call causing unnecessary recompilation; modify it to cache the
loaded module (e.g., store the imported module in a module-level variable like
_LOADED_TOOL and return that on subsequent calls) or replace usages with a
pytest fixture scoped to "session" that loads the module once, referencing the
existing _load_tool function name in edits and update all test usages to call
the cached loader or the new session-scoped fixture to avoid repeated
spec.loader.exec_module invocations.

In `@tools/check_bandit.py`:
- Around line 94-106: The loop currently calls _format_issue(issue) for every
result even when only LOW or UNDEFINED severities don't use the formatted line;
to fix, remove the unconditional line = _format_issue(issue) and instead call
_format_issue(issue) only inside the branches that need it (when severity ==
_HIGH append to high and when severity == _MED append to medium), leaving the
undefined_count increment for _UNDEFINED and keeping LOW silent; update the
branch logic around severity (using _HIGH, _MED, _UNDEFINED, and LOW) to avoid
unnecessary formatting work.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 191a9b79-00df-4b7f-93bc-4588526fd031

📥 Commits

Reviewing files that changed from the base of the PR and between d4e1d08 and 44dbb21.

📒 Files selected for processing (58)
  • .github/workflows/ci.yml
  • .github/workflows/nightly.yml
  • .gitignore
  • CHANGELOG.md
  • README.md
  • docs/analysis/code_reviews/closure-plan-202604300906.md
  • docs/analysis/code_reviews/ghost-features-analysis-20260502.md
  • docs/analysis/code_reviews/iso27001-soc2-alignment-202605052315.md
  • docs/analysis/code_reviews/wave4-followup-review-prompt.md
  • docs/analysis/code_reviews/wave4-review-prompt.md
  • docs/guides/gdpr_erasure-tr.md
  • docs/guides/gdpr_erasure.md
  • docs/guides/iso_soc2_deployer_guide-tr.md
  • docs/guides/iso_soc2_deployer_guide.md
  • docs/qms/README-tr.md
  • docs/qms/README.md
  • docs/qms/access_control-tr.md
  • docs/qms/access_control.md
  • docs/qms/encryption_at_rest-tr.md
  • docs/qms/encryption_at_rest.md
  • docs/qms/risk_treatment_plan-tr.md
  • docs/qms/risk_treatment_plan.md
  • docs/qms/roles_responsibilities-tr.md
  • docs/qms/sop_change_management-tr.md
  • docs/qms/sop_change_management.md
  • docs/qms/sop_data_management-tr.md
  • docs/qms/sop_incident_response-tr.md
  • docs/qms/sop_incident_response.md
  • docs/qms/sop_model_training-tr.md
  • docs/qms/statement_of_applicability-tr.md
  • docs/qms/statement_of_applicability.md
  • docs/reference/compliance_summary.md
  • docs/reference/iso27001_control_mapping-tr.md
  • docs/reference/iso27001_control_mapping.md
  • docs/reference/soc2_trust_criteria_mapping-tr.md
  • docs/reference/soc2_trust_criteria_mapping.md
  • docs/reference/supply_chain_security-tr.md
  • docs/reference/supply_chain_security.md
  • docs/standards/localization.md
  • docs/standards/testing.md
  • docs/usermanuals/en/compliance/audit-log.md
  • docs/usermanuals/en/compliance/human-oversight.md
  • docs/usermanuals/en/deployment/chat.md
  • docs/usermanuals/en/deployment/gguf-export.md
  • docs/usermanuals/en/getting-started/project-layout.md
  • docs/usermanuals/tr/compliance/audit-log.md
  • docs/usermanuals/tr/compliance/human-oversight.md
  • docs/usermanuals/tr/deployment/chat.md
  • docs/usermanuals/tr/deployment/gguf-export.md
  • docs/usermanuals/tr/getting-started/project-layout.md
  • forgelm/cli/subcommands/_doctor.py
  • pyproject.toml
  • tests/test_check_anchor_resolution.py
  • tests/test_supply_chain_security.py
  • tools/check_anchor_resolution.py
  • tools/check_bandit.py
  • tools/check_bilingual_parity.py
  • tools/check_pip_audit.py

Comment on lines +59 to +60
| Treatment | SBOM (CycloneDX 1.5) on every release tag; `pip-audit` nightly (Wave 4 / Faz 23); `forgelm doctor` pre-flight env check; pinned upper bounds in `pyproject.toml`; transitive-dep CVE feed |
| Residual L × I | Low × Med = LOW |

@coderabbitai coderabbitai Bot May 6, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Risk treatments currently overstate shipped mitigations

The RTP marks non-shipped capabilities as active treatments (e.g., Line 59 forgelm doctor, Line 90/92 forgelm purge, Line 151 forgelm reverse-pii). In a QMS template, this can produce incorrect auditor-facing risk posture.

Please gate these as “planned control” with explicit version/status, or replace with currently available controls only.

Also applies to: 90-93, 151-154

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/qms/risk_treatment_plan.md` around lines 59 - 60, The RTP currently
lists non-shipped features as active treatments (e.g., "forgelm doctor",
"forgelm purge", "forgelm reverse-pii"); update the markdown so each of those
entries is clearly marked as a planned control with an explicit status/version
(e.g., "Planned — vX.Y / in development / ETA YYYY-MM") or remove them and
replace with only currently available controls (e.g., SBOM, pip-audit, pinned
pyproject bounds); ensure you edit the relevant table rows containing "forgelm
doctor", "forgelm purge", and "forgelm reverse-pii" to reflect the change.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the flag — verified each named subcommand against the live parser before deciding the disposition:

$ forgelm doctor --help     # Phase 34 — Environment + dependency diagnostics
$ forgelm purge --help      # Phase 21 — GDPR Article 17 erasure
$ forgelm reverse-pii --help  # Phase 38 — GDPR Article 15 right-of-access
$ forgelm safety-eval --help  # Phase 36 — Standalone safety evaluation
$ forgelm verify-gguf --help  # Phase 36 — GGUF integrity check

All four are shipped subcommands in v0.5.x (forgelm/cli/_parser.py:484+ registrations). The RTP correctly cites them as active treatments because they are active in the shipping release. The original review framing ("non-shipped capabilities") was based on a stale read; the audit catalog at docs/reference/audit_event_catalog.md carries the matching event vocabulary for each. No change needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

Let me verify the parser registrations against the live code before closing this out.


🏁 Script executed:

#!/bin/bash
# Verify the subcommand registrations in the CLI parser around line 484+
rg -n "doctor|purge|reverse.pii|safety.eval|verify.gguf" --type py -C2 forgelm/cli/_parser.py 2>/dev/null | head -80

Length of output: 3325


@cemililik, confirmed — the codebase backs you up completely. All five subcommands are registered in forgelm/cli/_parser.py:

Subcommand Function Phase
doctor _add_doctor_subcommand (line 312) Phase 34
purge _add_purge_subcommand (line 803) Phase 21 / GDPR Art. 17
reverse-pii _add_reverse_pii_subcommand (line 903) Phase 38 / GDPR Art. 15
safety-eval _add_safety_eval_subcommand (line 621) Phase 36
verify-gguf _add_verify_gguf_subcommand (line 677) Phase 36

My original comment was based on a stale read. The RTP treatment entries are accurate. No change needed — apologies for the noise.


✏️ Learnings added
Learnt from: cemililik
Repo: cemililik/ForgeLM PR: 33
File: docs/qms/risk_treatment_plan.md:59-60
Timestamp: 2026-05-06T07:05:56.816Z
Learning: In the cemililik/ForgeLM repo, the following CLI subcommands are all shipped and active in v0.5.x, registered in `forgelm/cli/_parser.py`: `forgelm doctor` (Phase 34, env diagnostics), `forgelm purge` (Phase 21, GDPR Article 17 erasure), `forgelm reverse-pii` (Phase 38, GDPR Article 15 right-of-access), `forgelm safety-eval` (Phase 36, standalone safety evaluation), and `forgelm verify-gguf` (Phase 36, GGUF integrity check). Do not flag these as ghost features or unshipped capabilities in future reviews.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: cemililik
Repo: cemililik/ForgeLM PR: 28
File: docs/usermanuals/tr/getting-started/installation.md:109-109
Timestamp: 2026-05-04T13:05:13.484Z
Learning: In the cemililik/ForgeLM repo documentation, use the correct pip optional-extra name for distributed training: `distributed` (e.g., `pip install 'forgelm[distributed]'`). Do not suggest renaming `distributed` to `deepspeed` in any pip install commands or extras lists. Document `deepspeed>=0.14.0` only as the underlying PyPI dependency that is included inside the `distributed` extra (as defined in `pyproject.toml`). If `forgelm doctor` shows an `extras.deepspeed` label, treat it as a probe/display name rather than the pip extra name.

Comment thread docs/qms/sop_change_management.md Outdated
Comment on lines +28 to +29
| A.5.4 Management responsibilities | FL-helps | `forgelm doctor`; `compliance_report.json`; `training_manifest.yaml` |
| A.5.5 Contact with authorities | OOS | — |

@coderabbitai coderabbitai Bot May 6, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

ISO 27001 mapping includes evidence entries tied to non-shipped commands

Rows such as Line 28 (forgelm doctor), Line 58 (forgelm reverse-pii / forgelm purge), Line 73 (forgelm doctor --offline), and Line 111 (forgelm purge) present controls as implemented evidence where command availability is not aligned with current release reality.

Please constrain this mapping to shipped evidence or annotate non-shipped items as planned controls to avoid audit-facing misrepresentation.

Also applies to: 58-59, 73-74, 102-104, 111-113

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/iso27001_control_mapping.md` around lines 28 - 29, The ISO
27001 control mapping lists non-shipped commands as implemented evidence; update
the table entries so only shipped commands/artifacts are presented as evidence
or explicitly annotate non-shipped items as "planned" or "not yet released".
Locate rows referencing commands like `forgelm doctor`, `forgelm doctor
--offline`, `forgelm reverse-pii`, and `forgelm purge` and either remove them
from the implemented-evidence cells (replace with actual shipped artifacts like
`compliance_report.json`/`training_manifest.yaml`) or append a clear marker such
as "(planned)" and optionally move planned items to a separate "Planned
controls" column/section to avoid audit-facing misrepresentation.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same verification as the RTP thread — each cited "non-shipped" command is actually in the shipped parser. Confirmed live:

$ forgelm doctor --help        # exit 0, prints check categories
$ forgelm reverse-pii --query foo data/*.jsonl --help  # GDPR Art. 15
$ forgelm purge --row-id ID --corpus FILE --help       # GDPR Art. 17

The forgelm doctor --offline variant is also shipped (Phase 35 air-gap pre-cache integration). The mapping is honest as written; no relabel-as-planned needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify shipped CLI subcommands: doctor, doctor --offline, reverse-pii, purge
echo "=== Searching for 'doctor' subcommand ==="
fd '_doctor.py' --type f

echo ""
echo "=== Searching for 'reverse-pii' / 'reverse_pii' subcommand ==="
fd '_reverse_pii.py\|reverse.pii' --type f
rg -rn --type py 'reverse.pii\|reverse_pii' forgelm/cli/ -l

echo ""
echo "=== Searching for 'purge' subcommand ==="
fd '_purge.py' --type f
rg -rn --type py '"purge"\|purge' forgelm/cli/ -l

echo ""
echo "=== Searching for offline flag in doctor ==="
rg -n 'offline' forgelm/cli/subcommands/_doctor.py

echo ""
echo "=== Listing all subcommands ==="
fd '_.*.py' forgelm/cli/subcommands/ --type f

Length of output: 2713


@cemililik, you're right — I've verified it directly against the codebase. All four commands are present and shipped:

Command File
forgelm doctor forgelm/cli/subcommands/_doctor.py
forgelm doctor --offline Same file — --offline flag is fully implemented (e.g. _build_check_plan(offline=...), _run_all_checks(offline=...))
forgelm reverse-pii forgelm/cli/subcommands/_reverse_pii.py
forgelm purge forgelm/cli/subcommands/_purge.py

My original comment was a false positive. The mapping in docs/reference/iso27001_control_mapping.md is accurate as written — no changes needed.


✏️ Learnings added
Learnt from: cemililik
Repo: cemililik/ForgeLM PR: 33
File: docs/reference/iso27001_control_mapping.md:28-29
Timestamp: 2026-05-06T07:06:24.938Z
Learning: In cemililik/ForgeLM, the following CLI subcommands are fully shipped (not planned/ghost features): `forgelm doctor` (_doctor.py), `forgelm doctor --offline` (--offline flag in _doctor.py), `forgelm reverse-pii` (_reverse_pii.py), and `forgelm purge` (_purge.py). Do not flag these as non-shipped or planned in future reviews.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: cemililik
Repo: cemililik/ForgeLM PR: 28
File: docs/usermanuals/tr/getting-started/installation.md:109-109
Timestamp: 2026-05-04T13:05:13.484Z
Learning: In the cemililik/ForgeLM repo documentation, use the correct pip optional-extra name for distributed training: `distributed` (e.g., `pip install 'forgelm[distributed]'`). Do not suggest renaming `distributed` to `deepspeed` in any pip install commands or extras lists. Document `deepspeed>=0.14.0` only as the underlying PyPI dependency that is included inside the `distributed` extra (as defined in `pyproject.toml`). If `forgelm doctor` shows an `extras.deepspeed` label, treat it as a probe/display name rather than the pip extra name.

Comment on lines +40 to +55
| CC4.1 | Değerlendirmeleri seçer, geliştirir, gerçekleştirir | `forgelm verify-audit`; `forgelm safety-eval` |
| CC4.2 | İç kontrol eksikliklerini iletir | `pipeline.failed`/`reverted`/`erasure_failed` olayları |
| CC5.1 | Kontrol aktivitelerini seçer, geliştirir | F-compliance-110 strict gate; auto-revert; staging |
| CC5.2 | Genel BT kontrollerini seçer | `safe_post` HTTP discipline; Pydantic config validation |
| CC5.3 | Politikalar ve prosedürler dağıtır | `docs/qms/` 5 SOPs (Wave 0); 4 yeni Wave 4 / Faz 23'te |
| CC6.1 | Mantıksal-erişim güvenlik yazılımı | Operator-id attribution; HMAC chain |
| CC6.2 | Yeni iç kullanıcıları yetkilendirir | `human_approval.required`/`granted` chain |
| CC6.3 | Sonlandırılan kullanıcıların erişimini kaldırır | Operatör CI runner identity'sini iptal eder |
| CC6.4 | Fiziksel erişimi kısıtlar | OOS — datacenter güvenliği |
| CC6.5 | Yetkisiz imhaya karşı korur | `forgelm purge` Madde 17; salted hashing |
| CC6.6 | Mantıksal-erişim kontrolleri uygular | Salted hashing audit olaylarında; `forgelm reverse-pii` |
| CC6.7 | Bilgi hareketini kısıtlar | `safe_post` egress discipline; webhook payload curation |
| CC6.8 | Yetkisiz yazılımı tespit eder/önler | SBOM; `pip-audit` nightly; `bandit` CI |
| CC7.1 | Zafiyetleri tespit eder | `pip-audit` nightly; CVE feed |
| CC7.2 | Sistem bileşenlerini izler | `forgelm verify-audit`; `forgelm verify-gguf`; `safety_trend.jsonl` |
| CC7.3 | Güvenlik olaylarını değerlendirir | `data.erasure_failed`, `pipeline.failed` olayları `error_class` + `error_message` ile |

@coderabbitai coderabbitai Bot May 6, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

TR haritada da mevcut sürümde olmayan komutlar “kanıt” olarak yazılmış

Line 40 (forgelm safety-eval), Line 54 (forgelm verify-gguf), Line 89/100 (forgelm purge / forgelm reverse-pii), Line 68 (forgelm doctor) gibi girdiler mevcut sürümde doğrulanamayan yetenekleri aktif kontrol kanıtı gibi gösteriyor.

Lütfen bunları ya mevcut sürümdeki gerçek kanıtlarla değiştirin ya da açıkça “planlanan / v0.5.5’te yok” notuyla işaretleyin.

Also applies to: 68-69, 89-90, 100-101

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/soc2_trust_criteria_mapping-tr.md` around lines 40 - 55, The
Turkish mapping contains commands presented as active evidence though they don't
exist in the current release; update entries referencing commands like `forgelm
safety-eval`, `forgelm verify-gguf`, `forgelm purge`, `forgelm reverse-pii`, and
`forgelm doctor` by replacing them with verifiable current-release evidence
(e.g., actual log/event names, docs pages, SOP IDs) or explicitly annotate each
such command with a clear “planned / not in v0.5.5” note; ensure you edit the
rows for CC4.1, CC7.2, CC6.5/6.6, CC? (lines called out 40, 54, 68-69, 89-90,
100-101) so the mapping only claims capabilities that are demonstrable in the
present version.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

forgelm safety-eval, verify-gguf, purge, reverse-pii, doctor — hepsi v0.5.x parser yuzeyinde shipped subcommand olarak ship ediyor. Dogrulama: forgelm --help ciktisi tum bu subcommand'lari listeler; her birinin kendi --help'i exit 0 doner. Faz 21/34/36/38 closure-plan'da merged; audit-event-catalog (EN+TR) eslesen event vocabulary'i tasiyor. SOC 2 TR mapping dogru — relabel gerekmiyor.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

Let me verify these subcommands exist in the codebase before closing this out.


🏁 Script executed:

#!/bin/bash
# Check for the subcommand files in the CLI
echo "=== Subcommand files ==="
fd . forgelm/cli/subcommands/ --type f -e py | sort

echo ""
echo "=== Check for safety-eval, verify-gguf, purge, reverse-pii, doctor ==="
rg -n "safety.eval|safety_eval|verify.gguf|verify_gguf|purge|reverse.pii|reverse_pii|doctor" forgelm/cli/subcommands/ --type py -l

echo ""
echo "=== Check CLI entry point for registered subcommands ==="
rg -n "safety.eval|verify.gguf|purge|reverse.pii|doctor" forgelm/cli/ --type py -C2

Length of output: 67885


@cemililik, orijinal yorumum hatalıydı. Özür dilerim. Codebase'de tüm beş subcommand'ın tam olarak implement edilip kayıtlı olduğunu doğruladım:

Subcommand Dosya _parser.py kaydı _dispatch.py kaydı
forgelm doctor _doctor.py ✅ "doctor" ✅
forgelm safety-eval _safety_eval.py ✅ "safety-eval" ✅
forgelm verify-gguf _verify_gguf.py ✅ "verify-gguf" ✅
forgelm purge _purge.py ✅ "purge" ✅
forgelm reverse-pii _reverse_pii.py ✅ "reverse-pii" ✅

Tüm subcommand'lar forgelm/cli/__init__.py'de test erişimi için de re-export edilmiş. SOC 2 TR haritası doğru; relabel gerekmiyor.


✏️ Learnings added
Learnt from: cemililik
Repo: cemililik/ForgeLM PR: 33
File: docs/reference/soc2_trust_criteria_mapping-tr.md:40-55
Timestamp: 2026-05-06T07:07:16.856Z
Learning: In cemililik/ForgeLM, all of the following CLI subcommands are fully shipped in v0.5.x and are valid SOC 2 / ISO 27001 evidence references in documentation: `forgelm doctor` (_doctor.py, Phase 34), `forgelm safety-eval` (_safety_eval.py, Phase 36), `forgelm verify-gguf` (_verify_gguf.py, Phase 36), `forgelm purge` (_purge.py, Phase 21/GDPR Art.17), `forgelm reverse-pii` (_reverse_pii.py, Phase 38/GDPR Art.15). All are registered in forgelm/cli/_parser.py and forgelm/cli/_dispatch.py, and re-exported in forgelm/cli/__init__.py. Do not flag these as unshipped or ghost features.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: cemililik
Repo: cemililik/ForgeLM PR: 28
File: docs/usermanuals/tr/getting-started/installation.md:109-109
Timestamp: 2026-05-04T13:05:13.484Z
Learning: In the cemililik/ForgeLM repo documentation, use the correct pip optional-extra name for distributed training: `distributed` (e.g., `pip install 'forgelm[distributed]'`). Do not suggest renaming `distributed` to `deepspeed` in any pip install commands or extras lists. Document `deepspeed>=0.14.0` only as the underlying PyPI dependency that is included inside the `distributed` extra (as defined in `pyproject.toml`). If `forgelm doctor` shows an `extras.deepspeed` label, treat it as a probe/display name rather than the pip extra name.

Learnt from: cemililik
Repo: cemililik/ForgeLM PR: 33
File: docs/qms/sop_change_management.md:0-0
Timestamp: 2026-05-06T07:06:02.187Z
Learning: Ensure CLI usage in documentation shows forgelm approve uses a positional run_id argument (forgelm approve <run_id> --output-dir <output_dir>), not a --run-id flag. Update docs (e.g., docs/qms/sop_change_management.md) and any examples accordingly; verify with forgelm approve --help. Document that the deprecated config key evaluation.approval_retention_days forwards to the canonical retention.staging_ttl_days in forgelm/config.py:1023; prefer the canonical key in docs and config references. If possible, add CI validation to prevent the old flag form and to validate alias mapping.

Comment on lines +40 to +55
| CC4.1 | Selects, develops, performs evaluations | `forgelm verify-audit`; `forgelm safety-eval` |
| CC4.2 | Communicates internal-control deficiencies | `pipeline.failed`/`reverted`/`erasure_failed` events |
| CC5.1 | Selects, develops control activities | F-compliance-110 strict gate; auto-revert; staging |
| CC5.2 | Selects general IT controls | `safe_post` HTTP discipline; Pydantic config validation |
| CC5.3 | Deploys policies and procedures | `docs/qms/` 5 SOPs (Wave 0); 4 new in Wave 4 / Faz 23 |
| CC6.1 | Logical-access security software | Operator-id attribution; HMAC chain |
| CC6.2 | Authorises new internal users | `human_approval.required`/`granted` chain |
| CC6.3 | Removes access for terminated users | Deployer revokes CI runner identity |
| CC6.4 | Restricts physical access | OOS — datacenter security |
| CC6.5 | Protects against unauthorised disposal | `forgelm purge` Article 17; salted hashing |
| CC6.6 | Implements logical-access controls | Salted hashing in audit events; `forgelm reverse-pii` |
| CC6.7 | Restricts movement of information | `safe_post` egress discipline; webhook payload curation |
| CC6.8 | Detects/prevents unauthorised software | SBOM; `pip-audit` nightly; `bandit` CI |
| CC7.1 | Detects vulnerabilities | `pip-audit` nightly; CVE feed |
| CC7.2 | Monitors system components | `forgelm verify-audit`; `forgelm verify-gguf`; `safety_trend.jsonl` |
| CC7.3 | Evaluates security events | `data.erasure_failed`, `pipeline.failed` events with `error_class` + `error_message` |

@coderabbitai coderabbitai Bot May 6, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not map SOC 2 controls to non-shipped CLI capabilities

Several rows cite non-shipped commands as current evidence (e.g., Line 40 forgelm safety-eval, Line 54 forgelm verify-gguf, Line 90/101 forgelm purge / forgelm reverse-pii, Line 69 forgelm doctor). That overstates control coverage and creates compliance-evidence drift.

Please either (a) replace with currently shipped evidence only, or (b) mark those entries explicitly as “planned / not available in v0.5.5”.

Also applies to: 69-70, 90-91, 101-102

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/soc2_trust_criteria_mapping.md` around lines 40 - 55, Several
table rows map SOC 2 controls to non-shipped CLI commands (e.g., forgelm
safety-eval, forgelm verify-gguf, forgelm purge, forgelm reverse-pii, forgelm
doctor) which overstates coverage; update each offending cell so it either
references only shipped evidence or is clearly annotated as "planned / not
available in v0.5.5". Locate the entries mentioning forgelm safety-eval, forgelm
verify-gguf, forgelm purge, forgelm reverse-pii, and forgelm doctor and replace
the command text with the actual shipped alternative evidence (logs, events,
SOPs, CI tools) or append "— planned / not available in v0.5.5" to the cell so
reviewers know it is not yet shipped.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same verification path as the SOC 2 TR + RTP threads — forgelm safety-eval, verify-gguf, purge, reverse-pii, doctor are all shipped CLI subcommands in v0.5.x. Confirmed via:

$ forgelm --help
$ forgelm <subcommand> --help   # exits 0 with full usage for each

Closure-plan citations: Phase 21 (purge), Phase 34 (doctor), Phase 35 (cache + offline doctor), Phase 36 (safety-eval + verify-gguf), Phase 38 (reverse-pii). The mapping accurately reflects shipped capability — no "planned / not in v0.5.5" annotation needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

Let me verify these subcommands exist in the codebase.


🏁 Script executed:

#!/bin/bash
# Check for the presence of each claimed subcommand in forgelm CLI
fd -t f '_doctor\|_purge\|_safety\|_verify\|_reverse' forgelm/cli/subcommands/
echo "---"
# Also check the CLI registration to see what subcommands are wired up
rg -n 'safety.eval\|verify.gguf\|purge\|reverse.pii\|doctor' forgelm/cli/ --type py -l
echo "---"
# Check main CLI entry point for registered subcommands
rg -n 'add_parser\|subcommand' forgelm/cli/ --type py -A1 | head -80

Length of output: 8


Let me look more broadly at the CLI structure.


🏁 Script executed:

#!/bin/bash
# Discover CLI directory structure
tree forgelm/cli/ 2>/dev/null || find forgelm/cli/ -type f -name "*.py" | sort
echo "==="
# Search across entire codebase for these subcommands
rg -rn 'safety.eval\|verify.gguf\|reverse.pii\|forgelm purge\|add_subparsers' forgelm/ --type py | head -60
echo "==="
# Look for any subcommand registration
rg -rn 'subcommand\|add_parser' forgelm/ --type py | head -60

Length of output: 709


@cemililik, you're right — I've confirmed this directly in the codebase. All five flagged subcommands are present as shipped CLI modules:

  • forgelm/cli/subcommands/_doctor.py ✅
  • forgelm/cli/subcommands/_purge.py ✅
  • forgelm/cli/subcommands/_safety_eval.py ✅
  • forgelm/cli/subcommands/_verify_gguf.py ✅
  • forgelm/cli/subcommands/_reverse_pii.py ✅

My original concern was mistaken. The SOC 2 mapping accurately reflects shipped v0.5.x capability and no "planned / not available in v0.5.5" annotations are needed. Apologies for the noise.

🐇 scratches ear sheepishly


✏️ Learnings added
Learnt from: cemililik
Repo: cemililik/ForgeLM PR: 33
File: docs/reference/soc2_trust_criteria_mapping.md:40-55
Timestamp: 2026-05-06T07:06:34.181Z
Learning: In cemililik/ForgeLM, the following CLI subcommands are all shipped in v0.5.x (confirmed present in forgelm/cli/subcommands/): `forgelm doctor` (_doctor.py), `forgelm purge` (_purge.py), `forgelm safety-eval` (_safety_eval.py), `forgelm verify-gguf` (_verify_gguf.py), `forgelm reverse-pii` (_reverse_pii.py), `forgelm verify-audit` (_verify_audit.py), `forgelm verify-annex-iv` (_verify_annex_iv.py). Do not flag these as unshipped or ghost features when reviewing compliance/reference documentation.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: cemililik
Repo: cemililik/ForgeLM PR: 28
File: docs/usermanuals/tr/getting-started/installation.md:109-109
Timestamp: 2026-05-04T13:05:13.484Z
Learning: In the cemililik/ForgeLM repo documentation, use the correct pip optional-extra name for distributed training: `distributed` (e.g., `pip install 'forgelm[distributed]'`). Do not suggest renaming `distributed` to `deepspeed` in any pip install commands or extras lists. Document `deepspeed>=0.14.0` only as the underlying PyPI dependency that is included inside the `distributed` extra (as defined in `pyproject.toml`). If `forgelm doctor` shows an `extras.deepspeed` label, treat it as a probe/display name rather than the pip extra name.

Comment thread docs/reference/supply_chain_security.md
Comment thread docs/usermanuals/en/compliance/human-oversight.md Outdated
Comment thread README.md Outdated
Wave 4 round-3 absorption from inline review comments on PR #33.
Per "Verify each finding against current code" methodology: 4
findings skipped as INVALID (CLI commands claimed non-shipped that
verifiably ship in v0.5.x — `forgelm doctor`/`purge`/`reverse-pii`/
`safety-eval`/`verify-gguf`/`approvals` all confirmed via
`forgelm --help`).

Skipped (with reasons noted in this commit message):
- RTP / iso27001_control_mapping / soc2_trust_criteria_mapping
  EN+TR — reviewer claimed `forgelm doctor`/`purge`/`reverse-pii`/
  etc. as non-shipped; verified shipped via Phase 21/34/35/36/37/38
  + live `forgelm <subcommand> --help` invocations.
- iso_soc2_deployer_guide.md L149-152 — reviewer wanted
  `_fingerprint_local_file` → `_hash_file`; current cite is correct
  (`_fingerprint_local_file` IS the local-file fingerprint helper
  at compliance.py:510, distinct from `_hash_file` at :466 which
  is for model-artefact hashing under `model_integrity.json`).
- nightly.yml v5→v7 bump — no justification given; v5 is the
  current pinned version per repo history.
- check_anchor_resolution code-fence false-positives — wide-scope
  change requiring fence-tracking + inline-code stripping; the
  36-link advisory baseline is Faz 30 follow-up territory.
- _load_tool caching nit — performance gain negligible (tests run
  in 0.5s) for added complexity.

Absorbed (16 fixes):
- README.md L57 — HMAC integrity qualifier: "active only when
  FORGELM_AUDIT_SECRET is set + KMS-managed + rotated between
  output-dir lifecycles" with cross-link to access_control §3.4.
- supply_chain_security.md + -tr.md severity policy — UNKNOWN
  flipped from "silent" to "single summary `::warning::` with
  count + report path" matching the round-2 pip-audit/bandit
  behaviour change.
- human-oversight.md (EN) — `forgelm approve --run-id <run-id>`
  → positional `forgelm approve <run-id> --output-dir <dir>
  --comment "..."` (parser uses positional run_id; --run-id is
  not a flag).
- human-oversight.md / -tr.md — canonicalised event names from
  mixed underscore/dot to dotted form (`human_approval.required`,
  `.granted`, `.timeout`) matching the audit catalog.
- standards/testing.md — "67 test modules, ~1410 tests" → "~70
  modules, ~1413 tests" + added the 4 newest test files
  (supply_chain_security, check_anchor_resolution,
  check_bilingual_parity, gdpr_erasure) + clarified the listing
  is a representative subset (`git ls-files tests/` for full
  inventory).
- gguf-export.md / -tr.md — `--quant fp16` → `--quant f16` (matches
  parser choices q2_k/q3_k_m/q4_k_m/q5_k_m/q8_0/f16); size 14 GB
  → 13 GB (matches the quantisation-table f16 row).
- iso_soc2_deployer_guide.md / -tr.md — softened "verify-audit
  requires manifest" to "manifest is the truncate-and-resume
  detection signal; verifier walks chain end-to-end without it";
  recommends backing up both for full tamper-detection coverage.
- qms/README-tr.md — 9 internal QMS links updated from English
  filenames to `-tr.md` mirrors (sop_model_training-tr.md,
  sop_data_management-tr.md, etc.).
- sop_incident_response-tr.md — removed duplicated "güvenlik
  olaylarını" phrase from §1 lead-in.
- statement_of_applicability.md / -tr.md — internal pointer
  "§3.1–§3.4" corrected to "§2.1–§2.4" (the SoA's own matrix
  structure); kept the cross-reference to the design doc's §3
  Coverage tally in a separate sentence with the absolute path.
- compliance_summary.md + access_control-tr.md — replaced brittle
  `forgelm/compliance.py:104-114` line-range cite with the stable
  symbol path `AuditLogger.__init__` + `verify_audit_log` (per the
  Faz 26 line-anchors-to-symbol-references policy applied during
  the compliance_summary rewrite).
- supply_chain_security-tr.md — 3 "See also" links updated from
  English QMS files to `-tr.md` mirrors (risk_treatment_plan-tr.md,
  sop_change_management-tr.md, sop_incident_response-tr.md).
- sop_change_management.md / -tr.md — staging path
  `staging_model.<run_id>` → `final_model.staging.<run_id>` (matches
  config.py:482); retention key
  `evaluation.approval_retention_days` → `retention.staging_ttl_days`
  (matches config.py:1023); approve invocation flag-form
  `--run-id <run_id>` → positional `<run_id> --output-dir <dir>`
  (matches the shipped parser surface).
- ghost-features-analysis-20260502.md L110 — added Status update
  paragraph reconciling the original "no doctor / no _doctor.py"
  claim (true at 2026-05-02) with the current state (GH-1 closed
  via Phase 34; _doctor.py ships and contains the
  FORGELM_RESUME_TOKEN defensive secret-mask entry referenced at
  line 604).
- check_bandit.py — `_format_issue` micro-opt: only call inside
  HIGH/MEDIUM branches (LOW is silent + UNDEFINED surfaces as a
  count, so per-finding formatting on those paths is wasted).
- check_anchor_resolution.py — `--exclude` help text now matches
  actual behaviour (default = `("analysis",)` only;
  `analysis/code_reviews/` is excluded transitively as a child;
  passing `--exclude` REPLACES rather than augments).

Validation
- ruff format / check — clean.
- python3 tools/check_bilingual_parity.py --strict — 23/23 OK.
- python3 -m pytest --no-cov -q — 1413 passed, 14 skipped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (2)
docs/qms/access_control-tr.md (1)

190-193: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

forgelm approve örneği hatalı flag kullanıyor.

Line 192’deki --run-id kullanımı CLI sözleşmesiyle uyumsuz; doküman komutu çalıştırılamaz hale getiriyor.

Suggested fix
-FORGELM_OPERATOR="alice@acme.example" \
-    forgelm approve --run-id <run-id>
+FORGELM_OPERATOR="alice@acme.example" \
+    forgelm approve <run_id> --output-dir <output_dir>

Based on learnings: forgelm approve uses positional run_id (forgelm approve <run_id> --output-dir <output_dir>), not a --run-id flag.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/qms/access_control-tr.md` around lines 190 - 193, The example uses the
wrong flag for the CLI: replace the incorrect `--run-id` usage in the `forgelm
approve` example with the positional run_id argument required by the command
(i.e., call `forgelm approve <run-id>`), keep the FORGELM_OPERATOR environment
variable as shown, and if needed demonstrate additional flags like `--output-dir
<output_dir>` as separate optional args rather than using `--run-id`.
docs/reference/compliance_summary.md (1)

106-109: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Article 14 bölümünde eski staging path ve eski approve flag’i geri gelmiş.

Line 107-109’daki örnek, güncel çalışır kontrat yerine deprecated formu anlatıyor.

Suggested fix
-- Implementation: when `evaluation.require_human_approval: true`
-  the trained model lands in `<output_dir>/staging_model.<run_id>/`
-  awaiting `forgelm approve --run-id <id>` from a non-trainer
+-- Implementation: when `evaluation.require_human_approval: true`
+  the trained model lands in `<output_dir>/final_model.staging.<run_id>/`
+  awaiting `forgelm approve <run_id> --output-dir <output_dir>` from a non-trainer
   operator.

Based on learnings: use positional run_id for forgelm approve, and document the shipped staging path as final_model.staging.<run_id>.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/compliance_summary.md` around lines 106 - 109, The example
uses a deprecated staging path and approve flag: replace the old
`staging_model.<run_id>/` and flag-style approve with the current contract by
documenting the staging directory as `final_model.staging.<run_id>` and showing
the CLI call using a positional run_id (e.g., `forgelm approve <run_id>`) while
still referencing the config key `evaluation.require_human_approval` as the
trigger for human approval; update the lines that mention
`staging_model.<run_id>` and `forgelm approve --run-id <id>` to the new
`final_model.staging.<run_id>` and `forgelm approve <run_id>` form.
🧹 Nitpick comments (1)
docs/guides/iso_soc2_deployer_guide-tr.md (1)

282-291: ⚡ Quick win

Prefer TR cross-links in the Turkish guide where mirrors exist.

In the Bkz. list, several links point to EN docs. For localization consistency, point to -tr.md variants when available, and fall back to EN only for docs without TR mirrors.

As per coding guidelines, docs/**/*.md must follow localization standards (docs/standards/localization.md).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/guides/iso_soc2_deployer_guide-tr.md` around lines 282 - 291, Update the
Bkz. list to prefer Turkish mirror filenames: for each link (e.g.
../analysis/code_reviews/iso27001-soc2-alignment-202605052315.md,
../qms/encryption_at_rest.md, ../qms/access_control.md,
../qms/risk_treatment_plan.md, ../qms/statement_of_applicability.md,
../qms/sop_incident_response.md, ../qms/sop_change_management.md,
../reference/iso27001_control_mapping.md,
../reference/soc2_trust_criteria_mapping.md,
../reference/supply_chain_security.md) replace the target with the corresponding
-tr.md variant when that Turkish mirror exists (e.g.
../qms/encryption_at_rest-tr.md); if a -tr.md file is not present, leave the
original EN link. Ensure changes follow the docs/standards/localization.md rules
for cross-linking and localization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/reference/supply_chain_security-tr.md`:
- Line 3: Update the Turkish intro line string "ForgeLM'in supply-chain güvenlik
tooling'i için referans dokuman:" to correct the spelling by replacing "dokuman"
with "doküman" (i.e., "ForgeLM'in supply-chain güvenlik tooling'i için referans
doküman:") and ensure the change follows the docs standards in
docs/standards/documentation.md for user-facing content.

In `@docs/usermanuals/tr/compliance/human-oversight.md`:
- Around line 77-80: Update the Turkish CLI examples to match the shipped
contract: replace the deprecated --run-id and --reason flags and add
--output-dir where required; specifically change the approvals example to
include --output-dir <dir>, and change the approve and reject examples to use a
positional <run-id> argument plus --output-dir <dir> and --comment "..." (refer
to the commands approvals, approve, and reject in the snippet to locate the
lines to edit).

In `@tools/check_anchor_resolution.py`:
- Around line 241-250: _locate_target currently accepts resolved paths even if
they escape the repo root; update it to ensure both candidate paths (target and
alt) are constrained to inside repo_root by comparing their resolved forms
against repo_root.resolve() (e.g., using Path.is_relative_to or manual ancestor
check) and return BrokenLink(link, ...) when a candidate exists but is outside
the repo root; reference the symbols _locate_target, target, alt, repo_root, and
BrokenLink when making the check so the function only returns paths under
repo_root.
- Around line 343-357: The _resolve_excludes function treats an empty-string
entry in exclude_arg as a real path and ends up excluding the entire scope; to
fix this, filter out empty strings (and whitespace-only strings) from
exclude_arg before building specs so that exclude_arg=[""] is treated like no
excludes. Update _resolve_excludes to normalize exclude_arg (ignore None and any
"" entries), set specs accordingly (default to ("analysis",) only when there are
no valid spec strings), and then resolve (scope_dir / spec).resolve() for each
valid spec; reference symbols: _resolve_excludes, exclude_arg, specs, scope_dir.

---

Duplicate comments:
In `@docs/qms/access_control-tr.md`:
- Around line 190-193: The example uses the wrong flag for the CLI: replace the
incorrect `--run-id` usage in the `forgelm approve` example with the positional
run_id argument required by the command (i.e., call `forgelm approve <run-id>`),
keep the FORGELM_OPERATOR environment variable as shown, and if needed
demonstrate additional flags like `--output-dir <output_dir>` as separate
optional args rather than using `--run-id`.

In `@docs/reference/compliance_summary.md`:
- Around line 106-109: The example uses a deprecated staging path and approve
flag: replace the old `staging_model.<run_id>/` and flag-style approve with the
current contract by documenting the staging directory as
`final_model.staging.<run_id>` and showing the CLI call using a positional
run_id (e.g., `forgelm approve <run_id>`) while still referencing the config key
`evaluation.require_human_approval` as the trigger for human approval; update
the lines that mention `staging_model.<run_id>` and `forgelm approve --run-id
<id>` to the new `final_model.staging.<run_id>` and `forgelm approve <run_id>`
form.

---

Nitpick comments:
In `@docs/guides/iso_soc2_deployer_guide-tr.md`:
- Around line 282-291: Update the Bkz. list to prefer Turkish mirror filenames:
for each link (e.g.
../analysis/code_reviews/iso27001-soc2-alignment-202605052315.md,
../qms/encryption_at_rest.md, ../qms/access_control.md,
../qms/risk_treatment_plan.md, ../qms/statement_of_applicability.md,
../qms/sop_incident_response.md, ../qms/sop_change_management.md,
../reference/iso27001_control_mapping.md,
../reference/soc2_trust_criteria_mapping.md,
../reference/supply_chain_security.md) replace the target with the corresponding
-tr.md variant when that Turkish mirror exists (e.g.
../qms/encryption_at_rest-tr.md); if a -tr.md file is not present, leave the
original EN link. Ensure changes follow the docs/standards/localization.md rules
for cross-linking and localization.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9f438ce1-1590-452a-88da-2a923728fc5b

📥 Commits

Reviewing files that changed from the base of the PR and between 44dbb21 and 20e4245.

📒 Files selected for processing (21)
  • README.md
  • docs/analysis/code_reviews/ghost-features-analysis-20260502.md
  • docs/guides/iso_soc2_deployer_guide-tr.md
  • docs/guides/iso_soc2_deployer_guide.md
  • docs/qms/README-tr.md
  • docs/qms/access_control-tr.md
  • docs/qms/sop_change_management-tr.md
  • docs/qms/sop_change_management.md
  • docs/qms/sop_incident_response-tr.md
  • docs/qms/statement_of_applicability-tr.md
  • docs/qms/statement_of_applicability.md
  • docs/reference/compliance_summary.md
  • docs/reference/supply_chain_security-tr.md
  • docs/reference/supply_chain_security.md
  • docs/standards/testing.md
  • docs/usermanuals/en/compliance/human-oversight.md
  • docs/usermanuals/en/deployment/gguf-export.md
  • docs/usermanuals/tr/compliance/human-oversight.md
  • docs/usermanuals/tr/deployment/gguf-export.md
  • tools/check_anchor_resolution.py
  • tools/check_bandit.py
✅ Files skipped from review due to trivial changes (1)
  • docs/guides/iso_soc2_deployer_guide.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/usermanuals/en/deployment/gguf-export.md

@@ -0,0 +1,200 @@
# Supply-chain güvenliği — SBOM + zafiyet taraması

> ForgeLM'in supply-chain güvenlik tooling'i için referans dokuman:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix Turkish spelling in the intro line.

dokuman should be corrected to doküman for user-facing documentation quality.

As per coding guidelines, docs/**/*.md content must follow documentation standards (docs/standards/documentation.md).

🧰 Tools
🪛 LanguageTool

[grammar] ~3-~3: Ensure spelling is correct
Context: ...-chain güvenlik tooling'i için referans dokuman: > SBOM üretimi (Wave 2 dönemi), pip-aud...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/supply_chain_security-tr.md` at line 3, Update the Turkish
intro line string "ForgeLM'in supply-chain güvenlik tooling'i için referans
dokuman:" to correct the spelling by replacing "dokuman" with "doküman" (i.e.,
"ForgeLM'in supply-chain güvenlik tooling'i için referans doküman:") and ensure
the change follows the docs standards in docs/standards/documentation.md for
user-facing content.

Comment on lines +77 to +80
```bash
forgelm approvals --pending # onay bekleyen koşumları listele
forgelm approve --run-id <run-id> # staging → final_model'e promote
forgelm reject --run-id <run-id> --reason "..." # staged modeli at

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Canonical CLI examples are using outdated flags in Turkish doc

Line 79 and Line 80 use --run-id (and Line 80 uses --reason), but the shipped contract uses positional <run-id> plus --output-dir and --comment. Line 78 should also include --output-dir for approvals --pending to match actual usage.

Suggested doc fix
 ```bash
-forgelm approvals --pending                       # onay bekleyen koşumları listele
-forgelm approve --run-id <run-id>                 # staging → final_model'e promote
-forgelm reject  --run-id <run-id> --reason "..."  # staged modeli at
+forgelm approvals --pending --output-dir <dir>            # onay bekleyen koşumları listele
+forgelm approve  <run-id> --output-dir <dir> --comment "..."  # staging → final_model'e promote
+forgelm reject   <run-id> --output-dir <dir> --comment "..."  # staged modeli at
</details>

Based on learnings: “Ensure CLI usage in documentation shows forgelm approve uses a positional run_id argument … not a --run-id flag,” and “The documented commands must reflect the exact usage … approvals --pending --output-dir, approve <run-id> … --comment, reject <run-id> … --comment.”

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/usermanuals/tr/compliance/human-oversight.md` around lines 77 - 80,
Update the Turkish CLI examples to match the shipped contract: replace the
deprecated --run-id and --reason flags and add --output-dir where required;
specifically change the approvals example to include --output-dir <dir>, and
change the approve and reject examples to use a positional <run-id> argument
plus --output-dir <dir> and --comment "..." (refer to the commands approvals,
approve, and reject in the snippet to locate the lines to edit).

Comment on lines +241 to +250
def _locate_target(link: Link, path_part: str, repo_root: Path) -> Path | BrokenLink:
"""Resolve a repo-relative path against the source's parent or repo root."""
target = (link.source.parent / path_part).resolve()
if target.exists():
return target
# Fall back: maybe the path is repo-root-relative (legacy refs).
alt = (repo_root / path_part).resolve()
if alt.exists():
return alt
return BrokenLink(link, f"target file not found: {path_part!r}")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Target çözümleme repo-kök sınırını zorlamıyor.

Line 244-249’da path varsa kabul ediliyor; absolute/escape path’ler repo dışına çözülüp ortama bağlı yanlış “geçti” sonucu üretebilir.

Suggested fix
 def _locate_target(link: Link, path_part: str, repo_root: Path) -> Path | BrokenLink:
@@
-    if target.exists():
+    if target.exists() and _is_under(target, repo_root):
         return target
@@
-    if alt.exists():
+    if alt.exists() and _is_under(alt, repo_root):
         return alt
+    if target.exists() or alt.exists():
+        return BrokenLink(link, f"target resolves outside repository root: {path_part!r}")
     return BrokenLink(link, f"target file not found: {path_part!r}")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/check_anchor_resolution.py` around lines 241 - 250, _locate_target
currently accepts resolved paths even if they escape the repo root; update it to
ensure both candidate paths (target and alt) are constrained to inside repo_root
by comparing their resolved forms against repo_root.resolve() (e.g., using
Path.is_relative_to or manual ancestor check) and return BrokenLink(link, ...)
when a candidate exists but is outside the repo root; reference the symbols
_locate_target, target, alt, repo_root, and BrokenLink when making the check so
the function only returns paths under repo_root.

Comment on lines +343 to +357
def _resolve_excludes(scope_dir: Path, exclude_arg: list[str] | None) -> tuple[Path, ...]:
# Default exclude list — `analysis/` is gitignored research with
# local-only path references; `code_reviews/` lives under it and
# is caught transitively (its closure-plan docs cite real files at
# line-anchored locations that drift).
#
# Passing --exclude REPLACES the default rather than augmenting it
# (call sites that need additional excludes pass the full list,
# including ``analysis``); this matches the help-text contract.
specs: tuple[str, ...]
if exclude_arg is None:
specs = ("analysis",)
else:
specs = tuple(exclude_arg)
return tuple((scope_dir / spec).resolve() for spec in specs)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

--exclude '' tüm scope’u yanlışlıkla dışlıyor (false-green risk).

exclude_arg=[""] olduğunda resolver scope_dir’i exclude ediyor; sonuçta hiçbir .md dosyası taranmıyor.

Suggested fix
 def _resolve_excludes(scope_dir: Path, exclude_arg: list[str] | None) -> tuple[Path, ...]:
@@
-    if exclude_arg is None:
-        specs = ("analysis",)
-    else:
-        specs = tuple(exclude_arg)
+    if exclude_arg is None:
+        specs = ("analysis",)
+    else:
+        specs = tuple(spec for spec in exclude_arg if spec.strip())
     return tuple((scope_dir / spec).resolve() for spec in specs)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/check_anchor_resolution.py` around lines 343 - 357, The
_resolve_excludes function treats an empty-string entry in exclude_arg as a real
path and ends up excluding the entire scope; to fix this, filter out empty
strings (and whitespace-only strings) from exclude_arg before building specs so
that exclude_arg=[""] is treated like no excludes. Update _resolve_excludes to
normalize exclude_arg (ignore None and any "" entries), set specs accordingly
(default to ("analysis",) only when there are no valid spec strings), and then
resolve (scope_dir / spec).resolve() for each valid spec; reference symbols:
_resolve_excludes, exclude_arg, specs, scope_dir.

…+ anchor checker hardening)

All 7 findings verified valid against current code; round 3 caught
the EN side of the approve/reject + staging-path drift but missed
several TR mirror sites + the compliance_summary EN reference.

Documentation (5)
- supply_chain_security-tr.md L3 — "dokuman" → "doküman" (TR
  spelling).
- usermanuals/tr/compliance/human-oversight.md L77-80 — round 3
  fixed the EN CLI block but missed the TR mirror; now uses the
  shipped contract:
    forgelm approvals --pending --output-dir <dir>
    forgelm approve  <run-id> --output-dir <dir> --comment "..."
    forgelm reject   <run-id> --output-dir <dir> --comment "..."
  + explicit note about positional run_id.
- qms/access_control-tr.md L190-193 + qms/access_control.md L190 —
  segregation-of-duties Job 2 example used `forgelm approve
  --run-id <run-id>`; replaced with positional
  `forgelm approve <run-id> --output-dir <output_dir>` (parser
  contract). Both EN + TR.
- reference/compliance_summary.md L106-109 — Article 14 staging
  description used the deprecated `staging_model.<run_id>/` path
  AND the broken `--run-id <id>` flag form. Now uses
  `final_model.staging.<run_id>/` (matches `forgelm/config.py:482`)
  and `forgelm approve <run_id> --output-dir <output_dir>`
  (positional). Mirror of round-2/3 fixes propagated to the
  compliance_summary surface.
- guides/iso_soc2_deployer_guide-tr.md L282-291 — "Bkz." list
  linked to 9 EN files when TR mirrors exist. Updated all 9 to
  `-tr.md` variants (qms × 6, reference × 4 + audit_event_catalog).
  Left the analysis design doc link as EN (no TR mirror exists for
  research artefacts under `docs/analysis/`).

Tooling (2)
- tools/check_anchor_resolution.py::_locate_target — both candidate
  paths (`target` from source.parent + `alt` from repo_root) are
  now constrained to live under `repo_root.resolve()` via
  `Path.relative_to`. A `../../../etc/passwd`-style path traversal
  that resolves outside the repo tree is now treated as broken
  rather than silently followed. Defensive correctness fix; no
  shipped doc trips the new branch (anchor-checker baseline still
  reports the same 36 broken links).
- tools/check_anchor_resolution.py::_resolve_excludes — empty /
  whitespace-only entries in `--exclude` are now filtered (an
  `--exclude ""` previously resolved to `scope_dir` itself and
  silently excluded the entire tree). When the cleaned list is
  empty (all entries filtered out), falls back to the default
  ("analysis",) rather than scanning everything.

Validation
- ruff format / check — clean.
- python3 tools/check_bilingual_parity.py --strict — 23/23 OK.
- python3 -m pytest tests/test_check_anchor_resolution.py — 31/31 pass.
- python3 -m pytest --no-cov -q — 1413 passed, 14 skipped.
- Anchor advisory baseline unchanged at 36 (Faz 30 territory).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented May 6, 2026

Copy link
Copy Markdown

@cemililik
cemililik merged commit 01e40ba into development May 6, 2026
3 of 4 checks passed
cemililik added a commit that referenced this pull request May 6, 2026
…gent review findings

- Wave 5 PR #34 round 3 absorption: full sweep of CodeRabbit's 6 OOD +
  20 Minor inline review comments PLUS 24 multi-agent review findings
  (code-correctness / privacy-security / standards / test-rigor docs
  under docs/analysis/code_reviews/wave5-*.md).

HIGH/Major absorptions:
- 4 broken `forgelm.cli.subcommands.*` symbol citations across
  purge/approvals reference docs (en+tr): _run_row_erasure →
  _run_purge_row_id, _handle_pending → _run_approvals_list_pending,
  _handle_show → _run_approvals_show (F-W5-PRIV-02).
- configuration.md (en+tr): drop `kserve | triton` ghost choices and
  the entire `## deployment:` ghost YAML block (no `DeploymentConfig`
  in ForgeConfig; extra="forbid" rejects it at load) — replace with a
  v0.6.0+ Phase 14 callout (F-W5-S1, F-W5-S2).
- ingestion.md (en+tr): drop conflicting "instructions format
  default" claim; document raw-chunk JSONL with summary-only
  --output-format {text,json} (CR-OOD ingestion).
- closure-plan PR #33 status: line 131 said "PR #33 pending" but
  line 119 said merged with `01e40ba` (CR-OOD closure-plan).
- leakage.md (en+tr): remove `audit.leakage_check.remove_cross_split_overlap`
  knob reference — knob doesn't exist in code; replace with the
  documented jq-based removal flow (CR-OOD leakage).
- TR + EN experiment-tracking: drop `$ ` prompt prefix in `text`-tagged
  preview blocks for `forgelm compare-runs` (CR-OOD experiment-tracking).
- roadmap mermaid (en+tr): add Phase 12.6 (Closure Cycle) → v0.5.5
  node + edge so visual flow matches table (CR-OOD roadmap).

Minor absorptions:
- phase-12-6-closure-cycle.md L123: stale "(currently 0.5.1rc1)"
  parenthetical → already-bumped during Wave 5 (F-W5-S4 / CR Minor).
- gdpr-erasure.md (en+tr): rename duplicate `### What gets recorded`
  / `### Neyi kaydeder` H3 to disambiguate Article 17 vs 15 sections
  (CR Minor #2 + #20).
- verify-gguf.md (en+tr) L147: revise misleading "still match SHA-256"
  hash explanation; clarify magic-header layer doesn't catch
  truncation independent of sidecar (CR Minor #3).
- verify_audit link mismatch in 4 reference docs (en+tr × verify_gguf
  + verify_annex_iv): label text now matches href (CR Minor #4 + #8).
- air_gap_deployment-tr.md L19: add `text` language tag to ASCII
  diagram fence (CR Minor #6).
- site/index.html L374: drop internal "Phase 19" milestone leak; tag
  reads `embed` (user-facing label) (CR Minor #7).
- air_gap_deployment.md L193: fix dangling sentence fragment in
  HF_TOKEN gated-models tip (CR Minor #9).
- performance.md (en+tr) L184: drop ghost `forgelm audit
  --output-format parquet`; replace with pandas/pyarrow conversion
  step (CR Minor #10).
- phase-11-5-backlog.md L10-12: link text → package paths matching
  href (forgelm/data_audit.py → forgelm/data_audit/, etc.) (CR Minor #11).
- testing.md L140: stale `23/23` → `39/39` bilingual parity count
  (CR Minor #12).
- testing.md L198: `python3` prefix consistency in checklist
  (CR Minor #13).
- supply-chain.md (en+tr): bandit cadence aligned to standards doc
  (Nightly 03:00 UTC + release tag, not "every PR + main push") (CR
  Minor #14 + #15).
- translations.js L1927: "Three values" → "Two values" (only
  forgelm-lang + forgelm-theme listed) (CR Minor #16).
- approvals_subcommand.md (en+tr) L26: staging path → match L84 JSON
  sample (`final_model.staging.<run_id>` canonical, run-id-less form
  honoured as fallback) (CR Minor #17 + #19).
- translations.js L1445/L1462/L1504/L1521 (en+tr): `<code>reject</code>`
  → `<code>forgelm reject</code>` for fully-qualified copy/paste
  parity (CR Minor #18).
- _meta.yaml header: add formal DE/FR/ES/ZH deferred-policy banner
  per closure-plan Task L (F-W5-S6).
- release.md L20 + L359: stale "0.3.1rc1 current" + "no
  __version__" claims; corrected to 0.5.5 + reflect that __version__
  + __api_version__ ARE exported per Library API standard (F-W5-S3).
- purge_subcommand.md (en+tr): add WARNING-on-fallback language for
  --output-dir asymmetry vs reverse-pii (F-W5-PRIV-05).
- verify-audit.md (en+tr): replace overstated "escrow" wording with
  KMS/HSM-based separation (F-W5-PRIV-06).

Tool tightening + new tests:
- check_cli_help_consistency.py: tighten _FORWARD_REF_MARKERS to
  whole-phrase forms (drop bare "planned"/"future"/"roadmap" which
  matched "planned attacks" / "future work" / "roadmap-driven" in
  unrelated prose); add Turkish equivalents for bilingual docs
  (F-W5-01).
- test_check_cli_help_consistency.py: 3 new regression tests:
  bare-substring negative (F-W5-01), >±3-line forward-ref window
  negative (F-W5-TR-01a), and Wrong:-block scope-to-one-block
  resumption (F-W5-TR-01b). Suite 17 → 20 tests, all green.

User-manual orphan fix:
- _meta.yaml: register `reference/json-output` page (existed in
  filesystem since Wave 2 but never declared in nav config — was
  invisible on the live site). Now declared = on-disk = 65 each.

Skipped (with reason):
- CR Minor #5 (library_api.md `forgelm.__version__` example):
  INVALID — verified `python3 -c "import forgelm; print(forgelm.__version__)"`
  prints 0.5.5 cleanly; both __version__ and __api_version__ ARE
  exported per Library API standard. CodeRabbit's web-search must
  have hit pre-Wave-5 PyPI. Doc is correct; code matches.
- F-W5-S5 (parity tool autodiscover usermanuals): registry shape
  refactor (~50 new pairs) is scope creep for round 3; defer to v0.6.
- F-W5-S8 (compliance_summary-tr.md): explicitly deferred to v0.6 by
  the finding itself.
- F-W5-S9, F-W5-TR-11/12 (NIT cite/style): non-load-bearing.
- F-W5-02/03/04 (cognitive complexity, unterminated fence,
  resume-after-Wrong unit test): refactor scope; covered by F-W5-TR-01
  block-scope tests for the resume case.
- F-W5-TR-02 (cleanup commit baseline regression test): the live CI
  --strict gate IS the guard; doubling up the integration-test
  layer is defensible but not blocking.
- F-W5-TR-03/05/06/07/08/09/10 (extras): non-blocking coverage gaps.

Self-review gauntlet (all green):
  ruff format/check ✅
  bilingual_parity --strict 39/39 ✅
  anchor_resolution --strict 264/264 ✅
  cli_help_consistency --strict 425/425 ✅ (reduced from 449 due to
    intentional invocation removals: ghost YAML block, parquet ghost,
    4 broken symbol-cite paths, etc.)
  site_claims --strict (artefacts/templates/GPU/version) ✅
  field_descriptions --strict ✅
  pytest 1433 passed / 14 skipped (+5 new tests vs round 2) ✅
  forgelm --config config_template.yaml --dry-run ✅
  build_usermanuals.py: en/tr 65/65 OK, JS bundles regenerate ✅

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cemililik added a commit that referenced this pull request May 6, 2026
…ck findings

Wave 5 PR #34 round 4 absorption: CodeRabbit re-scanned the round-3
absorption commit (dcbdcf5) and surfaced 15 new inline + 1 OOD +
1 duplicate + 4 nitpick findings. 25 files changed, +65/-44 LOC.

HIGH/Major absorptions:
- forgelm/cli/subcommands/_purge.py L465-502 (`_validate_match_count_or_fail`):
  redact raw `args.row_id` from BOTH the audit-event `error_message`
  field AND the operator-facing stdout/JSON error payload. The function
  now takes `target_id_hash` and emits `<id_hash:{first12}…>` so neither
  the persisted audit log nor the CI consumer's stdout leaks a
  potentially-PII identifier. Audit event already used hashed
  `target_id`; now `error_message` is consistent (CR-purge-PII).
- docs/reference/verify_gguf_subcommand.md (en+tr) L31-33 +
  verify_annex_iv_subcommand.md (en+tr) L31-34: split exit code 1
  (caller/input + integrity-mismatch — non-file path, malformed JSON,
  non-object root, magic mismatch, hash mismatch) from exit code 2
  (genuine I/O failure on existing file). Aligns reference docs with
  the canonical _verify_gguf.py + _verify_annex_iv.py emit sites; the
  usermanual versions were already updated in round 2 (CR exit-code).
- docs/usermanuals/en/compliance/gdpr-erasure.md (en+tr) L90-93: fix
  rotation contradiction. FORGELM_AUDIT_SECRET rotation rotates ONLY
  the chain HMAC key; identifier hashes derive from per-output-dir
  salt and are stable across env-var rotations. Previous text claimed
  it rotated "BOTH the identifier-hash XOR and the chain HMAC key"
  contradicting the next bullet (CR-gdpr-rotation).
- docs/usermanuals/en/deployment/verify-gguf.md (en+tr) L12-14:
  "fail on exit 1" → "fail on any non-zero exit code" with reference
  to error-handling.md 0/1/2/3/4 contract (CR verify-gguf-exit).
- docs/usermanuals/en/deployment/verify-gguf.md (en+tr) L146-148:
  rewrite hash-explanation pitfall — round 3 had it wrong in the
  opposite direction. Truncation DOES change SHA-256, so a sidecar
  from the original CANNOT validate a truncated copy. Real bypass is
  attacker who removes/regenerates the .sha256 sidecar after
  tampering. Installing `gguf` is defence-in-depth, not sidecar
  replacement (CR-verify-gguf-hash).

Minor absorptions:
- docs/guides/human_approval_gate.md (en+tr) L138 + L228-229: add
  third audit row (`compliance.artifacts_exported`) to match "three
  rows / üç satır" prose; switch TR `approve` / `approvals` reference
  links to the `*-tr.md` mirrors (CR-3-rows + CR-tr-mirror).
- docs/roadmap.md L13: "38 fazlar" → "38 phases" (drop TR token from
  EN roadmap line) (CR-tr-leak).
- docs/usermanuals/en/data/secrets.md L124 + tr L124: drop broken
  `see "Always on" above` reference to nonexistent section; replace
  with explicit always-on description + link to `Audit-only mode`
  section that explains scan-mode semantics (CR-secrets-anchor).
- docs/usermanuals/tr/data/ingestion.md L56 + L85: translate English
  prose `Shipped` → `Sunulan`, `top-level` → `üst düzey`. CLI flag
  identifiers (`--strategy`, `sliding`, `paragraph`, `markdown`,
  `--recursive`) kept exactly as-is per project i18n policy
  (CR-tr-prose).
- docs/usermanuals/{en,tr}/data/leakage.md L72: fix wrong JSON path —
  `leakage.cross_split_overlap` → `cross_split_overlap.pairs[...]`
  (matches actual `_data_audit/_summary.py:368-371` shape). Skipped
  bot's recommendation to cite `--remove-cross-split-overlap=val|test`
  CLI flag — VERIFIED that flag does NOT exist (`forgelm audit
  --help | grep remove` returns nothing); bot is hallucinating. The
  jq-based manual-removal flow remains the documented v0.5.5 method
  (CR-leakage-path).
- README.md L291: drop hardcoded `68 test modules, ~1442 tests` —
  replace with stable `Test suite — run with pytest tests/ (count
  grows over time; CI gates on green-on-every-commit)` so the README
  doesn't drift after every PR (CR-readme-stat).
- site/index.html L165: hardcoded `1428` test count → stable `CI ✓`
  badge with same i18n label, eliminating drift (CR-site-stat).
- docs/analysis/code_reviews/closure-plan-202604300906.md L102:
  ambiguous status → canonical `Implementation complete; merge pending`
  with PR #33 merge `01e40ba` cited and PR #34 still open on
  `closure/wave5-integration` (CR-closure-canonical).
- docs/guides/air_gap_deployment.md L19: add `text` lang tag to ASCII
  diagram fence (TR was already done in round 3) (CR-en-fence).
- docs/usermanuals/{en,tr}/deployment/chat.md L14: example version
  string `ForgeLM 0.5.2` → `0.5.5` (CR-version-example).
- docs/usermanuals/tr/deployment/chat.md L111: `Pro CLI seviyesi
  için` → `Pro CLI için` for consistent Turkish wording matching L66
  (CR-tr-wording).

Outside-diff absorption:
- site/js/translations.js privacy.body (all 6 locales en/tr/de/fr/
  es/zh): short version now correctly discloses BOTH network calls —
  Google Fonts on every page load, Formspree only on contact-form
  submit. Previous text said "the only network call goes to Formspree"
  while the same body's "Third-party assets" section listed Google
  Fonts; rewrite reconciles the contradiction without changing the
  detailed disclosure below (CR-OOD-fonts).

Skipped (with reason):
- CR `_extract_invocation` refactor (extract `_parse_flags_from_tokens`):
  cognitive-complexity refactor — the helper ships with 20 pinned tests
  (round 3 added 3); refactor is mechanical but adds risk for zero
  user-visible change. Defer to v0.6 maintenance window.
- CR `_iter_code_block_lines` refactor (extract `_stitch_block_lines`,
  drop unused `source: Path` param): same scope-creep argument; the
  function is 100% covered by the 20 pinned tests and the unused
  parameter is a one-line cleanup, not a correctness issue.

Self-review gauntlet (all green):
  ruff format + check ✅ clean
  bilingual_parity --strict 39/39 ✅
  anchor_resolution --strict 264/264 ✅
  cli_help_consistency --strict 425/425 ✅
  site_claims --strict ✅
  field_descriptions --strict ✅
  pytest 1433 passed / 14 skipped (test_gdpr_erasure assertions
    updated to reflect new redacted-error-payload contract) ✅
  forgelm --config config_template.yaml --dry-run ✅
  build_usermanuals.py: en/tr 65/65 OK ✅

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cemililik
cemililik deleted the closure/wave4-integration branch May 10, 2026 11:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant