Write down the contribution rules: look for a library before writing one, and the formats data leaves in #653

Closed
opened 2026-10-03 01:58:35 +00:00 by tiagoagueda · 0 comments
Owner

Two rules from the maintainer's list of 2026-10-02 are written nowhere a contributor, or an assistant working from CLAUDE.md, would read them. The first is about writing code:

Before implementing any new code library, always check if an open source alternative is already built and can be incorporated in the project according to its license. That could save work and time, unless the library has an unpatched SEVERE security bug. For example: django-cities-xtd, django-scheduler, selenium, etc.

The second is about formats:

Preferable export/import format of ALL KIND data is JSON. Preferable export document format is PDF. Alternatives are ODT and DOCX. Preferable export/import format of contact details is vCard 4. Preferable export/import format of events details is iCalendar.

What exists today

  • No rule about reuse. CONTRIBUTING.md says what will not be merged (payment, a weakened security boundary, something nobody can use: :160-179), that a new boundary takes security tests and that "CI audits the dependencies too" (:253-256), and how the lock is kept current (:301-313). A search of it for reuse, hand-written or new dependency finds nothing. CLAUDE.md:1-83 has no word on dependencies or formats either; its AI section (:77-83) says to credit a model "the way you would credit a library".
  • The nearest written position goes the other way. The core is said to stay light: documents/formats.py:18-22 ("The core stays dependency-light"), documents/docx.py:3-6 (no python-docx, which would bring lxml), applications/ical.py:1-6 ("A dependency would bring the rest of the standard along for nothing"), docs/PLAN.md:133-136 (BeautifulSoup and lxml not added). The DAV plugin says the same of vCard and iCalendar (postulo-dav/pyproject.toml:19-22, src/postulo_dav/text.py:1-8).
  • What hand-writing has cost. Injection through the hand-written iCalendar lines (#218, #450), and the same weakness in the plugin's separate copy of the escaping, never fixed there (postulo/postulo-dav#27); a time zone read as UTC and an alarm's text replacing an interview's notes (postulo/postulo-dav#24, #11). None of these says the choice was wrong when it was made; they are what the choice costs, and the new rule asks that the cost is looked at.
  • One reversal already made. #304 took phonenumberslite (Apache-2.0, libphonenumber's metadata as pure Python) for telephone numbers, and src/postulo/core/phones.py:29-45 says why: the hand-written rule of thumb "was itself producing numbers nobody can dial" and could not tell an unusual number from a mistyped one. The dependency is commented where it is declared (pyproject.toml:55-61). That is the rule applied before it was written; this issue gives it a place.
  • Machinery that already checks a dependency. pip-audit --strict over the lock and npm audit --audit-level=high (.forgejo/workflows/ci.yml:311-320); an advisory is ignored only by name, with a test that expires the ignore (tests/test_security_audit.py:39-54); a monthly Dependencies workflow; the image's SBOM (.forgejo/workflows/image.yml:199). Vendored files are held to THIRD-PARTY.md by tests/test_trademarks.py, which names a fixed list of directories (#579). Packages from the index are outside that register on purpose (THIRD-PARTY.md:38-40); several pyproject.toml entries (httpx, defusedxml, django-cotton) carry a comment saying why they are there.
  • No pull request template. .forgejo/ holds workflows/ and zizmor.yml. #351 adds issue forms only. No plugin repository has a CONTRIBUTING.md; Writing a plugin has a Dependencies paragraph (Writing-a-plugin.md:396-400).
  • The formats today. The whole account as JSON (archive format 29, core/export.py:80), the candidate's record as JSON (format 4, :104), one contact as JSON (#297), the API; ODT is #480, DOCX and text are done (#236); iCalendar is written by hand and never read; vCard exists only in the DAV plugin.

Checked against main at f09b6010b.

Proposal

  1. CONTRIBUTING.md gets a section, Look for a library before you write one, after House style, saying in the maintainer's terms: before writing code that implements a standard, a format, a data set or a well-known algorithm, look for an open-source library that already does it, and say in the pull request what was found. Take it when: its licence is compatible with AGPL-3.0-or-later; it is maintained; pip-audit or npm audit (or OSV) report no unpatched advisory in the range the lock would hold; its cost is stated (size, a compiled or system dependency, what it brings with it); and it fits the content security policy and makes no request nobody asked for. It is not taken when it has an unpatched severe advisory. Writing it by hand is then right, and the pull request says which advisory.
  2. A second section, Formats, says what a new export or import picks, in order: JSON for data; vCard 4.0 for contacts; iCalendar for events and dated things; PDF, then ODT, then DOCX for documents. A format further down the list needs a reason in the issue.
  3. CLAUDE.md gets two lines in How the code is shaped, pointing at both sections, so an assistant reads them before it starts.
  4. A pull request template (.forgejo/PULL_REQUEST_TEMPLATE.md) with the same three questions: what library was looked at, whether a licence line is needed (THIRD-PARTY.md for files in the tree, a comment in pyproject.toml for a package), and whether the advisory check came back clean. The feature form of #351 gets one field: Is there an open-source library or a standard that already does this?
  5. Writing a plugin says the rule binds plugins too, in the Dependencies paragraph; each plugin's README links to the core's section, since none has a CONTRIBUTING.md.
  6. The three examples are answered where the work is. django-cities-xtd belongs to #700 (maps) and django-scheduler to #661 (calendar). selenium was not weighed in #36, which built the browser suite on Playwright because it was already an optional dependency. The checks run on 2026-10-02: django-cities-xtd 0.7.1 (2026-01-08, MIT, no advisory in OSV); django-scheduler 0.12.0 (2026-02-15, BSD-3-Clause, none); selenium 4.50.0 (2026-09-30, Apache-2.0, two advisories, both fixed in 4.0.0 and 4.14.0). The browser suite is Playwright (1.62.0 in uv.lock, 1.63.0 the latest release; Apache-2.0, no advisory). The rule asks for the check; it does not say the alternative wins.

Decisions

  • Retroactive, or from now on. Options: re-examine every hand-written standard now (ical.py, docx.py, the DAV parser, the SVG sanitiser); or apply the rule to new code and to code a commit touches. Recommended: from now on, and when touched. Working code is not rewritten for a rule that arrived later; #660 and #661 touch the two files that matter and carry the prior art.
  • The earlier decision that the core stays light. The comments above record it; the new rule overrides it. Recommended: weight is a cost under the rule (a compiled extension for every instance is item four of the check), not a veto, so python-docx and lxml would still be refused and a pure-Python library with no new dependency would not be. The comments are reworded when their files are next touched.
  • What “severe” means. Options: any advisory; High or Critical (CVSS 7.0 and up) with no fixed release; a maintainer's judgement. Recommended: High or Critical with no fixed release. An advisory with a fix is met by raising the floor in pyproject.toml; one whose fix cannot be taken yet is ignored by name with a test that expires the ignore, as oauthlib's is (#323, tests/test_security_audit.py). The library is still taken.
  • Which licences are compatible. Recommended: MIT, BSD-2 and -3, ISC, 0BSD, Apache-2.0, MPL-2.0, LGPL-3.0, CC0, AGPL-3.0 and GPL-3.0 are taken; GPL-2.0-only, BSD-4-Clause with its advertising clause, non-commercial and source-available terms are not. The list is the maintainer's to confirm; this is not legal advice.
  • CSV. The report's CSV (applications/views.py:1181) and the spreadsheet import (core/csv_import.py) are CSV because employment offices and spreadsheets are. Recommended: the formats rule governs what Postulo offers first; CSV stays where a spreadsheet is the other end.
  • A mechanical licence check in CI. Recommended: not in this issue; add it as its own if the checklist is skipped once.

Needed by

#654, #659, #660 and #661 each record a library check against this rule.

Builds on

Issues #579 (the register and its test), #351 (the forms), #107 (marks), #279 (vendored notices), #480 and #236 (document formats).

Done when

  • CONTRIBUTING.md carries both sections, CLAUDE.md points at them, Writing a plugin says the rule binds plugins, and the pull request template exists with the three questions. The feature form of #351 carries its field.
  • A new test, in the style of tests/test_trademarks.py, holds the prose to the tree: the template exists and the headings CONTRIBUTING.md links to are there.
  • Nothing in the code changes. The suite, lint and tests/test_wiki_surface.py are unaffected.

From the list of improvements of 2026-10-02.

Two rules from the maintainer's list of 2026-10-02 are written nowhere a contributor, or an assistant working from `CLAUDE.md`, would read them. The first is about writing code: > Before implementing any new code library, always check if an open source alternative is already built and can be incorporated in the project according to its license. That could save work and time, unless the library has an unpatched SEVERE security bug. For example: django-cities-xtd, django-scheduler, selenium, etc. The second is about formats: > Preferable export/import format of ALL KIND data is JSON. Preferable export document format is PDF. Alternatives are ODT and DOCX. Preferable export/import format of contact details is vCard 4. Preferable export/import format of events details is iCalendar. ## What exists today - **No rule about reuse.** `CONTRIBUTING.md` says what will not be merged (payment, a weakened security boundary, something nobody can use: `:160-179`), that a new boundary takes security tests and that "CI audits the dependencies too" (`:253-256`), and how the lock is kept current (`:301-313`). A search of it for *reuse*, *hand-written* or *new dependency* finds nothing. `CLAUDE.md:1-83` has no word on dependencies or formats either; its AI section (`:77-83`) says to credit a model "the way you would credit a library". - **The nearest written position goes the other way.** The core is said to stay light: `documents/formats.py:18-22` ("The core stays dependency-light"), `documents/docx.py:3-6` (no `python-docx`, which would bring `lxml`), `applications/ical.py:1-6` ("A dependency would bring the rest of the standard along for nothing"), `docs/PLAN.md:133-136` (BeautifulSoup and lxml not added). The DAV plugin says the same of vCard and iCalendar (`postulo-dav/pyproject.toml:19-22`, `src/postulo_dav/text.py:1-8`). - **What hand-writing has cost.** Injection through the hand-written iCalendar lines (#218, #450), and the same weakness in the plugin's separate copy of the escaping, never fixed there (postulo/postulo-dav#27); a time zone read as UTC and an alarm's text replacing an interview's notes (postulo/postulo-dav#24, #11). None of these says the choice was wrong when it was made; they are what the choice costs, and the new rule asks that the cost is looked at. - **One reversal already made.** #304 took `phonenumberslite` (Apache-2.0, libphonenumber's metadata as pure Python) for telephone numbers, and `src/postulo/core/phones.py:29-45` says why: the hand-written rule of thumb "was itself producing numbers nobody can dial" and could not tell an unusual number from a mistyped one. The dependency is commented where it is declared (`pyproject.toml:55-61`). That is the rule applied before it was written; this issue gives it a place. - **Machinery that already checks a dependency.** `pip-audit --strict` over the lock and `npm audit --audit-level=high` (`.forgejo/workflows/ci.yml:311-320`); an advisory is ignored only by name, with a test that expires the ignore (`tests/test_security_audit.py:39-54`); a monthly `Dependencies` workflow; the image's SBOM (`.forgejo/workflows/image.yml:199`). Vendored files are held to `THIRD-PARTY.md` by `tests/test_trademarks.py`, which names a fixed list of directories (#579). Packages from the index are outside that register on purpose (`THIRD-PARTY.md:38-40`); several `pyproject.toml` entries (httpx, defusedxml, django-cotton) carry a comment saying why they are there. - **No pull request template.** `.forgejo/` holds `workflows/` and `zizmor.yml`. #351 adds issue forms only. No plugin repository has a `CONTRIBUTING.md`; *Writing a plugin* has a *Dependencies* paragraph (`Writing-a-plugin.md:396-400`). - **The formats today.** The whole account as JSON (archive format 29, `core/export.py:80`), the candidate's record as JSON (format 4, `:104`), one contact as JSON (#297), the API; ODT is #480, DOCX and text are done (#236); iCalendar is written by hand and never read; vCard exists only in the DAV plugin. Checked against `main` at `f09b6010b`. ## Proposal 1. **`CONTRIBUTING.md` gets a section, *Look for a library before you write one*,** after *House style*, saying in the maintainer's terms: before writing code that implements a standard, a format, a data set or a well-known algorithm, look for an open-source library that already does it, and say in the pull request what was found. Take it when: its licence is compatible with AGPL-3.0-or-later; it is maintained; `pip-audit` or `npm audit` (or OSV) report no unpatched advisory in the range the lock would hold; its cost is stated (size, a compiled or system dependency, what it brings with it); and it fits the content security policy and makes no request nobody asked for. It is not taken when it has an **unpatched severe advisory**. Writing it by hand is then right, and the pull request says which advisory. 2. **A second section, *Formats*,** says what a new export or import picks, in order: JSON for data; vCard 4.0 for contacts; iCalendar for events and dated things; PDF, then ODT, then DOCX for documents. A format further down the list needs a reason in the issue. 3. **`CLAUDE.md` gets two lines** in *How the code is shaped*, pointing at both sections, so an assistant reads them before it starts. 4. **A pull request template** (`.forgejo/PULL_REQUEST_TEMPLATE.md`) with the same three questions: what library was looked at, whether a licence line is needed (`THIRD-PARTY.md` for files in the tree, a comment in `pyproject.toml` for a package), and whether the advisory check came back clean. The feature form of #351 gets one field: *Is there an open-source library or a standard that already does this?* 5. ***Writing a plugin* says the rule binds plugins too,** in the *Dependencies* paragraph; each plugin's README links to the core's section, since none has a `CONTRIBUTING.md`. 6. **The three examples are answered where the work is.** `django-cities-xtd` belongs to #700 (maps) and `django-scheduler` to #661 (calendar). `selenium` was not weighed in #36, which built the browser suite on Playwright because it was already an optional dependency. The checks run on 2026-10-02: django-cities-xtd 0.7.1 (2026-01-08, MIT, no advisory in OSV); django-scheduler 0.12.0 (2026-02-15, BSD-3-Clause, none); selenium 4.50.0 (2026-09-30, Apache-2.0, two advisories, both fixed in 4.0.0 and 4.14.0). The browser suite is Playwright (1.62.0 in `uv.lock`, 1.63.0 the latest release; Apache-2.0, no advisory). The rule asks for the check; it does not say the alternative wins. ## Decisions - **Retroactive, or from now on.** Options: re-examine every hand-written standard now (`ical.py`, `docx.py`, the DAV parser, the SVG sanitiser); or apply the rule to new code and to code a commit touches. **Recommended:** from now on, and when touched. Working code is not rewritten for a rule that arrived later; #660 and #661 touch the two files that matter and carry the prior art. - **The earlier decision that the core stays light.** The comments above record it; the new rule overrides it. **Recommended:** weight is a cost under the rule (a compiled extension for every instance is item four of the check), not a veto, so `python-docx` and `lxml` would still be refused and a pure-Python library with no new dependency would not be. The comments are reworded when their files are next touched. - **What “severe” means.** Options: any advisory; High or Critical (CVSS 7.0 and up) with no fixed release; a maintainer's judgement. **Recommended:** High or Critical with no fixed release. An advisory with a fix is met by raising the floor in `pyproject.toml`; one whose fix cannot be taken yet is ignored by name with a test that expires the ignore, as oauthlib's is (#323, `tests/test_security_audit.py`). The library is still taken. - **Which licences are compatible.** **Recommended:** MIT, BSD-2 and -3, ISC, 0BSD, Apache-2.0, MPL-2.0, LGPL-3.0, CC0, AGPL-3.0 and GPL-3.0 are taken; GPL-2.0-only, BSD-4-Clause with its advertising clause, non-commercial and source-available terms are not. The list is the maintainer's to confirm; this is not legal advice. - **CSV.** The report's CSV (`applications/views.py:1181`) and the spreadsheet import (`core/csv_import.py`) are CSV because employment offices and spreadsheets are. **Recommended:** the formats rule governs what Postulo offers first; CSV stays where a spreadsheet is the other end. - **A mechanical licence check in CI.** **Recommended:** not in this issue; add it as its own if the checklist is skipped once. ## Needed by #654, #659, #660 and #661 each record a library check against this rule. ## Builds on Issues #579 (the register and its test), #351 (the forms), #107 (marks), #279 (vendored notices), #480 and #236 (document formats). ## Done when - `CONTRIBUTING.md` carries both sections, `CLAUDE.md` points at them, *Writing a plugin* says the rule binds plugins, and the pull request template exists with the three questions. The feature form of #351 carries its field. - A new test, in the style of `tests/test_trademarks.py`, holds the prose to the tree: the template exists and the headings `CONTRIBUTING.md` links to are there. - Nothing in the code changes. The suite, lint and `tests/test_wiki_surface.py` are unaffected. From the list of improvements of 2026-10-02.
tiagoagueda added this to the 0.5.0 milestone 2026-10-03 01:58:35 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#653
No description provided.