Repository navigation
[Wave 3] Medium — Module sweep: Compliance core: Annex IV, audit log, integrity manifest, provenance (part 2/2) #544
Description
Wave 3 · 7 finding(s) in 6 fix package(s). Fix these whenever a pull request touches this module ("clean the module you touch").
Findings
-
CR-A07-060 (code, Medium) — Article 10 governance report credits merged primary + extra_datasets statistics to the primary dataset, and extra_datasets, mix_ratio and the realised composition appear nowhere in it
severity Medium · reachabilitydefault· intentcontract-violation· confidence confirmed · independently confirmed · reproduced end to end
Failure scenario. Config: data.dataset_name_or_path=primary_text.jsonl (10 rows), extra_datasets=[extra_big.jsonl] (300 rows), mix_ratio=[0.9,0.1], governance block set.forgelm audit primary_text.jsonl --output outis run first, thenforgelm --config cfg.yaml(exit 0). compliance/data_governance_report.json says primary_dataset=primary_text.jsonl with train sample_count 36 and validation 4. In-process origin tagging of the same deterministic preparation shows 27 of the 36 train rows and 3 of the 4 validatio…
Where.forgelm/compliance.py:718-731(generate_data_governance_report body; the report dict is at 720-724 and the audit inlining at about 730-735),forgelm/compliance.py:643-651,forgelm/trainer.py:2095,forgelm/data.py:525-546(_merge_extra_datasets); _ensure_validation_split is at about 551-581, and the call site in prepare_dataset is about 701-710
Recommended fix. Replace primary_dataset with a 'sources' list (primary + each extra, with path and fingerprint reference). Record the declared mix_ratio and, per split, the realised row count per source. Mark the split statistics as 'post-merge, post-split'. Set a per-source audit coverage flag instead of a single data_audit_inlined bool, and emit governance_section_missing when any extra corpus is unaudited. Pu… -
CR-A07-063 (code, Medium) — Annex IV points with no key: human oversight §2(e), cybersecurity §2(h), §2(f), §4, §6, §7, §8, the §9 plan and most of §1. Only some are disclosed, and only on the overview page
severity Medium · reachabilitydefault· intentintended-but-harmful· confidence confirmed · independently confirmed · reproduced end to end
Failure scenario. A high-risk provider runs with require_human_approval: true and relies on annex_iv_metadata.json as its Annex IV index. The artefact is silent on the Art. 14 oversight measure ForgeLM actually enforced (§2(e)) and on cybersecurity (§2(h)). Nothing in annex-iv.md or the reference page tells the provider to author these points elsewhere. The verifier still reports '§1-9 fields populated'.
Where.forgelm/compliance.py:1491-1631,forgelm/compliance.py:1817-1867,docs/usermanuals/en/compliance/overview.md:125-139,docs/usermanuals/tr/compliance/overview.md:139
Recommended fix. Add a key for §2(e) fed from evaluation.require_human_approval and the approval outcome, and state §2(h) explicitly as not covered (or as operator-supplied). Move the gap disclosure into annex-iv.md and the reference page and extend it to every uncovered point: §1(b),(d),(e),(g),(h); §2(e),(f),(h); §4; §6; §7; §8; the §9 plan. Remove the contradictory '§6 post-market' label. -
CR-A07-064 (code, Medium) — deployer_instructions.md is labelled 'per EU AI Act Article 13' but covers only Art. 13(3)(b)(i)/(iii) and part of (b)(ii); (b)(iv)-(vii), (c), the lifetime/maintenance part of (e) and (f) are absent…
severity Medium · reachabilitydefault· intentcontract-violation· confidence confirmed · independently confirmed · reproduced end to end
Failure scenario. A provider ships deployer_instructions.md as its Art. 13 instructions for use because ForgeLM labels it so. A market-surveillance review finds that the training-data information, log-handling mechanism, expected lifetime/maintenance and output-interpretation guidance required by Art. 13(3)(b)(vi), (f), (e) and (b)(vii) are absent.
Where.forgelm/compliance.py:1681-1767,forgelm/compliance.py:1701,forgelm/compliance.py:1739-1749,docs/reference/compliance_summary.md:30-31
Recommended fix. Either: - relabel the file as a partial Art. 13 starter, listing the uncovered (3)(b)(iv)-(vii), (c), (e) and (f) items in the file and the docs; or - populate what ForgeLM knows: data_provenance for (b)(vi), the approval-gate state for (d), the audit-log location and verify-audit for (f), and a vulnerable-groups statement for (b)(v). -
CR-A07-065 (code, Medium) — The audit writer and verifier split lines differently: a raw U+2028/U+2029/U+0085 on the tail makes the next genuine append break the chain
severity Medium · reachabilitydefault· intentcontract-violation· confidence confirmed · independently confirmed · reproduced end to end
Failure scenario. Someone with write access to output_dir re-encodes an escaped line separator in the last audit record (for example in an approver's comment) as the raw character. The nightly verify-audit --require-hmac sweep and verify-annex-iv --pipeline still pass. The next approver runsforgelm reject. From then on verify-audit exits 6 with 'chain broken' at the approver's own line, and Tier 3 reports the pipeline as contradicted. The forensic trail points at the approver's record instead of the planted c…
Where.forgelm/compliance.py:326(confirmed),forgelm/compliance.py:315,forgelm/compliance.py:2658,forgelm/compliance.py:2576(confirmed)
Recommended fix. Give the writer, the verifier, Tier 3 and _audit_log_reader one shared record splitter that works on bytes and splits on b'\n' only. Never use str.splitlines() on audit data. Make the writer's chain-head read hash exactly what the verifier hashes, and have it refuse (as the torn-tail guard at compliance.py:288-294 does) a last record that is not a JSON object or that contains \r or a Unicode line… -
CR-A07-066 (code, Medium) — A lone CR in place of an LF passes verify-audit --require-hmac and Tier 3, but the LF-only approval reader merges the two records: approvals --pending silently drops a pending run (exit 0), --show fi…
severity Medium · reachabilitydefault· intentcontract-violation· confidence confirmed · independently confirmed · reproduced end to end
Failure scenario. A principal with write access to the output dir turns one '\n' into '\r' just before a run's human_approval.required record. The approver'sforgelm approvals --pendingqueue (exit 0) no longer shows the run. CI'sverify-audit --require-hmacstays green, so nothing flags the log. When the approver later triesforgelm approve, it is refused as 'corrupted', while the integrity tool says the log is intact.
Where.forgelm/compliance.py:2658,forgelm/compliance.py:2648-2660,forgelm/compliance.py:3445,forgelm/cli/subcommands/_audit_log_reader.py:167-182
Recommended fix. Use one record splitter (bytes, LF only) for the verifier, Tier 3, iter_audit_events and the purge readers. Have the verifier reject a record that contains a bare \r, since the writer never emits one, rather than treating it as a record boundary. Have approvals --pending surface skipped or malformed lines in its JSON envelope (as --show does with corrupted/corruption_detail) instead of exiting 0… -
CR-A07-086 (code, Low) — Behaviour-changing env vars outside the YAML, two undocumented, contradict 'No hidden env-var flags'
severity Low · reachabilityundocumented· intentintended-but-harmful· confidence likely · single reviewer · reproduced end to end
Failure scenario. An auditor reads the README's 'no hidden env-var flags' and does not know that FORGELM_ALLOW_AUDIT_REROOT=1 in the environment silently authorises a fresh audit chain over a truncated one (the ERROR line still fires).
Where.forgelm/compliance.py:427,forgelm/data_audit/_orchestrator.py:221-223,README.md:16,docs/product_strategy.md:43
Recommended fix. Document FORGELM_ALLOW_AUDIT_REROOT in the audit/verify reference (EN+TR), soften the README claim to 'no hidden flags for training behaviour', and move the test hook behind a test-only seam (for example, an injected callable) instead of an env var in shipped code. -
↳ same root cause: DOC-D4B03-004 (docs, Medium) — CLAUDE.md: misleading — Principle 1: 'No env-var sniffing for behaviour (only for secrets). No hardcoded feature flags.'
severity Medium
Where.CLAUDE.md:114· type: misleading
The document says. Principle 1: 'No env-var sniffing for behaviour (only for secrets). No hardcoded feature flags.'
What the code does. Several environment variables select behaviour. HF_HUB_OFFLINE, HF_DATASETS_OFFLINE and TRANSFORMERS_OFFLINE force offline mode (model.py:90-93, data.py:136-147). FORGELM_ALLOW_AUDIT_REROOT lets an audit chain be deliberately re-rooted (compliance.py:407,427). FORGELM_ALLOW_ANONYMOUS_OPERATOR (compliance.py:219, approve.py:161, doctor.py:896), FORGELM_GGUF_CONVERTER (export.py:100) and HF_ENDPO…
Code references.forgelm/compliance.py:219,forgelm/compliance.py:407,forgelm/export.py:100,forgelm/model.py:90-93
Proposed correction. Reword: 'Behaviour comes from validated YAML/CLI. The only environment inputs are secrets and a small documented set of operator opt-ins (FORGELM_ALLOW*, FORGELM_GGUF_CONVERTER, HF*OFFLINE, HF_ENDPOINT, FORGELM_OPERATOR).' In code, move the FORGELM_AUDIT_TEST_WORKER_RAISES hook out of the production worker.
Done when
- Every finding above is fixed or closed with a reason (tick it here).
- Code fixes carry a test; doc fixes update the Turkish mirror in the same PR.
Found by the October 2026 ForgeLM code and documentation review against commit cab2947. Code links point at that commit; line numbers may have moved since. Finding IDs (CR-…, DOC-…, TECH-…) are stable references for this backlog.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity