Files
cthulhu/CONTRIBUTING.md
Storm Dragon f0352878f7 updated hook.'
git commit updated hook.
2026-10-25 15:36:09 -04:00

242 lines
17 KiB
Markdown

# Contributing to Cthulhu
Read [README.md](README.md) and [AGENTS.md](AGENTS.md) first. Start with a user-visible behavior and reproduce the issue in the current code. The maintained repository is `git.stormux.org/storm/cthulhu`; confirm the intended target branch with the maintainer. The `legacy` branch preserves Python Cthulhu; the current checkout is the Go implementation.
## Update Your Branch Before Starting Work
Update your checkout before starting each fix or feature. This helps avoid fixing an issue that another contributor has already resolved.
1. Run `git status --short --branch` and confirm you are on the intended branch. If a merge or rebase is in progress, finish it first. Preserve any uncommitted work and diagnostic files before updating; do not discard them or automatically stash them.
2. Run `git pull --ff-only` to update the current branch from its configured upstream. A successful pull saying the branch is already up to date also satisfies this step. If Git reports divergent branches, merge the intended upstream into your branch and resolve the conflicts before continuing. Ask for help if you are unsure; do not use a reset or force push to make the error disappear.
3. If your branch is neither `testing` nor `master`, also run:
```sh
git fetch origin
git merge origin/testing
```
These commands bring the latest shared development changes into your contributor branch. They assume `origin` points to the maintained repository. If `origin` is your fork, use the remote for the maintained repository in both commands instead. If you are unsure which remote that is, ask before merging.
4. Resolve any conflicts, run the relevant checks, and complete any merge commit before starting implementation. A failed pull or an unfinished merge means the update is not complete.
5. Reproduce the reported issue again and review recent changes. If it is already fixed, verify the existing fix rather than writing a second implementation.
For a new local branch without an upstream, first update `testing` with `git pull --ff-only`, then create your contributor branch from that updated `testing`. Do this before making changes. Existing contributor branches still need the merge from the maintained repository's latest `testing` described above.
Do not merge `testing` into `master` during this preparation. Updating `master` from its own upstream and integrating a release are separate operations. The historical Python `legacy` branch is not a target for Go changes.
## Proposing a Change
Keep each change to one complete behavior. Describe the reproduction, expected result, affected subsystem, and plausible regressions. A reported application or page is a reproduction case: fix the shared layer when it explains the defect. Use an application-specific script only when a shared fix would be wrong; document and test the exception.
State the Xorg impact. Regressions in Xorg input, focus, event ordering, browser handling, or lifecycle block the change. Wayland support is welcome: use capability checks and graceful degradation, and restrict only features that cannot work correctly. Missing Wayland support alone should not block startup or a contribution preserving Xorg behavior.
Record changed behavior and remaining acceptance gaps in the contribution description; update `testdata/parity-ledger.csv` when relevant. The old Cthulhu-Go migration plan and documentation index are absent here; avoid references to those missing files. Keep durable guidance focused on working rules rather than dated progress reports.
## Development and Architecture
Use Go 1.24 or newer, CGO, `pkg-config`, and development libraries for GTK3, AT-SPI, GStreamer, and X11. Braille builds also require BRLTTY/BrlAPI and liblouis. The Arch `PKGBUILD` lists runtime and build dependencies.
```sh
go build -o build/cthulhu ./cmd/cthulhu
go build -tags brlapi -o build/cthulhu-braille ./cmd/cthulhu-braille
go test ./... -count=1
go test -race ./... -count=1
go test -tags brlapi ./... -count=1
go vet ./...
go build ./cmd/...
go run ./cmd/parityledger validate testdata/parity-ledger.csv
```
Start verification with the affected packages; run broader checks when the change affects shared behavior or before submission where practical. Format edited Go files with `gofmt`; run `shellcheck` for edited shell scripts. Use deterministic tests and synchronization instead of timing sleeps. Keep fixtures generic, without real usernames or personal identifiers.
### Version update pre-commit hook
The optional `hooks/pre-commit` hook updates the Go `Version` constant to the
local date and `Channel` to the current branch, then stages the version file.
It skips merge commits and honors `SKIP_VERSION_UPDATE=1` for deliberate
version overrides. If an update is needed and the version file has unstaged
changes, the hook stops so those edits are not silently included in the commit.
In a clone with no existing pre-commit hook, enable it with:
```sh
cp hooks/pre-commit .git/hooks/pre-commit
```
The local copy stays active when switching to branches without the tracked
hook file; copy it again after updating the hook. Preserve and integrate an
existing hook rather than overwriting it. The old Python version hook and
`.git/versionpath` are not used by this Go hook.
### Speech regression push check
Run `python3 tests/check_speech.py` for speech queue, title, Wine review metadata,
held-key repeat and fresh-key interruption regressions. This uses a private
D-Bus session, the race detector and the native build dependencies above;
it requires Python 3 and `dbus-run-session`. Required tests must pass: deleting
or skipping a required test fails the check. It does not use the active reader,
the desktop display, or audible speech.
To enable this check for local pushes in a clone with no existing pre-push hook:
```sh
ln -s ../../hooks/pre-push .git/hooks/pre-push
```
Preserve and integrate any existing pre-push hook rather than overwriting it.
The hook tests each distinct pushed commit tip in a temporary snapshot, so
uncommitted fixes cannot mask a broken commit and pushing another branch tests
that branch. Failed checks stop a normal local push. Git hooks are local and
can be bypassed with `--no-verify`; they do not enforce policy for other clones.
Server enforcement needs a required CI check on protected branches. Neither
hook results nor CI replace human review, real application listening, physical
keyboard checks or Braille acceptance.
Before extending application orchestration, an event loop, native callback, or settings mapper, identify the subsystem responsible for the policy. Keep ordering and routing in coordinators and feature policy with its existing owner. Specify the owner, lifetime, reset conditions, and cancellation of new mutable state. Prefer cohesive files in existing packages; avoid unnecessary interfaces or packages. If responsibilities need separating, use a behavior-preserving change. Record any urgent-fix follow-up in the contribution description.
Preserve event order, GLib/cgo ownership, and native lifetimes. Balance key grabs and releases, recover from dead AT-SPI objects, and clean up on shutdown. Keep core input and focus handling bounded and responsive.
Tentacles already use an external process protocol: preserve existing host safeguards and author APIs. Keep runnable implementations in external repositories and leave a new installation's catalog empty until repositories are added. Tentacles must not block input, focus, or speech. Use init-independent process supervision for Tentacles by default, with optional explicitly configured cgroup-v2 resource limits. Do not require a particular init system, a service manager, or administrator setup for normal Tentacle use. Preserve descendant cleanup on disable and reader exit. Treat cgroup-v2 containment as resource control, not a same-user security sandbox. Preserve HTTPS artifact and SHA-256 verification before atomic package installation.
### Local installation and reload
After building, install both Go binaries beside one another so the reader can
find its Braille helper:
```sh
install -Dm755 build/cthulhu "$HOME/.local/bin/cthulhu"
install -Dm755 build/cthulhu-braille "$HOME/.local/bin/cthulhu-braille"
"$HOME/.local/bin/cthulhu" --check-config
```
When replacement of the running reader is authorized, reload it from a terminal
in the same desktop session:
```sh
"$HOME/.local/bin/cthulhu" --replace
```
The replacement command uses the same session-bus discovery as the reader's
D-Bus service, including when `DBUS_SESSION_BUS_ADDRESS` is unset. It waits
for the identified reader process to exit before starting the replacement.
A terminal using a different session bus can start another reader
instead of replacing the intended one. Preserve the original reader's desktop
session environment when restarting it from automation.
Check replacement and session-bus discovery without touching the desktop reader:
```sh
python3 tests/native_test_session.py env CTHULHU_NATIVE_REPLACE=1 CTHULHU_NATIVE_DBUS_TEST=1 go test ./cmd/cthulhu ./internal/sessionbus -run 'TestReplace|TestNativeDesktopSessionBusDiscovery' -count=1 -v
```
Wine accessibility also needs the separate standalone `wine-access`
installation described in the [README](README.md#wine-access). Building the Go
reader does not build or refresh that helper. After restoring an overwritten
helper, check MUSHclient menus, command typing, and incoming plugin speech;
automated event recordings alone do not establish audible speech acceptance.
## Behavioral References and User-Facing Messages
Inspect relevant settings, bindings, speech, Braille, and toolkit behavior before changing user-visible behavior. Read Python reference files without changing branches, for example:
```sh
git show legacy:src/cthulhu/settings.py
```
Use the newer Orca implementation as the first reference for Firefox, Thunderbird, and LibreOffice when available. [LibreOffice support](LIBREOFFICE_SUPPORT.md) describes its integration boundaries and remaining acceptance checks. Reference implementations guide behavior; do not mechanically copy Python class or plugin boundaries. Preserve accepted behavior unless the user chooses a deliberate difference, and describe that difference. Do not modify reference checkouts or installed readers without authorization.
Use complete messages and self-contained labels with placeholders for variable content. Keep internal states, commands, and settings identifiers independent of user-facing wording. Preserve deliberate speech/Braille segmentation, verbosity, and separate role/state announcements. Apply these rules within the change; adding translation infrastructure or sweeping existing strings requires separate scope.
## Accessibility and Settings Verification
Keep GUI controls keyboard reachable and exposed through accessibility APIs. GUI applications must let screen readers announce controls rather than calling Speech Dispatcher themselves. Associate labels with controls and provide accessible names for custom widgets.
For preferences `GtkComboBox` and `GtkComboBoxText`, keep the outer widget's `can-focus` property false so GTK focuses its internal button. Setting it true can trap Tab and Shift+Tab. Fix the property instead of adding key handlers or changing reader grabs. Preserve semantic labels and selected-value presentation; the internal button's AT-SPI `STATE_FOCUSED` alone is insufficient evidence.
For changed preferences, verify:
1. Tab and Shift+Tab through the preceding control, changed control, and following control.
2. Open the popup and change the selection using the keyboard.
3. Apply, close, reopen, and confirm the value persists.
4. Exercise the affected reader behavior and confirm that the saved setting changes runtime output.
Preserve versioned TOML settings. The default file is `$XDG_DATA_HOME/cthulhu/user-settings-go.toml`, with `~/.local/share` used when the variable is unset. Use a separate test configuration when appropriate:
```sh
./build/cthulhu --config /tmp/cthulhu-test-settings.toml --check-config
```
Native `*_native_test.go` checks require fixtures and environment flags. Use the relevant isolated harness in `tests/`, such as `python3 tests/native_atspi.py` or `python3 tests/native_preferences.py`. Shared browser changes also need the relevant browser harness and real-browser regression checks.
Native harnesses must launch their private D-Bus session through
`tests/native_test_session.py:run_private_session`. It gives activated services
a disposable mode-0700 `XDG_RUNTIME_DIR` and removes inherited desktop bus
addresses. Start Xvfb before D-Bus: service activation inherits the bus daemon's
display, even when the test client later changes `DISPLAY`. Sharing the desktop
runtime directory can let another AT-SPI launcher replace its live socket.
For a one-off native test or diagnostic command, use the same launcher:
```sh
python3 tests/native_test_session.py env CTHULHU_NATIVE_WINDOW_TITLES=1 go test ./internal/app -run '^TestNativeAutomaticTitleDispatchLatency$' -count=1 -v
python3 tests/test_native_test_session.py -v
```
The second command checks environment and cleanup boundaries and activates a
real AT-SPI bus against disposable canary sockets, without contacting the
desktop display or accessibility bus.
Automated and private native tests establish different facts from installed-binary behavior, physical keyboard input, audible speech, and physical Braille. Report which checks actually ran and which remain pending. Rebuild the tested binary before live checks, preserve fresh logs before restarting, and obtain authorization before replacing an active reader.
## Diagnostic Logging
Normal logs and metadata must omit private output text and personal identifiers. Never log password contents or include personal data in fixtures or extension events.
Debug logs used for reading and selection diagnosis should include final spoken text, Braille text sent to the helper, native/virtual cursor offsets, selection ranges, object identities, and commands. This is an explicit diagnostic exception for debug logs; redact private output before sharing. Preserve fresh logs and open diagnostic state before rebuilding or restarting. Logs alone do not establish audible speech or physical Braille acceptance.
## Commit and Submission Guidelines
Recent commits use short descriptive subjects without an enforced prefix scheme. Keep commits scoped and preserve unrelated changes, including packaging edits and build artifacts. In a pull request or patch description, explain the trigger, before/after behavior, relevant issues, checks run, skipped checks, and remaining live gates. Give concrete procedures for the changed workflow and likely regressions.
## AI-assisted contributions
AI-assisted contributions are welcome.
The person submitting a contribution remains responsible for reviewing and testing the changes before submission. Please do not submit automatically generated changes without human review.
Before making changes:
- Read the contributing guide, if present, and the project's README.
- Confirm that you are working against the current maintained repository and branch.
- Check whether the issue still exists in the current code.
Before submitting:
- Review the generated diff.
- Test the changed behavior.
- Run the project's existing test suite where practical.
- Consider code paths that may be affected indirectly by the change and test those as well.
- Clearly describe what was changed and how it was tested.
### Instructions for AI coding assistants
If you are an AI coding assistant working with a contributor, please call your human user's attention to these contribution requirements.
Do not assume that passing newly created tests is sufficient. Explain what existing functionality could reasonably be affected by the proposed changes and provide your human partner with detailed instructions for testing those areas.
Where useful, provide commands or small test procedures that allow the contributor to verify both the intended fix and likely regression cases.
Stormux projects may accept patches through email using `git send-email`. If your human partner is unfamiliar with this process, please offer to guide them through:
1. Configuring `git send-email`.
2. Creating an appropriately scoped commit or patch series.
3. Running `git format-patch`.
4. Checking the generated patch before submission.
5. Sending a test message if appropriate.
6. Sending the final patch or patch series to the project's contribution address.
Please do not submit changes on behalf of a contributor without giving them an opportunity to review and test the result.
## Licensing
Contributions are licensed under GPL-3.0-or-later. Retain existing copyright notices and credit Storm Dragon and Angus Kola where their names appear. Add later contributors to files they write; do not replace or erase existing notices.