From 43ed8427a2d652e876088fb273c56e23d6b593da Mon Sep 17 00:00:00 2001 From: Cemil ILIK Date: Sat, 17 Oct 2026 19:48:42 +0300 Subject: [PATCH 1/5] chore: add community-health files for contributor intake Add the repository files a public project is expected to carry so that a new contributor can find the rules and the ownership map without asking: - CITATION.cff so ForgeLM can be cited; version/date-released are omitted on purpose to avoid a second copy of the release version literal. - .github/CODEOWNERS routes reviews; branch protection does not require a code-owner review, so an unresponsive owner cannot stall a PR. - .github/dependabot.yml surfaces dependency updates upstream of the pip-audit and nightly CVE checks; Python minor/patch bumps are grouped. - GOVERNANCE.md records the maintainer-led model and the path to a reviewer and a maintainer role. - MAINTAINERS.md names the current maintainer and the review cadence for first-time contributors. - .github/ISSUE_TEMPLATE/documentation.yml gives docs reports a home, since the project's docs are a first-class contribution area. No behaviour changes; adds no imports and no dependencies. --- .github/CODEOWNERS | 12 +++ .github/ISSUE_TEMPLATE/documentation.yml | 47 +++++++++++ .github/dependabot.yml | 44 ++++++++++ CITATION.cff | 33 ++++++++ GOVERNANCE.md | 101 +++++++++++++++++++++++ MAINTAINERS.md | 40 +++++++++ 6 files changed, 277 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/documentation.yml create mode 100644 .github/dependabot.yml create mode 100644 CITATION.cff create mode 100644 GOVERNANCE.md create mode 100644 MAINTAINERS.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..95ea2f0a --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,12 @@ +# Code owners for ForgeLM. +# +# CODEOWNERS asks the owner of a changed path for a review when a pull request +# is opened. It does not block a merge on its own: branch protection for +# `development` does not require code-owner reviews, so an unresponsive owner +# cannot stall a contribution. See docs/standards/code-review.md for the review +# standard and GOVERNANCE.md for how ownership is granted. +# +# The project currently has one maintainer; each area gets its own owner once a +# co-maintainer takes responsibility for it (see MAINTAINERS.md). + +* @cemililik diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 00000000..0d76dd1d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,47 @@ +name: Documentation +description: Report a documentation error, or propose an improvement to a guide or its Turkish mirror +labels: ["documentation", "needs-triage"] +body: + - type: markdown + attributes: + value: | + Thanks for improving the docs! One correction per issue is easiest to review. + If a command or example is wrong, telling us the page you were reading makes + it much faster to find. Documentation pull requests are welcome directly + (see [CONTRIBUTING.md](https://github.com/HodeTech/ForgeLM/blob/development/CONTRIBUTING.md)). + + - type: input + id: page + attributes: + label: Page or file + description: The docs-site URL or the repository path you were reading. + placeholder: docs/guides/quickstart.md — or https://hodetech.github.io/ForgeLM/ + validations: + required: true + + - type: textarea + id: problem + attributes: + label: What is wrong or missing? + description: What does the page say, and what does the reader need instead? + validations: + required: true + + - type: textarea + id: suggestion + attributes: + label: Suggested wording (optional) + description: If you already know the fix, propose the text. We will tidy the language if needed. + + - type: dropdown + id: language + attributes: + label: Which copy is affected? + description: User-facing docs are maintained as an English page and a Turkish mirror. + options: + - English + - Turkish (or another mirror) + - Both + - Not sure + validations: + required: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..0a237f78 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,44 @@ +# Dependabot configuration for ForgeLM. +# +# Dependabot opens a pull request when a pinned dependency has a newer release. +# It is the upstream half of the supply-chain story: `tools/check_pip_audit.py` +# and the nightly CVE job catch known advisories, and these pull requests make +# the fix reachable. Minor and patch bumps for Python are grouped to keep the +# noise low; major bumps stay individual so they get a deliberate review. +# +# The `dependencies` label is already part of the backlog vocabulary +# (see CONTRIBUTING.md); `area: packaging-ci` routes the pull request to the +# right area. + +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "area: packaging-ci" + commit-message: + prefix: "chore(deps)" + groups: + python-minor-and-patch: + patterns: + - "*" + update-types: + - "minor" + - "patch" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "area: packaging-ci" + commit-message: + prefix: "chore(ci)" diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 00000000..1d213ea6 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,33 @@ +cff-version: 1.2.0 +message: "If you use ForgeLM in your work, please cite it using the metadata below." +title: "ForgeLM" +abstract: >- + Config-driven LLM fine-tuning: validated YAML in, a fine-tuned model and an + evidence trail out. Covers SFT, DPO, SimPO, KTO, ORPO and GRPO, with optional + dataset auditing, safety evaluation, evaluation gates, human approval and + EU AI Act compliance artifacts. The same configuration runs from a terminal, + a notebook, or a CI/CD pipeline. +type: software +authors: + - name: "ForgeLM Contributors" +repository-code: "https://github.com/HodeTech/ForgeLM" +url: "https://hodetech.github.io/ForgeLM/" +license: Apache-2.0 +keywords: + - llm + - fine-tuning + - lora + - qlora + - peft + - trl + - dpo + - grpo + - reproducibility + - mlops + - eu-ai-act + - ai-governance +# `version` and `date-released` are intentionally omitted. They would be a +# second copy of the release version, which `forgelm/_version.py`, `pyproject.toml` +# and CHANGELOG.md already carry, and nothing would keep the copies in sync. +# Add them together with a release-checklist step (or a guard) if citations +# need to name a specific release. diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 00000000..b5a64278 --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1,101 @@ +# ForgeLM Governance + +> **How decisions are made in ForgeLM, who makes them, and how you can take on +> more responsibility over time.** For how to contribute, see +> [CONTRIBUTING.md](CONTRIBUTING.md); for behaviour expectations, see +> [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). + +## Current model + +ForgeLM is **maintainer-led**. The project has a small group of maintainers who +are accountable for the code, the standards and the releases — today, one +(see [MAINTAINERS.md](MAINTAINERS.md)). There is no foundation and no steering +committee; the goal of this document is not to describe a large organisation but +to make the path into one explicit. + +Three principles shape every decision: + +1. **The standards are the rulebook.** `docs/standards/` holds the engineering + standards, `docs/roadmap/` holds what ships next, and the + [CHANGELOG.md](CHANGELOG.md) records what shipped. A decision that changes + behaviour is written into one of them; a decision that exists only in a chat + is not a decision. +2. **Reliability before features.** A capability ships with tests, docs and CI + coverage, or it does not ship. See + [docs/standards/testing.md](docs/standards/testing.md). +3. **Public reasoning.** Non-trivial proposals, breaking changes and anything + that changes a documented contract are discussed in an **issue** before a + pull request is opened, so the reasoning is reviewable and linkable. + +## Roles + +| Role | What they do | How it is granted | +|---|---|---| +| **Contributor** | Reports bugs, opens pull requests, reviews others' changes, improves docs | Anyone; no appointment | +| **Reviewer** | Reviews pull requests in an area and confirms findings | A maintainer says so in an issue, after several helpful reviews | +| **Maintainer** | Sets direction, merges to `development`, cuts releases, holds the standards | A maintainer invites them (see below) | + +Everyone contributing is bound by the +[Code of Conduct](CODE_OF_CONDUCT.md) and asked to follow the +[code-review standard](docs/standards/code-review.md). + +## How decisions are made + +- **Routine changes** — bug fixes, documentation and mirror updates, dependency + bumps — are decided in the pull request. One maintainer approval merges them. +- **Non-trivial changes** — a new config field, a new module, a new optional + dependency, a change to an exit code, the audit-event vocabulary or a + documented guarantee — start as an issue. Work that has no issue may be asked + to open one first, so the design is agreed before code is written. If the + change is larger than one issue, it becomes a roadmap phase under + [docs/roadmap/](docs/roadmap/). +- **Breaking changes** to the YAML schema or the CLI contract require a + deprecation period. Removing a YAML field is a MAJOR change; the target + release is single-sourced in `forgelm/config.py` and the + [release standard](docs/standards/release.md) governs the sequence. +- **Disagreement** is resolved by discussion on the issue. If a consensus does + not form, the maintainer decides and records the reasoning in the issue and, + when it sets a lasting constraint, in + [docs/roadmap/risks-and-decisions.md](docs/roadmap/risks-and-decisions.md). +- **Security reports** do not follow this path. They go through a private + advisory as [SECURITY.md](SECURITY.md) describes. + +## Becoming a maintainer + +There is no exam and no vote. A **reviewer** becomes a **maintainer** when a +current maintainer invites them, and that invitation is normally offered when +all of the following hold: + +- they have landed a handful of pull requests across more than one area; +- they have reviewed other people's pull requests with useful, specific + feedback, and respected the standards while doing so; +- they have shown judgement on the edge cases — an error path, a documented + contract, a supply-chain or compliance question; +- they are willing to be reachable, and to triage issues and review pull + requests on a predictable cadence rather than only when they feel like it. + +Area ownership follows the same idea: `MAINTAINERS.md` names who owns which +area, and `.github/CODEOWNERS` routes reviews there. A maintainer who becomes +unavailable is asked whether they want to step back; the project prefers an +accurate list over a flattering one, and stepping back is not held against +anyone. + +## Releases + +Releases are cut from `main` by a maintainer, following +[docs/standards/release.md](docs/standards/release.md). `development` is the +integration branch and the default branch; changes land there first and reach +`main` through a release pull request. Only maintainers merge to `main` and tag +releases. + +## Changing this document + +This document is a normal file in the repository: propose a change with a pull +request, and explain the reasoning in the pull request description. + +## Attribution + +The shape of this document — a written role ladder, area ownership, and the +"decide in an issue, record in the standards" rule — follows common practice in +established open-source projects; it is adapted, not copied, to ForgeLM's +config-driven and evidence-first way of working. diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 00000000..6e2238d2 --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,40 @@ +# ForgeLM Maintainers + +> **Who maintains ForgeLM, what each of them owns, and how to reach them.** +> See [GOVERNANCE.md](GOVERNANCE.md) for how the roles work and how to take one +> on, and [CONTRIBUTING.md](CONTRIBUTING.md) for how to contribute. + +## Current maintainers + +| GitHub | Areas | Reachable for | +|---|---|---| +| [@cemililik](https://github.com/cemililik) | All areas — trainer, CLI, config, data audit, safety, compliance, verify, docs, site, packaging & CI | Triage, design questions, reviews, releases | + +The project has a single maintainer today. When a co-maintainer takes +responsibility for an area, they are added here and to +[`.github/CODEOWNERS`](.github/CODEOWNERS), which routes reviews for that area +to them. + +## How to reach a maintainer + +- **A question or a bug** — open an + [issue](https://github.com/HodeTech/ForgeLM/issues/new/choose) or start a + [discussion](https://github.com/HodeTech/ForgeLM/discussions). Asking in public + means the answer is searchable for the next person. +- **A security vulnerability** — never in public. Use the repository's + **Security** tab, as [SECURITY.md](SECURITY.md) describes. +- **Anything covered by the Code of Conduct** — `forgelm@hodetech.io`. + +## Review cadence + +Issues are triaged and pull requests are reviewed on a best-effort basis, but +the project aims to give every **first-time contributor** a reply within a +couple of days — an unanswered first pull request is the most expensive thing a +young project can ship. If a pull request has not been reviewed for a while, a +polite nudge on the pull request is welcome; it is not rude. + +## Contributors + +Everyone who has contributed is credited by GitHub's contributors graph and in +the project's history. This file names maintainers and area owners only; it is +not the contributor list. From 91b257a708e16ea4304e326e1714335b1aa53be7 Mon Sep 17 00:00:00 2001 From: Cemil ILIK Date: Sat, 17 Oct 2026 20:29:45 +0300 Subject: [PATCH 2/5] chore: address review findings on the community-health files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MAINTAINERS.md: replace the CoC address with a pointer to the Code of Conduct's enforcement section (A-01). `forgelm@hodetech.io` does not resolve (NXDOMAIN at the TLD's own servers); the address is pre-existing in CODE_OF_CONDUCT.md and its replacement is a separate decision. - check_readme_links / check_source_path_refs: cover GOVERNANCE.md, MAINTAINERS.md, SECURITY.md and CODE_OF_CONDUCT.md, so the new root files are guarded the way the PR claimed (D-01, E-04). Tests updated for the wider surface set. - CODEOWNERS: remove the "an unresponsive owner cannot stall" claim, which is untrue with one maintainer (E-06), document last-match-wins (F-03), and pin the scaffolding paths so an area owner cannot silently take them (B-07). - CITATION.cff: correct the rationale comment — _version.py carries no version literal (it reads pyproject via importlib.metadata) and tools/update_site_version.py already guards the site copy (C-01, F-13); align the abstract with README's "audit trail" wording (C-05); ship the file in the sdist via MANIFEST.in (C-08). - GOVERNANCE.md: state the actual merge conditions instead of "one maintainer approval merges them" (A-02, F-01); point at the roadmap's product principles rather than restating a conflicting trio (A-09); drop the unverifiable attribution paragraph (A-21). - MAINTAINERS.md: questions belong in Discussions, not the issue tracker (A-16); one 72-hour reply target shared with SECURITY.md instead of two SLAs (A-17); the areas column mirrors the `area:` label vocabulary (A-19). - documentation.yml / config.yml: distinct chooser entries (F-06, E-08), EN and TR only since no other mirror exists (B-06, F-07), and a page-level placeholder (F-09). - CHANGELOG.md: record the additions under [Unreleased] (D-05). - README.md: link GOVERNANCE.md, MAINTAINERS.md and CITATION.cff (E-07, F-12). Not addressed here, pending a decision: the Dependabot scope (B-01/B-02/D-02), the reviewer role (A-04/F-10), maintainer access and continuity (F-02/A-03/A-06), and whether CITATION.cff should carry version/date (C-01 option b). --- .github/CODEOWNERS | 27 +++++++++++----- .github/ISSUE_TEMPLATE/config.yml | 4 +-- .github/ISSUE_TEMPLATE/documentation.yml | 17 ++++++----- CHANGELOG.md | 12 ++++++++ CITATION.cff | 16 ++++++---- GOVERNANCE.md | 24 +++++++-------- MAINTAINERS.md | 39 ++++++++++++++---------- MANIFEST.in | 1 + README.md | 5 +++ tests/test_check_readme_links.py | 4 +++ tools/check_readme_links.py | 4 +++ tools/check_source_path_refs.py | 13 +++++++- 12 files changed, 114 insertions(+), 52 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 95ea2f0a..e0ff20ab 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,12 +1,25 @@ # Code owners for ForgeLM. # -# CODEOWNERS asks the owner of a changed path for a review when a pull request -# is opened. It does not block a merge on its own: branch protection for -# `development` does not require code-owner reviews, so an unresponsive owner -# cannot stall a contribution. See docs/standards/code-review.md for the review +# When a pull request is opened, GitHub requests a review from the owner of each +# path it changes. This file only routes those review requests: whether a review +# is *required* before merging is a branch-protection setting, not anything an +# entry here can turn on. See docs/standards/code-review.md for the review # standard and GOVERNANCE.md for how ownership is granted. # -# The project currently has one maintainer; each area gets its own owner once a -# co-maintainer takes responsibility for it (see MAINTAINERS.md). +# These rules are evaluated last-match-wins, so a more specific pattern placed +# below `*` overrides it. When an area gets its own owner, add their line below +# the default rather than replacing it, so the default owner stays on every path +# an area owner does not name. GitHub does not request a review for a draft or a +# draft pull request. -* @cemililik +* @cemililik + +# Repository scaffolding and policy files stay with the default owner even after +# an area owner is added, because these paths define the rules the area owners +# work under. +/.github/ @cemililik +/CONTRIBUTING.md @cemililik +/GOVERNANCE.md @cemililik +/MAINTAINERS.md @cemililik +/SECURITY.md @cemililik +/pyproject.toml @cemililik diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index c3756212..acb566f8 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,9 +3,9 @@ contact_links: - name: Report a security vulnerability url: https://github.com/HodeTech/ForgeLM/security/advisories/new about: Report vulnerabilities privately, never in a public issue (see SECURITY.md) - - name: Documentation + - name: Browse the documentation url: https://github.com/HodeTech/ForgeLM/tree/main/docs - about: Check the docs and guides before opening an issue + about: Read the docs and guides before opening a documentation issue - name: Discussions (Q&A) url: https://github.com/HodeTech/ForgeLM/discussions about: Ask questions and get help from the community diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml index 0d76dd1d..ef234fa2 100644 --- a/.github/ISSUE_TEMPLATE/documentation.yml +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -6,16 +6,19 @@ body: attributes: value: | Thanks for improving the docs! One correction per issue is easiest to review. - If a command or example is wrong, telling us the page you were reading makes - it much faster to find. Documentation pull requests are welcome directly - (see [CONTRIBUTING.md](https://github.com/HodeTech/ForgeLM/blob/development/CONTRIBUTING.md)). + + User-facing documentation is kept as an English page **and** a Turkish + mirror, and the two are updated together — see + [CONTRIBUTING.md](https://github.com/HodeTech/ForgeLM/blob/development/CONTRIBUTING.md). + Tell us below which copy you were reading. Documentation pull requests are + welcome directly. - type: input id: page attributes: label: Page or file - description: The docs-site URL or the repository path you were reading. - placeholder: docs/guides/quickstart.md — or https://hodetech.github.io/ForgeLM/ + description: The repository path or the documentation-site page you were reading. + placeholder: docs/guides/quickstart.md — or the Quick start page on the docs site validations: required: true @@ -37,10 +40,10 @@ body: id: language attributes: label: Which copy is affected? - description: User-facing docs are maintained as an English page and a Turkish mirror. + description: User-facing docs are maintained as an English page and a Turkish mirror. An issue that needs mirror work is labelled `i18n` when it is triaged. options: - English - - Turkish (or another mirror) + - Turkish - Both - Not sure validations: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c510f6d..3aa89750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,18 @@ All notable changes to ForgeLM are documented here. and valid port; schemeless addresses are rejected instead of silently becoming `` in evidence. Use `https://monitor.example.com:8443/plan` or an `endpoint_env` name (#93). +### Added + +- `CITATION.cff`, so the repository can be cited through GitHub's "Cite this + repository" panel (#964). +- `GOVERNANCE.md` and `MAINTAINERS.md` at the repository root, recording how + decisions are made, how the maintainer roles work, and which areas the current + maintainer owns (#964). +- `.github/dependabot.yml`, so dependency updates arrive as reviewed pull requests + rather than waiting for a manual version check; `.github/CODEOWNERS` to route + review requests without gating a merge; and a Documentation issue template, since + the issue chooser previously offered only a bug and a feature form (#964). + ### Changed - Record monitoring default provenance in `defaulted_fields` and mark literal URL projection with diff --git a/CITATION.cff b/CITATION.cff index 1d213ea6..9459c30c 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -3,7 +3,7 @@ message: "If you use ForgeLM in your work, please cite it using the metadata bel title: "ForgeLM" abstract: >- Config-driven LLM fine-tuning: validated YAML in, a fine-tuned model and an - evidence trail out. Covers SFT, DPO, SimPO, KTO, ORPO and GRPO, with optional + audit trail out. Covers SFT, DPO, SimPO, KTO, ORPO and GRPO, with optional dataset auditing, safety evaluation, evaluation gates, human approval and EU AI Act compliance artifacts. The same configuration runs from a terminal, a notebook, or a CI/CD pipeline. @@ -26,8 +26,12 @@ keywords: - mlops - eu-ai-act - ai-governance -# `version` and `date-released` are intentionally omitted. They would be a -# second copy of the release version, which `forgelm/_version.py`, `pyproject.toml` -# and CHANGELOG.md already carry, and nothing would keep the copies in sync. -# Add them together with a release-checklist step (or a guard) if citations -# need to name a specific release. +# `version` and `date-released` are intentionally omitted for now: the released +# version is single-sourced in `pyproject.toml` (read at runtime by +# `forgelm/_version.py` via `importlib.metadata`, which carries no literal of its +# own) and the site's displayed version is derived from `CHANGELOG.md` by +# `tools/update_site_version.py --check`. This file is not one of that tool's +# targets, so a version here would be an un-guarded copy that no check keeps in +# sync — exactly what `docs/standards/release.md` exists to prevent. Extending the +# tool to rewrite this file (and adding a Zenodo DOI for citable releases) is +# tracked separately. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index b5a64278..472b9d34 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -13,17 +13,17 @@ are accountable for the code, the standards and the releases — today, one committee; the goal of this document is not to describe a large organisation but to make the path into one explicit. -Three principles shape every decision: +The project's product principles — reliability before features, enterprise +differentiation over feature parity, every capability config-driven and testable +— are recorded in [`docs/roadmap.md`](docs/roadmap.md) and are not restated here. +How decisions get made rests on two rules: 1. **The standards are the rulebook.** `docs/standards/` holds the engineering standards, `docs/roadmap/` holds what ships next, and the [CHANGELOG.md](CHANGELOG.md) records what shipped. A decision that changes behaviour is written into one of them; a decision that exists only in a chat is not a decision. -2. **Reliability before features.** A capability ships with tests, docs and CI - coverage, or it does not ship. See - [docs/standards/testing.md](docs/standards/testing.md). -3. **Public reasoning.** Non-trivial proposals, breaking changes and anything +2. **Public reasoning.** Non-trivial proposals, breaking changes and anything that changes a documented contract are discussed in an **issue** before a pull request is opened, so the reasoning is reviewable and linkable. @@ -42,7 +42,12 @@ Everyone contributing is bound by the ## How decisions are made - **Routine changes** — bug fixes, documentation and mirror updates, dependency - bumps — are decided in the pull request. One maintainer approval merges them. + bumps — are decided in the pull request. A pull request merges once the + required status checks pass, every review conversation is resolved, and a + maintainer has reviewed it. The exact gate is a branch-protection setting, not + this document. While the project has one maintainer, that maintainer merges + their own pull requests under the same conditions, which is what + [docs/standards/code-review.md](docs/standards/code-review.md) records. - **Non-trivial changes** — a new config field, a new module, a new optional dependency, a change to an exit code, the audit-event vocabulary or a documented guarantee — start as an issue. Work that has no issue may be asked @@ -92,10 +97,3 @@ releases. This document is a normal file in the repository: propose a change with a pull request, and explain the reasoning in the pull request description. - -## Attribution - -The shape of this document — a written role ladder, area ownership, and the -"decide in an issue, record in the standards" rule — follows common practice in -established open-source projects; it is adapted, not copied, to ForgeLM's -config-driven and evidence-first way of working. diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 6e2238d2..e9d6171d 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -8,33 +8,40 @@ | GitHub | Areas | Reachable for | |---|---|---| -| [@cemililik](https://github.com/cemililik) | All areas — trainer, CLI, config, data audit, safety, compliance, verify, docs, site, packaging & CI | Triage, design questions, reviews, releases | +| [@cemililik](https://github.com/cemililik) | All areas — the repository's `area:` label set (cli, compliance, config, data-audit, dev-tooling, eval-gates, gdpr-approval, ingestion, integrations, model-data, onboarding, operator-cmds, packaging-ci, pipeline, post-training, site, trainer, verify) | Triage, design questions, reviews, releases | The project has a single maintainer today. When a co-maintainer takes responsibility for an area, they are added here and to -[`.github/CODEOWNERS`](.github/CODEOWNERS), which routes reviews for that area -to them. +[`.github/CODEOWNERS`](.github/CODEOWNERS), which routes reviews for that area to +them. The "Areas" column mirrors the repository's `area:` labels, so an issue +labelled `area: site` and this table name the same area. ## How to reach a maintainer -- **A question or a bug** — open an - [issue](https://github.com/HodeTech/ForgeLM/issues/new/choose) or start a - [discussion](https://github.com/HodeTech/ForgeLM/discussions). Asking in public - means the answer is searchable for the next person. +- **A bug or a feature request** — open an + [issue](https://github.com/HodeTech/ForgeLM/issues/new/choose). +- **A question** — start a + [discussion](https://github.com/HodeTech/ForgeLM/discussions); questions are not + filed on the public issue tracker. Asking in public means the answer is + searchable for the next person. - **A security vulnerability** — never in public. Use the repository's **Security** tab, as [SECURITY.md](SECURITY.md) describes. -- **Anything covered by the Code of Conduct** — `forgelm@hodetech.io`. +- **Anything covered by the Code of Conduct** — follow the enforcement section of + the [Code of Conduct](CODE_OF_CONDUCT.md#enforcement). ## Review cadence -Issues are triaged and pull requests are reviewed on a best-effort basis, but -the project aims to give every **first-time contributor** a reply within a -couple of days — an unanswered first pull request is the most expensive thing a -young project can ship. If a pull request has not been reviewed for a while, a -polite nudge on the pull request is welcome; it is not rude. +Issues are triaged and pull requests are reviewed on a best-effort basis, with an +initial-reply target of **72 hours** — the same window [SECURITY.md](SECURITY.md) +commits to for a vulnerability report, so the project has one number rather than +two. An unanswered first pull request is the most expensive thing a young project +can ship, so a **first-time contributor**'s pull request is answered first. If a +pull request has not been reviewed for a while, a polite nudge on it is welcome; +it is not rude. ## Contributors -Everyone who has contributed is credited by GitHub's contributors graph and in -the project's history. This file names maintainers and area owners only; it is -not the contributor list. +This file names maintainers and area owners only; it is not the contributor list. +Everyone whose work is merged appears in the repository's commit history and on +its GitHub contributors page, and non-maintainer contributions are credited in +the release notes. diff --git a/MANIFEST.in b/MANIFEST.in index f1409d9a..1280670a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ include LICENSE include README.md include CHANGELOG.md +include CITATION.cff include config_template.yaml recursive-include configs *.json *.jsonl diff --git a/README.md b/README.md index 19e1b35d..14a000cd 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,11 @@ feature. Start small; you do not need a GPU to run the unit tests or documentati [Engineering standards](https://github.com/HodeTech/ForgeLM/tree/development/docs/standards). Report vulnerabilities privately using [SECURITY.md](https://github.com/HodeTech/ForgeLM/blob/main/SECURITY.md). +Who decides what, and who owns which area: [GOVERNANCE.md](https://github.com/HodeTech/ForgeLM/blob/main/GOVERNANCE.md) · +[MAINTAINERS.md](https://github.com/HodeTech/ForgeLM/blob/main/MAINTAINERS.md). +To cite ForgeLM, use GitHub's **Cite this repository** button or +[`CITATION.cff`](https://github.com/HodeTech/ForgeLM/blob/main/CITATION.cff). + ## License **Code:** [Apache 2.0](https://github.com/HodeTech/ForgeLM/blob/main/LICENSE). diff --git a/tests/test_check_readme_links.py b/tests/test_check_readme_links.py index 7b9b822d..029963de 100644 --- a/tests/test_check_readme_links.py +++ b/tests/test_check_readme_links.py @@ -59,6 +59,10 @@ def _make_tree(tmp_path: Path, readme: str, contributing: str = "# Contributing\ """Write a minimal repo-shaped tree and return its root.""" (tmp_path / "README.md").write_text(readme, encoding="utf-8") (tmp_path / "CONTRIBUTING.md").write_text(contributing, encoding="utf-8") + # Every surface in `guard._SURFACES` must exist, or the guard reports it as + # missing from the checkout. Keep this in step with that tuple. + for surface in ("CODE_OF_CONDUCT.md", "GOVERNANCE.md", "MAINTAINERS.md", "SECURITY.md"): + (tmp_path / surface).write_text("# stub\n", encoding="utf-8") (tmp_path / "docs" / "guides").mkdir(parents=True, exist_ok=True) (tmp_path / "docs" / "guides" / "real.md").write_text("# real\n", encoding="utf-8") (tmp_path / "LICENSE").write_text("Apache\n", encoding="utf-8") diff --git a/tools/check_readme_links.py b/tools/check_readme_links.py index 1fed1b31..02a308cc 100644 --- a/tools/check_readme_links.py +++ b/tools/check_readme_links.py @@ -85,7 +85,11 @@ # ``CONTRIBUTING.md`` is invisible to CI without this entry. _SURFACES: Tuple[Tuple[str, bool], ...] = ( ("README.md", True), + ("CODE_OF_CONDUCT.md", False), ("CONTRIBUTING.md", False), + ("GOVERNANCE.md", False), + ("MAINTAINERS.md", False), + ("SECURITY.md", False), ) _REPO_BLOB_PREFIX_RE = re.compile(r"^https://github\.com/HodeTech/ForgeLM/(?:blob|tree)/main/(?P[^#?]+)") diff --git a/tools/check_source_path_refs.py b/tools/check_source_path_refs.py index 4f9094d0..83db5b70 100644 --- a/tools/check_source_path_refs.py +++ b/tools/check_source_path_refs.py @@ -306,7 +306,18 @@ } # Files scanned outside the directory globs below. -_TOP_LEVEL_SURFACES: frozenset[str] = frozenset({"CLAUDE.md", "AGENTS.md", "CONTRIBUTING.md", "README.md"}) +_TOP_LEVEL_SURFACES: frozenset[str] = frozenset( + { + "AGENTS.md", + "CLAUDE.md", + "CODE_OF_CONDUCT.md", + "CONTRIBUTING.md", + "GOVERNANCE.md", + "MAINTAINERS.md", + "README.md", + "SECURITY.md", + } +) @dataclass(frozen=True) From db9cfbae28b6904d95a5fbc3a96ac9d068d270b9 Mon Sep 17 00:00:00 2001 From: Cemil ILIK Date: Sat, 17 Oct 2026 20:38:27 +0300 Subject: [PATCH 3/5] docs(governance): name the constant that sets a removal's release The Sourcery thread on this line was right about the ambiguity: "the target release is single-sourced in forgelm/config.py" does not say which of the file's constants. Name DEPRECATION_REMOVAL_VERSION (forgelm/config.py:35) and the release standard that governs the sequence (A-12). --- GOVERNANCE.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 472b9d34..8e4df3c5 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -55,8 +55,9 @@ Everyone contributing is bound by the change is larger than one issue, it becomes a roadmap phase under [docs/roadmap/](docs/roadmap/). - **Breaking changes** to the YAML schema or the CLI contract require a - deprecation period. Removing a YAML field is a MAJOR change; the target - release is single-sourced in `forgelm/config.py` and the + deprecation period. Removing a YAML field is a MAJOR change; the release a + removal lands in is named by a single constant, + `DEPRECATION_REMOVAL_VERSION` in `forgelm/config.py`, and the [release standard](docs/standards/release.md) governs the sequence. - **Disagreement** is resolved by discussion on the issue. If a consensus does not form, the maintainer decides and records the reasoning in the issue and, From b46db61d78ef417426970f00e4e04b4c075244e9 Mon Sep 17 00:00:00 2001 From: Cemil ILIK Date: Sat, 17 Oct 2026 20:43:27 +0300 Subject: [PATCH 4/5] chore: apply the remaining review decisions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dependabot.yml: `versioning-strategy: widen`, because ForgeLM declares bounded ranges with no lockfile, so the default `increase` is a no-op on every floor the ceiling already covers (B-01, D-02). Ignore ruff/mypy/bandit: their `[dev]` range must equal the one ci.yml's lint job installs (tests/test_packaging.py), and Dependabot edits only pyproject.toml, so a bump would fail that test on arrival (B-02). Group github-actions minor/patch (B-04). Correct the comment that claimed a pinned dependency, and note the stale requirements*.txt files it will still bump (F-05). - GOVERNANCE.md: remove the Reviewer role — it had no GitHub permission, no owner and no removal path, and "reviewer" already means something else in code-review.md (A-04, F-10). Add an Access and continuity section that records the single-owner gap as a gap rather than promising a fix (F-02, A-03, A-06). Soften the maintainer invitation into an offer the project makes when it needs one, not a reward for a merge count (A-15). - CONTRIBUTING.md and the documentation template: say that a maintainer completes the Turkish mirror when the contributor does not write Turkish, rather than leaving it to be discovered at review (F-08, B-12). --- .github/ISSUE_TEMPLATE/documentation.yml | 2 ++ .github/dependabot.yml | 41 +++++++++++++++++++----- CONTRIBUTING.md | 2 ++ GOVERNANCE.md | 41 ++++++++++++++++++------ 4 files changed, 69 insertions(+), 17 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml index ef234fa2..752e62c7 100644 --- a/.github/ISSUE_TEMPLATE/documentation.yml +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -10,6 +10,8 @@ body: User-facing documentation is kept as an English page **and** a Turkish mirror, and the two are updated together — see [CONTRIBUTING.md](https://github.com/HodeTech/ForgeLM/blob/development/CONTRIBUTING.md). + You do not need to write the Turkish yourself: open the pull request with + the English change and say so, and a maintainer will complete the mirror. Tell us below which copy you were reading. Documentation pull requests are welcome directly. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0a237f78..7d861eb3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,14 +1,27 @@ # Dependabot configuration for ForgeLM. # -# Dependabot opens a pull request when a pinned dependency has a newer release. -# It is the upstream half of the supply-chain story: `tools/check_pip_audit.py` -# and the nightly CVE job catch known advisories, and these pull requests make -# the fix reachable. Minor and patch bumps for Python are grouped to keep the -# noise low; major bumps stay individual so they get a deliberate review. +# Dependabot opens a pull request when a dependency's declared range no longer +# covers the newest release. It is the upstream half of the supply-chain story: +# `tools/check_pip_audit.py` and the nightly CVE job catch known advisories, and +# these pull requests make a fix reachable. # -# The `dependencies` label is already part of the backlog vocabulary -# (see CONTRIBUTING.md); `area: packaging-ci` routes the pull request to the -# right area. +# `versioning-strategy: widen` matters here. ForgeLM declares bounded ranges +# (`>=floor, Date: Sat, 17 Oct 2026 20:44:43 +0300 Subject: [PATCH 5/5] fix(readme): link the new files on development, not main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GOVERNANCE.md, MAINTAINERS.md and CITATION.cff land on `development` first, and `development` is the repository's default branch, so a `blob/main/…` link 404s for up to a release cycle. Point the three new links at `development`, matching the existing CONTRIBUTING.md and docs/standards links. Widening the link form would have cost the on-disk resolution check, so `check_readme_links` now strips `blob/development/…` as well as `blob/main/…` back to a repo-relative path. Link count resolved rises 126 → 129 (CodeRabbit thread on README.md:196). --- README.md | 6 +++--- tools/check_readme_links.py | 9 ++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 14a000cd..fe9b3584 100644 --- a/README.md +++ b/README.md @@ -192,10 +192,10 @@ feature. Start small; you do not need a GPU to run the unit tests or documentati [Engineering standards](https://github.com/HodeTech/ForgeLM/tree/development/docs/standards). Report vulnerabilities privately using [SECURITY.md](https://github.com/HodeTech/ForgeLM/blob/main/SECURITY.md). -Who decides what, and who owns which area: [GOVERNANCE.md](https://github.com/HodeTech/ForgeLM/blob/main/GOVERNANCE.md) · -[MAINTAINERS.md](https://github.com/HodeTech/ForgeLM/blob/main/MAINTAINERS.md). +Who decides what, and who owns which area: [GOVERNANCE.md](https://github.com/HodeTech/ForgeLM/blob/development/GOVERNANCE.md) · +[MAINTAINERS.md](https://github.com/HodeTech/ForgeLM/blob/development/MAINTAINERS.md). To cite ForgeLM, use GitHub's **Cite this repository** button or -[`CITATION.cff`](https://github.com/HodeTech/ForgeLM/blob/main/CITATION.cff). +[`CITATION.cff`](https://github.com/HodeTech/ForgeLM/blob/development/CITATION.cff). ## License diff --git a/tools/check_readme_links.py b/tools/check_readme_links.py index 02a308cc..555bb151 100644 --- a/tools/check_readme_links.py +++ b/tools/check_readme_links.py @@ -92,7 +92,14 @@ ("SECURITY.md", False), ) -_REPO_BLOB_PREFIX_RE = re.compile(r"^https://github\.com/HodeTech/ForgeLM/(?:blob|tree)/main/(?P[^#?]+)") +# README points at in-repo targets with an absolute `blob/main/…` or +# `blob/development/…` URL. Both are stripped back to a repo-relative path and +# resolved on disk: a file added by an unreleased pull request is linked on +# `development` until the release that puts it on `main`, and a typo in either +# form should still fail. +_REPO_BLOB_PREFIX_RE = re.compile( + r"^https://github\.com/HodeTech/ForgeLM/(?:blob|tree)/(?:main|development)/(?P[^#?]+)" +) # Markdown inline links and images: ``[text](href)`` / ``![alt](href)``. # The href stops at whitespace or the closing paren so that titles