fix(site): pass-5 closure — site-vs-code honesty sweep + i18n parity#41
Conversation
Closes 11 CRITICAL + 10 HIGH + 9 MEDIUM + 7 LOW findings from pass-4 site-vs-code audit. Every site claim now matches the live forgelm/ surface; the four non-en/tr locales achieve full key parity. CRITICAL — schema drift killed: - Y1-Y6: index.html YAML demo rewritten to use real Pydantic field names (num_train_epochs, per_device_train_batch_size, evaluation.benchmark.min_score, evaluation.safety.classifier, evaluation.require_human_approval, top-level webhook block). - T1-T5: compliance.html artefact tree redrawn (compliance/ + final_model/ instead of artifacts/, audit_log.jsonl at checkpoint root, config_snapshot.yaml ghost dropped). - X1: forgelm verify-audit example points at audit_log.jsonl, not the directory. - F1: compliance.config_hash ghost replaced with forgelm verify-audit chain integrity claim (HTML + en+tr i18n). - F2: compliance.human_approval ghost YAML replaced with evaluation.require_human_approval (HTML + 6 i18n + usermanuals source markdown). - C1: forgelm.api -> "from forgelm import ..." with real forgelm.__all__ symbols. - C2: forgelm quickstart byod -> forgelm quickstart domain-expert. - C3: forgelm/data_audit.py -> forgelm/data_audit/ (Phase 14 package). HIGH — overclaims softened to match live behaviour: - H4: exit codes 0/1/2/3/4 -> 0-5. - H5: Annex IV "eight" -> "nine required §1-9 sections" matching _ANNEX_IV_REQUIRED_FIELDS. - H6: 168 i18n strings (42 keys * 4 langs) backfilled into de/fr/es/zh — every locale now at 731 keys (was 689). - H7: chat "safety routing" -> "planned for upcoming Pro CLI release" (chat.py has no Llama Guard hook in v0.5.5). - H8: wizard step counter 7 -> 9; fr/es/zh "~ 3 minutes" semantic drift swapped for step-count parity. - R1-R5: auto-revert wording, verify-annex-iv audit-chain claim, safety-eval input formats, --model-card ghost flag, purge data- provenance manifest claim — all reworded to match real behaviour. - W1: wizard.js USE_CASE_PRESETS synced with quickstart.py::TEMPLATES. MEDIUM + LOW: reverse-pii wording (M10), Mermaid jsDelivr disclosure on privacy (M11), audit-event scope (M14), QMS SOP names, PII regex specifics, docker-compose.yaml, doctor pass/warn/fail, Discord webhook, dpia-template ghost link, customer-support/code-assistant body softening, quickstart template parentheticals, JSON-LD operatingSystem + Windows on 8 pages, Last updated 2026-04-28 -> 2026-05-09. M9 wizard step-name divergence + O1 STATE_VERSION drift documented inline in _orchestrator.py + _state.py + wizard.js. CHANGELOG.md added to check_no_analysis_refs.py exempt list (the review-cycle 5 entry that announces this very policy quotes the dir names verbatim — that is the documentation, not a content reference). CI gauntlet (14 guards + ruff + dry-run + 92 guard tests + 139 wizard tests) verified clean post-fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ⓘ 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. |
There was a problem hiding this comment.
Sorry @cemililik, your pull request is larger than the review limit of 150000 diff characters
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 0 |
| Duplication | 0 |
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.
There was a problem hiding this comment.
Code Review
This pull request updates documentation and the web-based wizard to reflect recent schema changes, including renaming configuration keys for human approval and restructuring the output artifact directory. It also expands the supported operating systems to include Windows, updates several feature descriptions (e.g., SimPO, safety evaluation, and webhooks), and aligns the web wizard's use-case presets with local CLI templates. Feedback suggests using standard acronyms for fine-tuning methods in code comments and maintaining consistency in the Article evidence list by referencing file paths instead of Python symbols.
| <span class="key">r</span>: <span class="number">16</span> | ||
| <span class="key">alpha</span>: <span class="number">32</span> | ||
| <span class="key">use_dora</span>: <span class="number">true</span> | ||
| <span class="key">method</span>: <span class="string">"dora"</span> <span class="comment"># lora / dora / pissa / rslora</span> |
There was a problem hiding this comment.
The comment lists pissa and rslora in lowercase, which matches the YAML values, but for consistency with the documentation and the CLI wizard's tutorial text (e.g., forgelm/wizard/_orchestrator.py:339), it is recommended to use the standard acronyms PiSSA and rsLoRA when referring to the methods in prose or comments.
| <span class="key">method</span>: <span class="string">"dora"</span> <span class="comment"># lora / dora / pissa / rslora</span> | |
| <span class="key">method</span>: <span class="string">"dora"</span> <span class="comment"># lora / dora / PiSSA / rsLoRA</span> |
There was a problem hiding this comment.
Accepted in commit f217314. Updated the YAML demo comment to # lora / DoRA / PiSSA / rsLoRA to mirror the academic-prose convention used in the CLI wizard tutorial at forgelm/wizard/_orchestrator.py:339.
The YAML value "dora" stays lowercase because LoraConfig.method is Literal["lora", "dora", "pissa", "rslora"] (forgelm/config.py:125) — operators must type the lowercase form to validate.
| <p data-i18n-html="compliance.gdpr.body"><code>--pii-mask</code> redacts emails, phones, credit cards, IBAN, national IDs before chunks land in JSONL.</p> | ||
| <div class="article-evidence"><b>forgelm/data_audit.py::mask_pii</b></div> | ||
| <p data-i18n-html="compliance.gdpr.body"><code>--pii-mask</code> redacts emails, phones, credit cards (Luhn-validated), IBAN, TR national ID, DE Personalausweis, FR SSN, US SSN before chunks land in JSONL.</p> | ||
| <div class="article-evidence"><b>forgelm/data_audit/</b> · <b>forgelm.mask_pii</b></div> |
There was a problem hiding this comment.
The evidence list mixes a directory path (forgelm/data_audit/) with a Python symbol (forgelm.mask_pii). For consistency with other Article cards that use file paths (e.g., forgelm/compliance.py), it might be clearer to reference the specific file implementing the PII masking logic.
| <div class="article-evidence"><b>forgelm/data_audit/</b> · <b>forgelm.mask_pii</b></div> | |
| <div class="article-evidence"><b>forgelm/data_audit/</b> · <b>forgelm/data_audit/masking.py</b></div> |
There was a problem hiding this comment.
Accepted in modified form in commit f217314.
The literal suggested path forgelm/data_audit/masking.py does not exist; mask_pii is defined at forgelm/data_audit/_pii_regex.py:127. Updated the evidence cell to point at the real file: forgelm/data_audit/ · forgelm/data_audit/_pii_regex.py — keeps the file-path convention used by the other Article cards while staying truthful.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@site/features.html`:
- Line 239: Update the text in site/features.html for the "forgelm safety-eval"
description: replace the incorrect filename reference "safety_evaluation.json"
with the actual output filename "safety_results.json" so the sentence reads that
safety-eval emits "safety_results.json" (keep the rest unchanged, including
references to --probes / --default-probes and safety_trend.jsonl).
In `@site/quickstart.html`:
- Line 154: The UI's "9 guided steps" count matches the JavaScript wizard's
STEPS array but the step identifiers and order differ from the Python
orchestrator (JS:
welcome,use-case,trainer,model,dataset,training,compliance,operations,review vs
Python:
welcome,use-case,model,strategy,trainer,dataset,training-params,compliance,evaluation),
causing UI/backend mismatch; fix by reconciling the canonical step list (choose
which implementation is authoritative) and then update the JavaScript STEPS
constant (and any i18n keys referenced in site/quickstart.html) to use the exact
step names and order used by the Python orchestrator (or vice versa), ensuring
the displayed labels, the counter text ("9 guided steps") and any code
referencing STEPS.length, step IDs, or navigation logic all use the same
identifiers (e.g., STEPS array, wizard navigation functions) so UI flow and
backend configuration align.
🪄 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: e44ae42a-92d5-44bd-aaee-14804fa35d12
📒 Files selected for processing (17)
docs/usermanuals/en/compliance/gdpr.mddocs/usermanuals/en/compliance/human-approval-gate.mddocs/usermanuals/tr/compliance/gdpr.mddocs/usermanuals/tr/compliance/human-approval-gate.mdforgelm/wizard/_orchestrator.pyforgelm/wizard/_state.pysite/compliance.htmlsite/contact.htmlsite/features.htmlsite/guide.htmlsite/index.htmlsite/js/translations.jssite/js/wizard.jssite/privacy.htmlsite/quickstart.htmlsite/terms.htmltools/check_no_analysis_refs.py
| <div class="wizard-spotlight-meta"> | ||
| <span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg> | ||
| <span data-i18n="quickstart.spotlight.meta1">7 guided steps</span></span> | ||
| <span data-i18n="quickstart.spotlight.meta1">9 guided steps</span></span> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify wizard step count in browser wizard matches documentation
# Count STEPS in site/js/wizard.js
echo "Checking site/js/wizard.js for STEPS array..."
rg -n "const STEPS\s*=" site/js/wizard.js -A 30
# Also verify the CLI wizard step count
rg -n "_STEPS.*Tuple\[_StepDef" forgelm/wizard/_orchestrator.py -A 12Repository: cemililik/ForgeLM
Length of output: 584
🏁 Script executed:
#!/bin/bash
# Check if site/js/wizard.js exists and how STEPS are defined
echo "=== Checking if site/js/wizard.js exists ==="
ls -la site/js/wizard.js 2>&1
echo ""
echo "=== Searching for STEPS definition in JavaScript (broader search) ==="
rg -n "STEPS" site/js/wizard.js 2>&1 | head -20
echo ""
echo "=== List all JavaScript files in site/js ==="
ls -la site/js/*.js 2>&1 | head -10Repository: cemililik/ForgeLM
Length of output: 1196
🏁 Script executed:
#!/bin/bash
# Extract and count the STEPS array from JavaScript
echo "=== Extracting STEPS array from site/js/wizard.js ==="
sed -n '938,1000p' site/js/wizard.js | head -80
echo ""
echo "=== Counting STEPS entries ==="
sed -n '938,1000p' site/js/wizard.js | grep -o '{' | wc -lRepository: cemililik/ForgeLM
Length of output: 3616
The HTML step count is correct, but step definitions differ critically between JavaScript and Python implementations.
The "9 guided steps" text (line 154) and counter total (line 373) correctly match the JavaScript wizard's STEPS.length, which contains 9 step objects. However, the JavaScript steps (welcome, use-case, trainer, model, dataset, training, compliance, operations, review) differ significantly from the Python orchestrator's steps (welcome, use-case, model, strategy, trainer, dataset, training-params, compliance, evaluation):
- Step names diverge: "training" (JS) vs "training-params" (Python), "operations" (JS) vs "strategy" (Python), "review" (JS) vs "evaluation" (Python)
- Step order differs in the middle sections
- This creates an inconsistency where the UI flow and backend configuration don't align
The UI count is accurate, but the underlying step definitions must be reconciled between the two implementations.
🤖 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 `@site/quickstart.html` at line 154, The UI's "9 guided steps" count matches
the JavaScript wizard's STEPS array but the step identifiers and order differ
from the Python orchestrator (JS:
welcome,use-case,trainer,model,dataset,training,compliance,operations,review vs
Python:
welcome,use-case,model,strategy,trainer,dataset,training-params,compliance,evaluation),
causing UI/backend mismatch; fix by reconciling the canonical step list (choose
which implementation is authoritative) and then update the JavaScript STEPS
constant (and any i18n keys referenced in site/quickstart.html) to use the exact
step names and order used by the Python orchestrator (or vice versa), ensuring
the displayed labels, the counter text ("9 guided steps") and any code
referencing STEPS.length, step IDs, or navigation logic all use the same
identifiers (e.g., STEPS array, wizard navigation functions) so UI flow and
backend configuration align.
There was a problem hiding this comment.
Skipped — divergence is by design and already documented inline (no functional defect).
The user-visible "9 guided steps" claim accurately matches STEPS.length = 9 in both wizards. The two surfaces produce identical generated YAML through different UX flows; the persistence stores are deliberately independent:
- CLI:
forgelm/wizard/_orchestrator.py::_STEPS(welcome, use-case, model, strategy, trainer, dataset, training-params, compliance, evaluation) → XDG cache JSON - Web:
site/js/wizard.js::STEPS(welcome, use-case, trainer, model, dataset, training, compliance, operations, review) →localStorage
STATE_VERSION = 3 (web) vs _STATE_VERSION = 1 (CLI) is also intentional and explicitly cross-referenced in code:
site/js/wizard.js:74-86— block comment naming the CLI counterpartforgelm/wizard/_state.py:145-156— block comment naming the web counterpartforgelm/wizard/_orchestrator.py:719-724— the canonical NOTE on the step-ID divergence
Reconciling step IDs would force a state-shape bump on at least one surface, risking replay breakage for in-progress wizard sessions on disk, with zero user-visible benefit. The two flows reach the same ForgeConfig-shaped YAML; that is the load-bearing contract.
A reviewer (the maintainer's PR-41 review verdict, §4) independently agreed: "I would not push back on the skip — reconciling step IDs would force a state-shape bump on at least one side and risk replay breakage … for zero user-visible benefit."
There was a problem hiding this comment.
@cemililik, understood — the concern is resolved by design. Both surfaces intentionally use independent step IDs and state schemas while converging on the same ForgeConfig-shaped YAML output; with the divergence cross-referenced at three code locations, there's nothing to reconcile. I'll record this for future reviews.
(∩`-´)⊃━☆゚.*・。゚
(\_/)
(•ᵕ•) noted!
/> >
✏️ Learnings added
Learnt from: cemililik
Repo: cemililik/ForgeLM PR: 41
File: site/quickstart.html:154-154
Timestamp: 2026-05-09T20:31:42.189Z
Learning: In the ForgeLM repository, the CLI wizard (`forgelm/wizard/_orchestrator.py::_STEPS`) and the in-browser wizard (`site/js/wizard.js::STEPS`) both have 9 steps but use deliberately different step IDs and order (CLI: welcome, use-case, model, strategy, trainer, dataset, training-params, compliance, evaluation → XDG cache JSON; Web: welcome, use-case, trainer, model, dataset, training, compliance, operations, review → localStorage). Their STATE_VERSION values also differ intentionally (_STATE_VERSION=1 CLI vs STATE_VERSION=3 web). Both flows produce identical ForgeConfig-shaped YAML output — that is the load-bearing contract. The divergence is documented inline at: site/js/wizard.js lines 74-86, forgelm/wizard/_state.py lines 145-156, and forgelm/wizard/_orchestrator.py lines 719-724. Reconciling step IDs would force a state-shape bump and risk replay breakage for in-progress sessions with zero user-visible benefit.
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.
Closes 3 of 4 inline review comments on PR #41; skips the 4th with a brief reason. Accepted (3): - coderabbit @ features.html:239 — safety-eval output filename was wrong: forgelm/safety.py:417 writes safety_results.json, not safety_evaluation.json. Fixed in HTML + all 6 i18n locales. - gemini @ index.html:542 — YAML demo comment "lora / dora / pissa / rslora" updated to "lora / DoRA / PiSSA / rsLoRA" to match the cross-surface academic-prose convention used in the wizard tutorial (forgelm/wizard/_orchestrator.py:339). The YAML *value* "dora" stays lowercase because the schema's Literal accepts lowercase. - gemini @ compliance.html:199 — Article 10 PII evidence row mixed a directory path (forgelm/data_audit/) with a Python symbol (forgelm.mask_pii); aligned with the file-path convention used by every other Article card. Gemini's literal suggestion (forgelm/data_audit/masking.py) does not exist — the real file is forgelm/data_audit/_pii_regex.py:127, so the evidence cell now points there. Skipped (1): - coderabbit @ quickstart.html:154 — wizard STEPS reconciliation between site/js/wizard.js and forgelm/wizard/_orchestrator.py. The divergence is by design and already documented inline at _orchestrator.py:719: both surfaces produce the same generated YAML through different UX flows (different stores: localStorage vs XDG cache; different preset-driven step ordering). Reconciling step IDs would force one surface's UX onto the other with no functional benefit; the user-visible "9 guided steps" counter accurately reflects the JS wizard's STEPS.length. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reviewer flagged pre-existing prose drift on two strings where the
en/tr versions describe a thicker mechanism than the four other
locales. Token-level claim parity now restored.
compliance.art14.body — de/fr/es/zh previously only described the
notification side-effect ("blocks model promotion until a human signs.
Webhook to your incident tool…") and never named the load-bearing CLI
surface (forgelm approve / forgelm reject + forgelm approvals + the
staging-directory mechanism). Rewritten to mirror en's wording — the
three CLI commands plus the staging-directory move now appear in
every locale. Token check across all 6 langs:
forgelm approve / reject / approvals — present.
privacy.body — de/fr/es/zh + (zh especially) were missing the entire
"Data-subject rights you can ship in your own pipeline" paragraph
that names forgelm reverse-pii (Article 15), forgelm purge
(Article 17), and the ISO 27001 / SOC 2 Type II alignment claim. The
paragraph was inserted into all four locales as a new <h2> section
between "The toolkit itself" and "Changes," matching en/tr's
information architecture. Token check across all 6 langs:
forgelm purge / reverse-pii / ISO 27001 — present.
This addresses the only "notable drift to flag" item in the PR-41
review verdict. Pre-existing prose drift, not introduced by this PR;
the wave-3 i18n batch never re-synced these two strings when the en/tr
versions were widened.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Two scopes bundled together since both are release-prep housekeeping on `development` ahead of the next PyPI tag: 1. Issue #37 — nightly pip-audit gate - `transformers` CVE-2026-1839 was failing the Supply-chain security workflow; published fix lives in 5.0.0rc3 (release candidate) and ForgeLM's pyproject pins `<5.0.0`. - Added `--ignore-vuln CVE-2026-1839` to `.github/workflows/nightly.yml` with multi-line rationale + remove-after condition. Per the policy in `tools/check_pip_audit.py` each ignore must carry a written justification; this one is reviewed at every release. 2. Release-prep doc refresh - CHANGELOG `[Unreleased]` rewritten in public-facing style (grouped by user-visible capability, no internal review-cycle / PR-letter / round-N terminology). Added entries for Phase 22 wizard parity-with-web, the site documentation correction sweep (PR #41), the working-memory directory policy, and the issue #37 stop-gap. - `docs/roadmap.md` + `docs/roadmap-tr.md` add Phase 22 + site sweep rows in the "Status at a glance" table; "Current state" sentence updated from the stale "release imminent" framing to reflect that v0.5.5 was paper-merged on main but the PyPI tag was deferred so the upcoming release can fold in the post- merge work. - `docs/roadmap/releases.md` marks v0.5.5 as "Merged on main; PyPI tag deferred"; new "Next PyPI release" section documents the upcoming release scope and surfaces the version-slot decision (`0.5.6` vs `0.6.0`) for the maintainer with rationale on each side. - `tools/check_no_analysis_refs.py` `_EXEMPT` list extended with `docs/roadmap/releases.md` (parallel to the CHANGELOG.md exempt for the policy-announcement entry that names the gitignored dirs verbatim). - `docs/roadmap/phase-12-6-closure-cycle.md` link to v0.5.5 section anchor updated to match the new heading. CI gauntlet (anchor resolution / bilingual parity / no-analysis-refs / yaml snippets / audit catalog / library API / numerical claims / wizard defaults / site claims / cli help / ruff / dry-run) verified clean. No code path or test changes; pure docs + workflow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promotes the [Unreleased] block into the [0.5.5] section under a new "Post-merge follow-up" subsection that captures the three PRs landed on top of the paper-merged closure cycle: - PR #40 (2026-05-08) — Phase 22 CLI wizard parity-with-web - PR #41 (2026-05-09) — Site documentation correction sweep + i18n parity backfill - PR #42 (2026-05-10) — Release-prep + nightly pip-audit gate fix + two review-absorption rounds The CHANGELOG [0.5.5] header date is bumped to 2026-05-10 (the actual PyPI release date) and a fresh empty [Unreleased] block is added at the top. __api_version__ stays at 1.0.0 — Phase 22 is a CLI/wizard surface change, not a Python library API addition; the 30-symbol forgelm.__all__ surface that this release anchors was already added during the Phase 12.6 closure cycle (paper-merged as v0.5.5). Roadmap (en + tr) marks v0.5.5 as released; "Latest release on PyPI" flipped from v0.5.0 to v0.5.5; "Current state" sentence simplified (no more "merged but tag deferred" framing). releases.md drops the "Next PyPI release (slot pending)" section since v0.5.5 now bundles everything that was staged in [Unreleased]. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>



Summary
forgelm/surface.compliance.html,index.htmlYAML demo,features.htmlgovernance cards) so a deployer auditor cannot find a path that disagrees with the code.What changed
CRITICAL — schema drift fixed
site/index.htmlhero YAML demo rewritten with realforgelm/config.pyfield names (num_train_epochs,per_device_train_batch_size,evaluation.benchmark.min_score,evaluation.safety.classifier,evaluation.require_human_approval, top-levelwebhook:).site/compliance.htmlartefact tree redrawn (compliance/+final_model/instead ofartifacts/,audit_log.jsonlat checkpoint root, ghostconfig_snapshot.yamlremoved).forgelm verify-auditquickstart example now points ataudit_log.jsonl, not the directory.compliance.config_hashandcompliance.human_approvalghost YAML keys replaced withforgelm verify-auditandevaluation.require_human_approval.forgelm.api→from forgelm import …with realforgelm.__all__symbols.forgelm quickstart byod→forgelm quickstart domain-expert.forgelm/data_audit.py→forgelm/data_audit/(Phase 14 package).HIGH — overclaims softened to match live behaviour
verify-annex-ivaudit-chain claim,safety-evalinput formats,--model-cardghost flag,forgelm purgedata-provenance manifest claim), W1 (wizardUSE_CASE_PRESETSsynced withquickstart.py::TEMPLATES).MEDIUM + LOW
docker-compose.yaml(was.yml), doctorpass / warn / fail(was green/yellow/red), Discord webhook, dpia-template ghost link, customer-support / code-assistant body softening (SFT-only), quickstart template parentheticals, JSON-LDoperatingSystem+ Windows on 8 pages, Last updated date refresh._STATE_VERSIONvs webSTATE_VERSIONdrift) documented inline so future readers don't read it as a sync bug.tools/check_no_analysis_refs.pyexempt list extended withCHANGELOG.mdfor the policy-announcement entry that quotes the gitignored dir names.Test plan
ruff check forgelm/ tools/ tests/— cleanruff format --check forgelm/ tools/ tests/— 178 files already formattedforgelm --config config_template.yaml --dry-run— DRY RUN COMPLETEpython3 tools/check_bilingual_parity.py --strict— 45 pairs matchpython3 tools/check_anchor_resolution.py --strict— 273 files cleanpython3 tools/check_cli_help_consistency.py --strict— 439 invocations matchpython3 tools/check_wizard_defaults_sync.py— schema matchpython3 tools/check_no_analysis_refs.py— clean (with new CHANGELOG.md exempt)python3 tools/check_site_claims.py— artefacts ✓ templates ✓ GPU ✓ versionpython3 tools/check_yaml_snippets.py— 23 / 323 validpython3 tools/check_doc_numerical_claims.py— cleanpython3 tools/check_audit_event_catalog.py— 36 ↔ 36python3 tools/check_library_api_doc.py— 30 ↔ 30python3 tools/check_bilingual_code_blocks.py— 45 pairs matchpytest tests/test_check_*.py— 92 passedpytest tests/test_wizard_phase22.py tests/test_wizard_byod.py— 139 passednodeparse ofsite/js/translations.js— all 6 langs at 731 keysNotes
tools/build_usermanuals.pywas re-run; the resultingsite/js/usermanuals/{en,tr}.jsbundles are gitignored artefacts so they don't appear in the diff.docs/analysis/code_reviews/2026-05-09_site_verification.md(gitignored working-memory per the policy added in the prior commit).forgelm/wizard/_orchestrator.pyandforgelm/wizard/_state.py.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation