![]() |
Ansel 0.0
A darktable fork - bloat + design vision
|
**This file holds the rules. The knowledge lives in `doc/`.**
It used to be both, and grew to 3,177 lines of accumulated findings. A verification pass on 2026-09-29 against 42eca0e8fe checked every falsifiable claim in it and found sixteen that were wrong — including one marked (OPEN) that had been fixed a month earlier, one that forbade a feature the code already implements, and one naming a struct field that does not exist. A file nobody can date is a file nobody can trust, so the findings moved to doc/, where each one carries the commit it was established against.
doc/. Read the file for the area you are touching before you touch it — every one of them exists because something cost days to work out.doc/ is dated and carries a commit hash. A finding is only as good as its hash. Before acting on one older than the code you are changing, re-measure it — and re-date it when you confirm it. Where a claim was found to be wrong, that is recorded rather than quietly corrected: how a claim was wrong is usually the more useful thing to know.doc/, not here — with the date and the commit you established it against.Named after the path relative to src/ (src/develop/masks/masks_history.h → DT_DEVELOP_MASKS_MASKS_HISTORY_H). #pragma once silently makes a cyclic include graph compile; explicit guards make the same situation greppable. src/darktable.h has an #error tripwire instead of a guard, and no header may include it. Five X-macro headers deliberately have no guard at all and must never get one.
Enforced: python3 tools/pragma_once_to_guards.py --verify, and python3 tools/include_graph.py --summary must keep reporting cycles 0. → `doc/architecture-rules.md`, `doc/include-graph.md`
Everything else belongs in the .c. A header that includes more becomes a supply line its consumers never asked for and cannot see. Implementations do not belong in headers either; the one exception is a header whose published interface is inline code.
Enforced: tools/check_unused_includes.sh --changed <ref>. → `doc/architecture-rules.md`
src/libs/ and src/views/ contain no raw SQL. Database access belongs behind named functions in src/common/ and src/database/. → `doc/architecture-rules.md`, `doc/collection.md`
The ONLY thread-safe interface between the pixel pipeline and an IOP module is history, guarded by dev->history_mutex. module->params and module->blend_params belong to the GUI thread. Never call dt_iop_commit_params(module, module->params, ...) from pipeline code — commit from the history snapshot. To push live state to the pipe, use the transient-resync interface dt_dev_transient_params_{set,clear,get,active}. → `doc/pipeline-history.md`, `doc/reorganisation.md`
An entry in an existing section is one edit, to data/anselconfig.xml.in. A new section value takes three: the XML, plus data/anselconfig.dtd (the section attribute is an enumerated list; xmllint fails the build otherwise) and tools/generate_prefs.xsl (a section not enumerated there is silently dropped from the UI, with no error).
Measured 2026-09-29 over the 108-commit history of that file: of the 45 commits that added a <dtconfig> entry, 40 touched only the XML and 5 touched the DTD or XSL — and those 5 are exactly the ones introducing a new section. → `doc/preferences.md`
This tree's history is full of plausible-but-wrong theories that survived source reading and died on the first measurement. Several entries in doc/ exist only to record which theories were killed and how. When you write a finding down, write down the number and the method.
| Read this | For |
|---|---|
| `doc/README.md` | the documentation index and how to build |
| `doc/reorganisation.md` | module map, layering, the direction of travel |
| `doc/architecture-rules.md` | the five rules above, with the evidence |
| `doc/include-graph.md` | include guards, cycles, how they are measured |
| `doc/preferences.md` | the three-edit rule |
| Read this | For |
|---|---|
| `doc/pipeline-cache.md` | the pixelpipe cache: keys, refcounts, peeks, memory pressure |
| `doc/pipeline-history.md` | history snapshots, the darkroom worker, the transient slot |
| `doc/image-mipmap-cache.md` | thumbnail invalidation, image cache entry locks |
| `doc/raw-roi-cfa.md` | RAW-domain ROI offsets, CFA phase, tile-grid dependence |
| `doc/resizing-scaling.md` | ROI planning and scaling |
| Read this | For |
|---|---|
| `doc/colorprofiles.md` | profile roles, locks, the derived-profile memo |
| `src/colorprofiles/README.md` | the module's own map |
| `doc/color.md` | colour spaces and the working space |
| `doc/highlights-reconstruction.md` | harmonic highlight reconstruction |
| `doc/interpolation.md` | which resampling kernel, and why |
| Read this | For |
|---|---|
| `doc/masks-geometry.md` | brush and polygon outlines and rasters |
| `doc/brush-boundary.md` | the full boundary account |
| `doc/masks-gui.md` | gestures, the wheel mapping, the shape manager |
| `doc/masks-history.md` | refcounted forms, module mask groups, the enclosure |
| `doc/masks-enclosure-p2.md` | the enclosure plan |
| `doc/masks_history_dedup.md` | the persistence dedup design |
| `doc/overlay-raster.md` | how the overlay is drawn |
| Read this | For |
|---|---|
| `doc/iop-notes.md` | per-module findings (ashift, retouch, toneequal, …) |
| `doc/drawlayer.md` | the drawlayer module in full |
| `doc/retouch-result-memo.md` | retouch's per-shape memo |
| `doc/gtk-patterns.md` | layout, focus, repaint and threading patterns |
| `doc/shutdown.md` | what a quit waits for, and the window that says so |
| `doc/darkroom-redraw.md` | the centre repaint path, priced |
| `doc/thumbtable.md` | the thumbnail grid |
| `doc/accelerators.md` | keyboard shortcuts end to end |
| `doc/collection.md` | the library module, import and removal |
| `doc/removal-undo.md` | how removal is undone |
| `doc/export.md` | export size resolution |
| Read this | For |
|---|---|
| `doc/nightly-distribution.md` | nightlies, channels, the manifest |
| `doc/sentry.md` | crash reports and how to fetch one |
| `doc/telemetry.md` | what is collected |
| `doc/static-iop.md` | static IOP linking |
| `doc/exiv2.md` | the bundled Exiv2 |
The full index, including everything not listed here, is `doc/README.md`.