Title-case every page and section heading

DPM is public-facing, and its headings read as titles: capitalized
throughout, with articles, conjunctions, and short prepositions left
lowercase in the middle.

Applies to the markdown documents and to the Doxygen page and section
titles in the public header, so the generated reference matches. One
prose cross-reference in DESIGN.md follows the section it names.
This commit is contained in:
2026-08-15 20:49:29 -04:00
parent 38bd9314cc
commit 99173d27ea
6 changed files with 57 additions and 57 deletions

View File

@@ -1,6 +1,6 @@
# DPM — An Overview
## What DPM is
## What DPM Is
DPM is the package manager for Dark Horse Linux. At its center is **libdpm-core.so**, a shared library that discovers modules, validates them, and routes calls to them, and that provides configuration and logging to whatever it has loaded. Modules — shared objects in the module directory — implement package functionality.
@@ -8,7 +8,7 @@ DPM is the package manager for Dark Horse Linux. At its center is **libdpm-core.
libdpm-core.so implements no package operations. It routes and hosts.
## The shape of the system
## The Shape of the System
Everything reaches a module the same way, and a module reaching another module is the same step repeated:
@@ -26,7 +26,7 @@ Two properties make the routing rule real rather than a convention:
- **There is one instance of libdpm-core.so in the process.** A module links against the library like any other consumer, and when the module is loaded the dynamic linker binds it to the copy already mapped. A module therefore drives the same context, the same module registry, and the same configuration the original caller opened.
- **Modules cannot see each other.** They are loaded with `RTLD_LOCAL`, so a module's symbols never enter the global namespace. The only symbols a module can resolve are libdpm-core.so's, so there is physically no path from one module to another that does not pass through the library.
## Running the dpm binary
## Running the dpm Binary
The `dpm` binary's subcommand surface is exactly the set of loadable modules. `dpm <module> <command> [args...]` loads that module and hands the command to it; `dpm <module> help` asks the module to describe itself. There is no fixed list of operations baked into the tool, because the tool contains no capability logic — it parses arguments and prints.
@@ -41,7 +41,7 @@ Four flags redirect the system defaults:
These four exist because of a rule the design imposes on itself: every field a linked program can override must also be a flag, so anything reachable from code is reachable from a shell. That rule holds for any override added in the future.
## Writing a program against the library
## Writing a Program Against the Library
A program includes `<dpm/core.h>` and links `-ldpm-core`, the same as it would link any other shared library. Everything it does happens through a **context**, an opaque handle obtained from `dpm_open`.
@@ -61,7 +61,7 @@ The context owns everything it hands out. Every string a caller receives stays v
**Services.** A module reaches the library through the context that dispatched the call: `dpm_log` to write a message, `dpm_config_get` to read a value from its own configuration namespace, `dpm_module_path` to learn where modules live, `dpm_core_version` to learn the library's version. A module needs no file handling and no logging machinery of its own.
## How a module reaches another module
## How a Module Reaches Another Module
A module is a consumer of `<dpm/core.h>` exactly like the `dpm` binary is. To reach a peer it performs the identical two steps its own caller performed: ask the library for the module by name, then ask the library to invoke it.
@@ -81,7 +81,7 @@ The `ctx` a module needs is the one handed to it in its own entry point, so it r
**A module never links, includes, or hardcodes anything belonging to another module.** No peer headers, no shared struct layouts, no peer symbols. The only build dependency a module has is libdpm-core.so, and the only knowledge it holds about a peer is the peer's name and the command it wants to run. That is what allows every module to live in its own repository and be built with no peer present anywhere on the machine.
## What DPM reads and writes on disk
## What DPM Reads and Writes on Disk
**Configuration** lives in `/etc/dpm/conf.d/`. Each `.conf` file in that directory is one namespace named after the file: `core.conf` holds the library's own settings, and a module named `mymodule` reads `mymodule.conf`. Files are sectioned, and a value is addressed by namespace, section, and key. The library's own file carries the log level, whether to write a log file and where, and the default module directory.
@@ -100,7 +100,7 @@ The `ctx` a module needs is the one handed to it in its own entry point, so it r
| public header | `/usr/include/dpm/core.h` |
| modules | `/usr/lib/dpm/modules/<name>.so` |
## The module contract
## The Module Contract
*What a module author implements.*
@@ -110,7 +110,7 @@ The entry point receives the context that dispatched the call, the command name,
A module is built against the system-installed `libdpm-core.so` and is responsible for being correct against it. Where it needs to know what it is running on, `dpm_core_version()` reports the running version and the module acts on that itself.
## Load-time enforcement
## Load-Time Enforcement
libdpm-core.so validates a module completely before offering it to anyone:
@@ -129,29 +129,29 @@ A module determines its own compatibility with the library it is running against
A module that depends on another module requires it, reads the version reported back, and decides for itself whether that version is suitable for the commands it intends to issue. libdpm-core.so reports what it saw and draws no conclusion from it, so a handle means the module is valid rather than that it suits any particular caller.
## Why it works this way
## Why It Works This Way
### Because it must run on a barren system
### Because It Must Run on a Barren System
The founding constraint is that DPM has to work in an environment providing nothing but libc and libstdc++, using the same binaries that run on a fully populated system. That forbids libdpm-core.so from taking on any dependency beyond the baseline, which forbids package logic from living inside it, which produces the division the whole architecture rests on: **libdpm-core.so routes and hosts, modules implement.** Anything needing a database, compression, or TLS is a module that arrives later.
### Because capability has to grow in layers
### Because Capability Has to Grow in Layers
Each layer of the system installs the dependencies of the next using only what already works. That requires upper layers to reach lower ones through a stable in-process interface rather than by re-implementing them, and it requires writes to flow strictly downward — a layer mutates the system only through the layer beneath it. Shared concerns like locking are then implemented once, at the bottom, and inherited by everything above.
### Because one implementation must serve every caller
### Because One Implementation Must Serve Every Caller
The requirement that every implementation exist exactly once, and be consumable by the `dpm` binary, by other layers, and by external programs, is what makes libdpm-core.so a C ABI library rather than an application with a library carved out of it. It is also why the command line and the C API stay in step: the flags are the override fields, one for one, so a program and a person redirect the same things by the same names.
### Because nothing may be trusted that has not been verified
### Because Nothing May Be Trusted That Has Not Been Verified
libdpm-core.so is the sole authority on module validity, and the contract is enforced by its validator rather than by an SDK a module author might skip, patch, or fall behind. That is why validation is all-or-nothing and why it happens at load: failures surface loudly and itemized at install time instead of halfway through an operation on a user's system.
### Because coordination happens at load, not at build
### Because Coordination Happens at Load, Not at Build
A caller states the module name and command it needs and is told at load whether the module is there. That is what allows modules to be released independently: agreement is reached when the pieces meet, through declared versions each consumer judges for itself, instead of through lockstep builds.
### Because modules are developed independently
### Because Modules Are Developed Independently
One repository per module, plus the libdpm-core.so repository. A module links libdpm-core.so and nothing else from DPM; peer modules never appear in its repository, build, or test environment. "Not all the pieces are there" is the normal, permanent condition at build time, so the architecture is arranged to make that a non-event:
@@ -162,7 +162,7 @@ One repository per module, plus the libdpm-core.so repository. A module links li
This repository's own fixtures are deliberately broken stub modules — missing symbols, a malformed version — plus one known-good stub. Developing libdpm-core.so never requires a real package module to exist.
## What this repository produces
## What This Repository Produces
- **`libdpm-core.so`** — the library
- **the `dpm` binary** — the command-line tool
@@ -179,7 +179,7 @@ Every other module is developed against libdpm-core.so and lives outside this re
5. A module is either fully valid or not loaded — no partial states, no consumer-side defense.
6. Anything a linked program can redirect, a shell user can redirect too.
## Further reading
## Further Reading
- **DESIGN.md** — the full design specification
- **CONSUMERS.md** — linking libdpm-core.so and driving it from a program