Normalize line endings to LF

.gitattributes sets text=auto with eol=lf, so every text file is
stored and checked out with LF, and a patch keeps its bytes. The files
that carried CRLF from a Windows editor are renormalized. No content
changes.
This commit is contained in:
ScottW514
2026-09-14 10:39:08 -04:00
parent d8b8adaef4
commit 7c0412075c
3 changed files with 1079 additions and 1075 deletions
+4
View File
@@ -0,0 +1,4 @@
# Every text file is stored and checked out with LF; a patch keeps its bytes.
* text=auto eol=lf
*.patch -text
*.diff -text
+398 -398
View File
@@ -1,398 +1,398 @@
# AGENTS.md # AGENTS.md
Instructions for AI coding agents that work in this repository. A human Instructions for AI coding agents that work in this repository. A human
contributor is welcome to read it too: it is the same set of rules. contributor is welcome to read it too: it is the same set of rules.
## ForgeFIRM repository rules ## ForgeFIRM repository rules
### Safety on the machine ### Safety on the machine
- The laser never fires with the coolant pump deliberately off. The heater-only - The laser never fires with the coolant pump deliberately off. The heater-only
flow-calibrate and flow-verify tools are the only pump-off state, and the flow-calibrate and flow-verify tools are the only pump-off state, and the
tube stays dark during them. tube stays dark during them.
- The 40 V motor rail stays up while the machine is on. Never cycle it for a - The 40 V motor rail stays up while the machine is on. Never cycle it for a
controller handover. A rail glitch can leave the stepper drivers controller handover. A rail glitch can leave the stepper drivers
unserviceable. unserviceable.
### The iteration loop ### The iteration loop
- Edit, cross-build in the Yocto build environment, hot-deploy to the - Edit, cross-build in the Yocto build environment, hot-deploy to the
machine, prove. Then one commit, one push, one pin bump for the proven machine, prove. Then one commit, one push, one pin bump for the proven
change. change.
- A full image build happens once, at the end of a work item, never per fix. - A full image build happens once, at the end of a work item, never per fix.
- Kernel and BSP changes ride one image flash, batched. Validate a `.ko` or - Kernel and BSP changes ride one image flash, batched. Validate a `.ko` or
overlay change on the image that ships it. Never hot-swap a `.ko` onto a overlay change on the image that ships it. Never hot-swap a `.ko` onto a
board that is about to be reflashed. board that is about to be reflashed.
### Acceptance coverage ### Acceptance coverage
- Evaluate every change against the acceptance catalog in - Evaluate every change against the acceptance catalog in
`forgetest/forgetest/suite/`. Does an existing test exercise the changed `forgetest/forgetest/suite/`. Does an existing test exercise the changed
behavior? Does its `covers` map name the files you touched? If not, add or behavior? Does its `covers` map name the files you touched? If not, add or
widen one in the same change. The coverage lint widen one in the same change. The coverage lint
(`python3 -m forgetest.coverage --enforce`) is the floor. (`python3 -m forgetest.coverage --enforce`) is the floor.
- The `SRCREV` of a component and the `PV` that moves with it live in - The `SRCREV` of a component and the `PV` that moves with it live in
`<recipe>-pin.inc` next to the recipe. Nothing else goes in that file. The `<recipe>-pin.inc` next to the recipe. Nothing else goes in that file. The
image manifest keeps `*-pin.inc` out of the layer content hash. Thus a pin image manifest keeps `*-pin.inc` out of the layer content hash. Thus a pin
bump invalidates only the acceptance tests that cover that component. A bump invalidates only the acceptance tests that cover that component. A
pin in a recipe body counts as a platform change and needs a full pin in a recipe body counts as a platform change and needs a full
acceptance campaign. acceptance campaign.
- Test a harness change yourself, on the host, before you hand it to the - Test a harness change yourself, on the host, before you hand it to the
operator for a bench run. A harness that fails on its own defect costs the operator for a bench run. A harness that fails on its own defect costs the
operator a full re-run cycle. operator a full re-run cycle.
- A test declares its `mode`, and the runner switches. Cloud tests stay in - A test declares its `mode`, and the runner switches. Cloud tests stay in
cloud mode. Keep `requires` lists minimal, and never gate one test behind a cloud mode. Keep `requires` lists minimal, and never gate one test behind a
chain of others. chain of others.
- Never exercise a gate or a limit through the `GFCOOL_*` environment - Never exercise a gate or a limit through the `GFCOOL_*` environment
overrides in a test. Use the settings API, and restore it in the teardown. overrides in a test. Use the settings API, and restore it in the teardown.
### CI couplings that set the push order ### CI couplings that set the push order
- The CI of `grblHAL-glowforge` gets the laser harnesses from `scripts/bench/` - The CI of `grblHAL-glowforge` gets the laser harnesses from `scripts/bench/`
at the head of `master`, unpinned. Push a harness change here before the at the head of `master`, unpinned. Push a harness change here before the
driver change that needs it. driver change that needs it.
- The acceptance page shares its theme and its vendored Bootstrap with the - The acceptance page shares its theme and its vendored Bootstrap with the
`forgectrl` panel, byte for byte. Land a UI change in `forgectrl` first. `forgectrl` panel, byte for byte. Land a UI change in `forgectrl` first.
Push it and pin it. Only then push this repository. Push it and pin it. Only then push this repository.
- The CI of `kernel-module-glowforge` cross-builds against the BSP from - The CI of `kernel-module-glowforge` cross-builds against the BSP from
`meta-openglow`. Push `meta-openglow` before a module change that needs a `meta-openglow`. Push `meta-openglow` before a module change that needs a
BSP change. BSP change.
### Builds and images ### Builds and images
- Builds run only in the dedicated Yocto build environment that the Build page - Builds run only in the dedicated Yocto build environment that the Build page
of the site defines (kas and bitbake). Never use a native host build of a of the site defines (kas and bitbake). Never use a native host build of a
component as proof, not even for a compile check. component as proof, not even for a compile check.
- Every build makes both images: `forgefirm-image` (the release image) and - Every build makes both images: `forgefirm-image` (the release image) and
`forgefirm-image-dev` (the bench image, with `forgetest` on port 8090). The `forgefirm-image-dev` (the bench image, with `forgetest` on port 8090). The
dev image needs an explicit `--target`. Report both artifact names. dev image needs an explicit `--target`. Report both artifact names.
- After a kernel-module pin bump, rebuild the kernel and the module in the - After a kernel-module pin bump, rebuild the kernel and the module in the
same run: `bitbake -c cleansstate linux-fslc kernel-module-glowforge`, then same run: `bitbake -c cleansstate linux-fslc kernel-module-glowforge`, then
the images. The kernel version suffix is not reproducible across the images. The kernel version suffix is not reproducible across
re-checkouts, and a rootfs whose kernel and module disagree fails. re-checkouts, and a rootfs whose kernel and module disagree fails.
- Read the layer HEAD lines at the top of a build log before you trust a build - Read the layer HEAD lines at the top of a build log before you trust a build
that moves a pin. that moves a pin.
### The record of the work ### The record of the work
This repository carries no status document and no dated log. Both were This repository carries no status document and no dated log. Both were
retired: every fact about the machine and the firmware is on the retired: every fact about the machine and the firmware is on the
documentation site, and **the record of a piece of work is the commit message documentation site, and **the record of a piece of work is the commit message
that carries it**: what was done, how it was proven, and what it replaced, in that carries it**: what was done, how it was proven, and what it replaced, in
the same place as the change itself. the same place as the change itself.
A measurement session or a bench drill is written up in the commit that A measurement session or a bench drill is written up in the commit that
lands its result. Nothing accumulates in a file. lands its result. Nothing accumulates in a file.
### On the bench ### On the bench
These rules apply whenever an agent works with the operator at a machine. These rules apply whenever an agent works with the operator at a machine.
- **One armed run per turn.** Start the run, let it finish, stop, report what - **One armed run per turn.** Start the run, let it finish, stop, report what
happened against what was expected, and wait for the operator's happened against what was expected, and wait for the operator's
confirmation before any further armed run or machine command. Never chain a confirmation before any further armed run or machine command. Never chain a
jog, a fix, or a re-run onto a burn in the same step. Dry runs (latch jog, a fix, or a re-run onto a burn in the same step. Dry runs (latch
locked, no emission) can be batched. Say which is which before you start. locked, no emission) can be batched. Say which is which before you start.
- **Zero inference during live fire.** Report only what the combined - **Zero inference during live fire.** Report only what the combined
observations confirm: the operator's eyes, the drill output, the logs, the observations confirm: the operator's eyes, the drill output, the logs, the
sysfs readbacks. Everything else is labeled "unconfirmed" and is not acted sysfs readbacks. Everything else is labeled "unconfirmed" and is not acted
on. on.
- **One Grbl connection.** Never open a second connection to TCP port 23 while - **One Grbl connection.** Never open a second connection to TCP port 23 while
a drill, an acceptance test, or a sender holds one. The last connection a drill, an acceptance test, or a sender holds one. The last connection
wins, the displaced client's cleanup never arrives, and its queued commands wins, the displaced client's cleanup never arrives, and its queued commands
wait behind the arm gate. Read state through `forgectrl` (HTTP) and sysfs wait behind the arm gate. Read state through `forgectrl` (HTTP) and sysfs
only. After a displaced or aborted drill: soft reset, confirm that the RX only. After a displaced or aborted drill: soft reset, confirm that the RX
buffer reads full, `M5`, confirm that `armed` is false, before anyone buffer reads full, `M5`, confirm that `armed` is false, before anyone
touches the button. touches the button.
- **The operator touches the machine.** The operator runs the install, the - **The operator touches the machine.** The operator runs the install, the
service restart, and the reflash on the machine. Never modify the software service restart, and the reflash on the machine. Never modify the software
of a running machine unless the operator asks for that exact step. of a running machine unless the operator asks for that exact step.
- **Bench hygiene.** Stage test files in `/tmp`. A file that must survive a - **Bench hygiene.** Stage test files in `/tmp`. A file that must survive a
reboot goes in `/data/bench-scratch/`, and that directory is deleted whole reboot goes in `/data/bench-scratch/`, and that directory is deleted whole
at the end of the session. Nothing goes loose in `/data`. Remove everything at the end of the session. Nothing goes loose in `/data`. Remove everything
you put on the board, in the same session, and list `/data` before you end. you put on the board, in the same session, and list `/data` before you end.
A bench tool worth a second use goes in `scripts/bench/`. The dev image A bench tool worth a second use goes in `scripts/bench/`. The dev image
installs those tools under `/usr/share/forgetest/bench/`. Run them from installs those tools under `/usr/share/forgetest/bench/`. Run them from
there. there.
## Project-wide rules ## Project-wide rules
The sections above are specific to this repository. The rules below apply to The sections above are specific to this repository. The rules below apply to
every repository of the OpenGlow ForgeFIRM project: the firmware components, every repository of the OpenGlow ForgeFIRM project: the firmware components,
the build base, the documentation, and the hardware designs. Where a the build base, the documentation, and the hardware designs. Where a
repository rule and a rule below conflict, the safety, proof, and hygiene repository rule and a rule below conflict, the safety, proof, and hygiene
rules below win. The documentation site, <https://docs.forgefirm.org/>, is rules below win. The documentation site, <https://docs.forgefirm.org/>, is
the source of truth for every fact about the machine and the firmware. Read the source of truth for every fact about the machine and the firmware. Read
its Developers section before you change code. its Developers section before you change code.
### What ForgeFIRM is ### What ForgeFIRM is
ForgeFIRM is open firmware for stock Glowforge lasers (Basic, Plus, Pro). It ForgeFIRM is open firmware for stock Glowforge lasers (Basic, Plus, Pro). It
runs on the factory NXP i.MX6 control board with no hardware modification. It runs on the factory NXP i.MX6 control board with no hardware modification. It
replaces the cloud-dependent factory userspace with an open Linux image that replaces the cloud-dependent factory userspace with an open Linux image that
controls the machine locally. In GRBL mode the machine is a standard grblHAL controls the machine locally. In GRBL mode the machine is a standard grblHAL
controller for LightBurn and other senders on TCP port 23. Cloud mode runs the controller for LightBurn and other senders on TCP port 23. Cloud mode runs the
factory experience through the Glowforge web service, and it is a deliberate, factory experience through the Glowforge web service, and it is a deliberate,
maintained feature. The stack is hardware validated: GRBL mode cuts real jobs, maintained feature. The stack is hardware validated: GRBL mode cuts real jobs,
and cloud mode runs end to end. and cloud mode runs end to end.
One controller runs at a time under `forgectrl`, the machine-services daemon, One controller runs at a time under `forgectrl`, the machine-services daemon,
which owns the pulse device, the cooling engine, the cameras, and the control which owns the pulse device, the cooling engine, the cameras, and the control
panel. The kernel module plays the pulse stream into the stepper drivers and panel. The kernel module plays the pulse stream into the stepper drivers and
owns the laser latch and the safety readbacks. The Technical section of the owns the laser latch and the safety readbacks. The Technical section of the
site describes the whole stack. site describes the whole stack.
### The repositories ### The repositories
All repositories live under the OpenGlow organization on GitHub, All repositories live under the OpenGlow organization on GitHub,
<https://github.com/openglow-org>. For development, check every repository out <https://github.com/openglow-org>. For development, check every repository out
as a sibling in one base directory named `openglow-forgefirm`. The build as a sibling in one base directory named `openglow-forgefirm`. The build
scripts expect that layout. Each repository is its own git repository. The scripts expect that layout. Each repository is its own git repository. The
base directory is not. base directory is not.
| Repository | Role | Default branch | License | | Repository | Role | Default branch | License |
|---|---|---|---| |---|---|---|---|
| `forgefirm` | The build and release base: the `meta-forgefirm` Yocto layer, the kas configuration, the image recipes, the install and release scripts, the acceptance tool `forgetest/`, the bench tools `scripts/bench/`, and the bench actuator firmware `fixture/`. It carries no project documentation. | `master` | MIT (layer metadata) | | `forgefirm` | The build and release base: the `meta-forgefirm` Yocto layer, the kas configuration, the image recipes, the install and release scripts, the acceptance tool `forgetest/`, the bench tools `scripts/bench/`, and the bench actuator firmware `fixture/`. It carries no project documentation. | `master` | MIT (layer metadata) |
| `meta-openglow` | The BSP layers `meta-glowforge-bsp` and `meta-openglow-core`: kernel, device tree, U-Boot, board recipes. | `scarthgap` | MIT (layer metadata) | | `meta-openglow` | The BSP layers `meta-glowforge-bsp` and `meta-openglow-core`: kernel, device tree, U-Boot, board recipes. | `scarthgap` | MIT (layer metadata) |
| `forgectrl` | The machine-services daemon (C) on HTTPS port 443, with the read-only routes on HTTP port 80: supervisor, pulse-device broker, motion-liveness gate, cooling engine, cameras, telemetry, settings, diagnostics, control panel, A/B updates. | `main` | MIT | | `forgectrl` | The machine-services daemon (C) on HTTPS port 443, with the read-only routes on HTTP port 80: supervisor, pulse-device broker, motion-liveness gate, cooling engine, cameras, telemetry, settings, diagnostics, control panel, A/B updates. | `main` | MIT |
| `grblHAL-glowforge` | The grblHAL driver for the stock board, the GRBL-mode controller. The core is a submodule at `src/grbl`. Machine constants are in `src/boards/glowforge.h`. | `main` | GPL-3.0-or-later | | `grblHAL-glowforge` | The grblHAL driver for the stock board, the GRBL-mode controller. The core is a submodule at `src/grbl`. Machine constants are in `src/boards/glowforge.h`. | `main` | GPL-3.0-or-later |
| `grblHAL-core` | The fork of the grblHAL core that the driver uses. Minimum change, no rationale comments. | `forgefirm` | The upstream grblHAL license | | `grblHAL-core` | The fork of the grblHAL core that the driver uses. Minimum change, no rationale comments. | `forgefirm` | The upstream grblHAL license |
| `kernel-module-glowforge` | `glowforge.ko`: the SDMA + EPIT pulse engine, the laser latch, the safety readbacks, the sensors. | `master` | GPL-2.0-or-later | | `kernel-module-glowforge` | `glowforge.ko`: the SDMA + EPIT pulse engine, the laser latch, the safety readbacks, the sensors. | `master` | GPL-2.0-or-later |
| `python3-gfhardware` | The `gfhardware` hardware library and the cloud-mode applications in `forgefirm-app/`. | `master` | MIT, with one LGPL-2.1-or-later component | | `python3-gfhardware` | The `gfhardware` hardware library and the cloud-mode applications in `forgefirm-app/`. | `master` | MIT, with one LGPL-2.1-or-later component |
| `Glowforge-Utilities` | `gfutilities` on PyPI: the factory protocol and service layer that cloud mode uses. | `master` | MIT | | `Glowforge-Utilities` | `gfutilities` on PyPI: the factory protocol and service layer that cloud mode uses. | `master` | MIT |
| `forgefirm-docs` | The documentation site. | `main` | CC BY-SA 4.0 | | `forgefirm-docs` | The documentation site. | `main` | CC BY-SA 4.0 |
| `openglow-serial-adapter` | The USB-C serial-console adapter for the control board. | `main` | CC BY-NC-SA 4.0 | | `openglow-serial-adapter` | The USB-C serial-console adapter for the control board. | `main` | CC BY-NC-SA 4.0 |
The full table, the license details, and the component diagram are on the The full table, the license details, and the component diagram are on the
site: <https://docs.forgefirm.org/developers/>. site: <https://docs.forgefirm.org/developers/>.
### Safety first, and in that order ### Safety first, and in that order
The machine is a laser, and the operator is the safety authority at it. These The machine is a laser, and the operator is the safety authority at it. These
rules bind every change, in every repository, that can affect what the machine rules bind every change, in every repository, that can affect what the machine
does. does.
- The hardware chain is the safety boundary. Software only adds gates on top - The hardware chain is the safety boundary. Software only adds gates on top
of it. `LASER_ON` is never a bare GPIO. The kernel laser latch is locked by of it. `LASER_ON` is never a bare GPIO. The kernel laser latch is locked by
default, and every close of the pulse device locks it again. default, and every close of the pulse device locks it again.
- Never defeat a switch, an interlock, or a readback, in hardware or in - Never defeat a switch, an interlock, or a readback, in hardware or in
software, not even for a test. software, not even for a test.
- Never change a fire gate, a thermal limit, or a safety default to make a - Never change a fire gate, a thermal limit, or a safety default to make a
test pass. test pass.
- The order of work is absolute: emission and motion first, robustness and - The order of work is absolute: emission and motion first, robustness and
hygiene after. Review a change that touches emission or motion for that hygiene after. Review a change that touches emission or motion for that
before anything else. before anything else.
- A change that can put energy where it was not commanded gets a regression - A change that can put energy where it was not commanded gets a regression
test with the fix, in the same commit, never after. test with the fix, in the same commit, never after.
- Position counters, homing anchors, and a homed flag are not proof of - Position counters, homing anchors, and a homed flag are not proof of
physical motion. The head accelerometer is, and so are the operator's eyes. physical motion. The head accelerometer is, and so are the operator's eyes.
### Proof before done ### Proof before done
A feature or fix is not complete until it is proven. The order of preference: A feature or fix is not complete until it is proven. The order of preference:
1. A host test that runs in CI. The Test page of the site lists the host tests 1. A host test that runs in CI. The Test page of the site lists the host tests
of each repository. of each repository.
2. A bench drill on the bench reference, recorded in the commit message that 2. A bench drill on the bench reference, recorded in the commit message that
carries the change. carries the change.
3. Documented reasoning. 3. Documented reasoning.
Also: Also:
- Run the host tests of this repository before every commit. Where the build - Run the host tests of this repository before every commit. Where the build
uses `-Werror`, a warning is a failure. uses `-Werror`, a warning is a failure.
- A component that ships in the image is also evaluated against the release - A component that ships in the image is also evaluated against the release
acceptance catalog in the `forgefirm` repository (Test page, "Coverage acceptance catalog in the `forgefirm` repository (Test page, "Coverage
currency"). A behavior change with no catalog consequence gets a sentence currency"). A behavior change with no catalog consequence gets a sentence
of justification in the commit message. of justification in the commit message.
- For a component that ships in the image, the proof build is the Yocto - For a component that ships in the image, the proof build is the Yocto
cross-build that the Build page of the site defines, never a native host cross-build that the Build page of the site defines, never a native host
build. build.
- Report outcomes faithfully. Quote failing output as it is. Name a skipped - Report outcomes faithfully. Quote failing output as it is. Name a skipped
step as skipped. Never narrate an expected result as an observed one. step as skipped. Never narrate an expected result as an observed one.
### The workflow: prove locally, push when proven ### The workflow: prove locally, push when proven
- Nothing goes to a public repository until it is proven: in the host tests - Nothing goes to a public repository until it is proven: in the host tests
for host-only changes, on the bench for changes that alter what the machine for host-only changes, on the bench for changes that alter what the machine
does. does.
- Iterate locally. Then make one commit and one push for the proven change. - Iterate locally. Then make one commit and one push for the proven change.
No chains of fix-up pushes. Every push runs CI, and CI minutes are a budget. No chains of fix-up pushes. Every push runs CI, and CI minutes are a budget.
- Commit only finished work, and only when asked. Never commit intermediate - Commit only finished work, and only when asked. Never commit intermediate
findings, working notes, plans, audits, or status files. If a conclusion is findings, working notes, plans, audits, or status files. If a conclusion is
still moving, it is not ready for a repository. Unpushed mistakes come out still moving, it is not ready for a repository. Unpushed mistakes come out
with `git reset --mixed <base>`, which keeps the working tree. with `git reset --mixed <base>`, which keeps the working tree.
- "Commit" and "commit and build" include the push of every touched - "Commit" and "commit and build" include the push of every touched
repository, in dependency order. Never hold a push back to protect earlier repository, in dependency order. Never hold a push back to protect earlier
unpushed commits on the same branch. The only exception is an explicit "do unpushed commits on the same branch. The only exception is an explicit "do
not push" for that session. not push" for that session.
- Never push, force-push, tag, cut a release, refresh a lockfile, bump a - Never push, force-push, tag, cut a release, refresh a lockfile, bump a
submodule pointer, or bump a pin unless asked. submodule pointer, or bump a pin unless asked.
### Pins ### Pins
A firmware component reaches the image only through its pin: an exact A firmware component reaches the image only through its pin: an exact
`SRCREV` in `meta-forgefirm` (in the `forgefirm` repository) for ForgeFIRM `SRCREV` in `meta-forgefirm` (in the `forgefirm` repository) for ForgeFIRM
components, or in `meta-openglow` for BSP components. There is no `AUTOREV`. components, or in `meta-openglow` for BSP components. There is no `AUTOREV`.
A commit in a component repository changes nothing on a machine until its pin A commit in a component repository changes nothing on a machine until its pin
moves. The order is always: push the source repository, bump its pin, then moves. The order is always: push the source repository, bump its pin, then
run `bitbake -c fetch <recipe>` to make sure that the pin resolves. Some run `bitbake -c fetch <recipe>` to make sure that the pin resolves. Some
pairs of repositories have a CI coupling that fixes the push order between pairs of repositories have a CI coupling that fixes the push order between
them. The Release flow page of the site lists them, and each affected them. The Release flow page of the site lists them, and each affected
repository names its own in the section above. repository names its own in the section above.
### Git conventions ### Git conventions
- A commit is attributed to the human who is responsible for it, in both the - A commit is attributed to the human who is responsible for it, in both the
author and the committer fields. Never list an AI assistant as an author or author and the committer fields. Never list an AI assistant as an author or
a co-author. Never add an AI attribution trailer or a "Generated with" line a co-author. Never add an AI attribution trailer or a "Generated with" line
to a commit message or a pull request. In a fresh clone, set the local to a commit message or a pull request. In a fresh clone, set the local
`user.name` and `user.email` before the first commit. `user.name` and `user.email` before the first commit.
- A commit message says what changed and why, in the present tense, in - A commit message says what changed and why, in the present tense, in
Simplified Technical English. The "why" of a change to fork code lives here Simplified Technical English. The "why" of a change to fork code lives here
and nowhere else. and nowhere else.
- Keep line endings LF in every file that Linux tooling consumes: patches, - Keep line endings LF in every file that Linux tooling consumes: patches,
shell scripts, recipes, device trees. Check the bytes after an edit from a shell scripts, recipes, device trees. Check the bytes after an edit from a
Windows tool. A CRLF patch breaks `do_patch`. Windows tool. A CRLF patch breaks `do_patch`.
- Never commit build output, `__pycache__`, virtual environments, editor - Never commit build output, `__pycache__`, virtual environments, editor
files, a local knowledge graph (`graphify-out/`), captured machine data that files, a local knowledge graph (`graphify-out/`), captured machine data that
carries an identity, tokens, keys, or passwords. carries an identity, tokens, keys, or passwords.
- Never rewrite published history unless the operator asks for it. - Never rewrite published history unless the operator asks for it.
- A pull request to an upstream repository is never automatic. The developer - A pull request to an upstream repository is never automatic. The developer
decides if and when to send one. You can remind them that upstream decides if and when to send one. You can remind them that upstream
candidates exist, but the decision is theirs. candidates exist, but the decision is theirs.
### Writing rules ### Writing rules
They apply to everything: documentation, README files, code comments, They apply to everything: documentation, README files, code comments,
docstrings, log and console text, commit messages, issue text, and replies. docstrings, log and console text, commit messages, issue text, and replies.
- **American English.** analyze, behavior, color, center, gray, catalog, - **American English.** analyze, behavior, color, center, gray, catalog,
license, judgment, program, artifact, percent, toward, among, while, license, judgment, program, artifact, percent, toward, among, while,
learned. The style lint in `forgefirm-docs` rejects the British forms. learned. The style lint in `forgefirm-docs` rejects the British forms.
- **ASD-STE100 Simplified Technical English.** Short sentences: 20 words in - **ASD-STE100 Simplified Technical English.** Short sentences: 20 words in
a procedure, 25 in a description. One topic per sentence, one instruction a procedure, 25 in a description. One topic per sentence, one instruction
per sentence. Active voice, imperative in procedures, simple present in per sentence. Active voice, imperative in procedures, simple present in
descriptions. "Must" for necessity, "can" for possibility. No "should", descriptions. "Must" for necessity, "can" for possibility. No "should",
"would", "could", "may". Prefer: do, make sure, use, start, show, occur, "would", "could", "may". Prefer: do, make sure, use, start, show, occur,
before, after, because, for example, that is. No "etc.", no "and/or". before, after, because, for example, that is. No "etc.", no "and/or".
Noun clusters of three words at most. Warnings and cautions come before the Noun clusters of three words at most. Warnings and cautions come before the
step they protect. Warm and direct is good. A joke that shades a fact is step they protect. Warm and direct is good. A joke that shades a fact is
not. not.
- **No em dashes.** Never, anywhere. Use a colon, a period, or a comma. - **No em dashes.** Never, anywhere. Use a colon, a period, or a comma.
- **Present tense, present state.** Text describes the code and the machine - **Present tense, present state.** Text describes the code and the machine
as they are. No history narrative, no "the old version did", no "evolved as they are. No history narrative, no "the old version did", no "evolved
from", no story of how the code got here. Upstream copyright and from", no story of how the code got here. Upstream copyright and
derivation attribution to public projects stays: that is license credit, derivation attribution to public projects stays: that is license credit,
not narrative. not narrative.
- **No workstation paths.** Nothing outside a repository appears as a path in - **No workstation paths.** Nothing outside a repository appears as a path in
it: no drive letters, no WSL mounts, no home directories, no sibling-repo it: no drive letters, no WSL mounts, no home directories, no sibling-repo
relative paths, no private reference directories. Name the artifact relative paths, no private reference directories. Name the artifact
instead: "the captured factory pulse files", "that bench session". instead: "the captured factory pulse files", "that bench session".
- **No bench-machine identity.** Never a hostname, a serial number, a fuse - **No bench-machine identity.** Never a hostname, a serial number, a fuse
value, a private IP address, or a login of the bench machine, in any file, value, a private IP address, or a login of the bench machine, in any file,
comment, commit message, sample, or test fixture. Use neutral placeholders comment, commit message, sample, or test fixture. Use neutral placeholders
of the `ABC-123` form. Record the fact of a verification, never the values. of the `ABC-123` form. Record the fact of a verification, never the values.
- **No factory firmware code.** Never cite the factory firmware binary or its - **No factory firmware code.** Never cite the factory firmware binary or its
code: no offsets, no addresses, no quoted or decompiled code. State the code: no offsets, no addresses, no quoted or decompiled code. State the
recovered fact (a formula, a constant, a behavior) and stop. Hardware recovered fact (a formula, a constant, a behavior) and stop. Hardware
addresses (IOMUX pad values, sensor registers, boot offsets) are fine. addresses (IOMUX pad values, sensor registers, boot offsets) are fine.
- **No rationale comments in fork code.** Code destined upstream (for - **No rationale comments in fork code.** Code destined upstream (for
example, the grblHAL core fork) carries the minimum change and no "why we example, the grblHAL core fork) carries the minimum change and no "why we
did this" comments. The reasoning goes in the commit message. Patches did this" comments. The reasoning goes in the commit message. Patches
carried in the Yocto layers are exempt. The `ForgeFIRM:` comment convention carried in the Yocto layers are exempt. The `ForgeFIRM:` comment convention
there is deliberate. there is deliberate.
- **Interface docs describe the lever, not the policy.** A sysfs attribute - **Interface docs describe the lever, not the policy.** A sysfs attribute
doc says what the attribute is, its range, its units, its conversion. How doc says what the attribute is, its range, its units, its conversion. How
the factory firmware drives it does not belong there. the factory firmware drives it does not belong there.
- **No definitive legal or regulatory statements.** The project is not a - **No definitive legal or regulatory statements.** The project is not a
lawyer. The only permitted form: modifying the machine, including lawyer. The only permitted form: modifying the machine, including
replacing its firmware, may have legal and regulatory ramifications, and it replacing its firmware, may have legal and regulatory ramifications, and it
is the end user's responsibility to adhere to the laws, regulations, is the end user's responsibility to adhere to the laws, regulations,
certifications, and insurance terms that apply where they are. Warranty certifications, and insurance terms that apply where they are. Warranty
wording is "may void your warranty", never "voids". Never cite a regulation, wording is "may void your warranty", never "voids". Never cite a regulation,
a standard, or a certification regime as applying or not applying. The a standard, or a certification regime as applying or not applying. The
affiliation disclaimer lives in the site footer only. It is also the user's affiliation disclaimer lives in the site footer only. It is also the user's
responsibility to make sure that they stay within the vendor's terms of responsibility to make sure that they stay within the vendor's terms of
service when they use a feature that calls that vendor's cloud services. service when they use a feature that calls that vendor's cloud services.
- **Copyright.** Copyright in this project belongs to 514 LLC d/b/a - **Copyright.** Copyright in this project belongs to 514 LLC d/b/a
OpenGlow. Every new source file carries two lines in its header, in the OpenGlow. Every new source file carries two lines in its header, in the
comment style of the file: `Copyright <year> 514 LLC d/b/a OpenGlow` and comment style of the file: `Copyright <year> 514 LLC d/b/a OpenGlow` and
`Written by Scott Wiederhold`. Keep the year, or the year range, that `Written by Scott Wiederhold`. Keep the year, or the year range, that
the file already has. The copyright notices of other holders stay the file already has. The copyright notices of other holders stay
unchanged. unchanged.
- **SPDX.** Every new source file carries an `SPDX-License-Identifier` line - **SPDX.** Every new source file carries an `SPDX-License-Identifier` line
under the license of its repository. under the license of its repository.
### Where documentation goes ### Where documentation goes
- **One home.** A fact lives on the documentation site, or it does not exist. - **One home.** A fact lives on the documentation site, or it does not exist.
A repository README says what the repository is, how to build and test it, A repository README says what the repository is, how to build and test it,
and where the documentation is. Nothing else. and where the documentation is. Nothing else.
- **The currency rule.** A change carries a documentation commit when it adds, - **The currency rule.** A change carries a documentation commit when it adds,
removes, or renames an interface (a sysfs attribute, an HTTP route, a removes, or renames an interface (a sysfs attribute, an HTTP route, a
settings key, a G-code or `$` setting), or when it corrects a measured settings key, a G-code or `$` setting), or when it corrects a measured
fact. A measured fact says how it was obtained, and on what: unless the page fact. A measured fact says how it was obtained, and on what: unless the page
says otherwise, a measurement on the site was taken on the bench reference, says otherwise, a measurement on the site was taken on the bench reference,
which the site defines. which the site defines.
- **A moved document is deleted.** No stub and no redirect stays at the old - **A moved document is deleted.** No stub and no redirect stays at the old
path. path.
- **Every diagram is Mermaid.** No ASCII art and no image of a diagram. - **Every diagram is Mermaid.** No ASCII art and no image of a diagram.
- There is no roadmap page. Open items are tracked as GitHub issues once the - There is no roadmap page. Open items are tracked as GitHub issues once the
repositories accept them. repositories accept them.
- Do not add plan files, audit files, working notes, or status files to any - Do not add plan files, audit files, working notes, or status files to any
repository. The project has **no status document and no dated log**: the repository. The project has **no status document and no dated log**: the
site describes the present, and the record of what was done, how it was site describes the present, and the record of what was done, how it was
proven, and what it replaced goes in the commit message that carries the proven, and what it replaced goes in the commit message that carries the
change. change.
### Analysis and reporting ### Analysis and reporting
- Rank engineering options on technical merit only: performance, correctness, - Rank engineering options on technical merit only: performance, correctness,
robustness, verifiability. Process cost (an acceptance campaign, an image robustness, verifiability. Process cost (an acceptance campaign, an image
flash, a new dependency) is a one-line footnote, never a ranking factor. flash, a new dependency) is a one-line footnote, never a ranking factor.
The operator decides the process cost. The operator decides the process cost.
- Never infer or assume a hardware fact. Label every unverified claim as - Never infer or assume a hardware fact. Label every unverified claim as
unverified, and say how to verify it. unverified, and say how to verify it.
- Report only what the observations confirm. Everything else is labeled - Report only what the observations confirm. Everything else is labeled
"unconfirmed" and is not acted on. "unconfirmed" and is not acted on.
### General practice for agents ### General practice for agents
- Read the README of this repository, this file, and the Developers section - Read the README of this repository, this file, and the Developers section
of the site before you change code. of the site before you change code.
- Orient in the code before you edit. If a local knowledge graph - Orient in the code before you edit. If a local knowledge graph
(`graphify-out/`) exists in the working tree or its parent, query it first. (`graphify-out/`) exists in the working tree or its parent, query it first.
It is a local artifact and is never committed. It is a local artifact and is never committed.
- Keep a change minimal and scoped to the request. No drive-by reformatting, - Keep a change minimal and scoped to the request. No drive-by reformatting,
no unrelated cleanups, no renames for taste. Match the style of the no unrelated cleanups, no renames for taste. Match the style of the
surrounding code. surrounding code.
- Do not add a dependency without a stated reason. The target is a - Do not add a dependency without a stated reason. The target is a
single-core machine with a small eMMC, and every package rides the image. single-core machine with a small eMMC, and every package rides the image.
- Extend an existing test or tool instead of adding a parallel one. - Extend an existing test or tool instead of adding a parallel one.
- Never create a file in the repository that the request does not need. - Never create a file in the repository that the request does not need.
- Ask before anything destructive or outward-facing: a push, a force-push, a - Ask before anything destructive or outward-facing: a push, a force-push, a
tag, a release, a history rewrite, or any change to a machine. tag, a release, a history rewrite, or any change to a machine.
- When a fact is unknown, say so and say how to find out. Never fill a gap - When a fact is unknown, say so and say how to find out. Never fill a gap
with a plausible number. with a plausible number.
- Use the exact names of the project: kas, bitbake, pin, SRCREV, campaign, - Use the exact names of the project: kas, bitbake, pin, SRCREV, campaign,
fingerprint, drill, sysfs, the latch, the armed window. Do not invent names. fingerprint, drill, sysfs, the latch, the armed window. Do not invent names.
### Before you commit ### Before you commit
1. The host tests of this repository pass, with `-Werror` where the build 1. The host tests of this repository pass, with `-Werror` where the build
uses it. uses it.
2. The change is proven at the highest level available: CI test, bench drill, 2. The change is proven at the highest level available: CI test, bench drill,
or documented reasoning. or documented reasoning.
3. For a component that ships in the image: the acceptance catalog covers the 3. For a component that ships in the image: the acceptance catalog covers the
changed behavior, or the commit message says why it has no catalog changed behavior, or the commit message says why it has no catalog
consequence. consequence.
4. New files carry the 514 LLC d/b/a OpenGlow copyright, the `Written by` 4. New files carry the 514 LLC d/b/a OpenGlow copyright, the `Written by`
line, and an SPDX line. Line endings are LF. line, and an SPDX line. Line endings are LF.
5. No em dashes, no British spellings, no workstation paths, no bench 5. No em dashes, no British spellings, no workstation paths, no bench
identity, no factory firmware code, no history narrative, no AI identity, no factory firmware code, no history narrative, no AI
attribution. attribution.
6. Documentation is current: interfaces and measured facts (the currency 6. Documentation is current: interfaces and measured facts (the currency
rule). rule).
7. The commit is one settled change, attributed to the human author, and it 7. The commit is one settled change, attributed to the human author, and it
is pushed only when the operator asks. is pushed only when the operator asks.
File diff suppressed because it is too large Load Diff