Skip to content

[Wave 3] Medium — Module sweep: Compliance core: Annex IV, audit log, integrity manifest, provenance (part 2/2) #544

Open

Description

@cemililik

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 · reachability default · intent contract-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 out is run first, then forgelm --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 · reachability default · intent intended-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 · reachability default · intent contract-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 · reachability default · intent contract-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 runs forgelm 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 · reachability default · intent contract-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's forgelm approvals --pending queue (exit 0) no longer shows the run. CI's verify-audit --require-hmac stays green, so nothing flags the log. When the approver later tries forgelm 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 · reachability undocumented · intent intended-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.

Activity

  1. added
    bugSomething isn't working
    documentationImprovements or additions to documentation
    securitySecurity-relevant
    severity: mediumReal defect with limited reach or a workaround
    source: review-2026-10Found by the October 2026 code and documentation review
    wave: 3Roadmap wave 3: medium severity, module sweeps
    on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: complianceCode area: compliancebugSomething isn't workingdocumentationImprovements or additions to documentationsecuritySecurity-relevantseverity: mediumReal defect with limited reach or a workaroundsource: review-2026-10Found by the October 2026 code and documentation reviewwave: 3Roadmap wave 3: medium severity, module sweeps

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions