Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
48d5e79
test(shipped): check completions command by command (3.5.0-DEV14, B127)
KeithRaghubar Oct 21, 2026
b9f9980
fix(man): generate ENVIRONMENT and JOURNAL from registries (3.5.0-B12…
KeithRaghubar Oct 21, 2026
03ae418
feat(config): check, clean and reset the live config (3.5.0-F18)
KeithRaghubar Oct 21, 2026
d85a4e5
test(standards): check citations in the design docs and .claude (3.5.…
KeithRaghubar Oct 21, 2026
2b61207
test(docs): check the concept-page rules (3.5.0-DEV16)
KeithRaghubar Oct 21, 2026
632fd30
fix(standards): a citation into a missing repo directory is still che…
KeithRaghubar Oct 21, 2026
7dafaa8
test: build every parsed command line for real; fix run kernel --keep…
KeithRaghubar Oct 22, 2026
0292a62
test: every parsed flag reaches the code that uses it (3.5.0-DEV17)
KeithRaghubar Oct 22, 2026
598027d
test(standards): a bare code name in the docs must exist in the code …
KeithRaghubar Oct 22, 2026
93a2b89
docs(design): describe the bare-name rule without quoting example nam…
KeithRaghubar Oct 22, 2026
512f351
test(config): every key the code reads is documented in the shipped d…
KeithRaghubar Oct 22, 2026
b579faa
feat(config): config check --json (3.5.0-F18)
KeithRaghubar Oct 22, 2026
86445b3
test: drop make_build_options' abi_check fallback and its stand-in (3…
KeithRaghubar Oct 22, 2026
049d214
feat(dev): surface snapshot gate, contributor rules, required CI (3.5…
KeithRaghubar Oct 22, 2026
a63b0a9
test: stub check-surface in the release-preflight fixture (3.5.0-DEV18)
KeithRaghubar Oct 22, 2026
f9d9562
fix(dev): CI runs once per PR commit; gitignored citations pass in a …
KeithRaghubar Oct 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/agents/pkgbuild-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ You review changes to:
- `sysforge/primitives/vcs_pkgver.py` — `[epoch:]pkgver-pkgrel` resolution for VCS sources
- `sysforge/primitives/source_meta.py` — `source_meta.toml` schema
- `sysforge/primitives/build_state.py` — `build_state.toml` schema
- `sysforge/update.py`, `sysforge/fetch.py`, `sysforge/converge.py` — call sites
- `sysforge/update.py`, `sysforge/fetch.py` — call sites

Reject the review request if the diff falls outside this scope; the user wants a generalist reviewer instead.

Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/pkgbuild-spec-check/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Trigger this whenever a change touches:

- [ ] **Source sync goes through the scheduler** (CLAUDE.md gotcha #3). Any new code path that needs a fresh PKGBUILD calls `sysforge.primitives.source_sync.get_scheduler().request(SyncRequest(...))` — never `git pull` directly.
- [ ] **`build_state.toml` invariants.** If you touch what's parsed from PKGBUILD, check whether the cached `build_state.toml` schema needs to evolve too.
- [ ] **Tests.** `tests/test_parser.py`, `tests/test_patcher.py`, `tests/test_pkgbuild_meta.py` (if present), and `tests/test_aur.py` are the regression nets — add or update cases that exercise the spec detail you just changed.
- [ ] **Tests.** `tests/test_parser.py`, `tests/test_patcher.py` and `tests/test_aur.py` are the regression nets — add or update cases that exercise the spec detail you just changed.

## Reporting

Expand Down
11 changes: 11 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- What changes, and why. Link the ROADMAP ID or issue. -->

## Checklist

CI checks most of this; the boxes are for what it cannot see.

- [ ] Release-note entry in `docs/release-notes/unreleased.md`, led by its roadmap ID
- [ ] If a user-facing surface changed: `make surface` committed, and its diff matches what I meant to change
- [ ] If a name was removed or renamed: the old one is in `tools/retired_names.toml` (config keys: `RETIRED_KEYS`)
- [ ] The guide for this feature (`docs/guides/`) still describes it correctly
- [ ] `make pre-release` (or `make ci-local`) passes locally
16 changes: 13 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
# Suite, lint and check-* gates on a clean Arch container (3.4.0-DEV1).
# Contributor-only, never shipped. Advisory: no branch protection until it has
# stayed green for one release cycle. The job body is tools/ci.sh; reproduce a
# red run locally with `make ci-local`.
# Contributor-only, never shipped. Required: a ruleset on main makes this
# `gates` job a required status check and changes arrive by pull request, so a
# red run blocks the merge. The job body is tools/ci.sh; reproduce a red run
# locally with `make ci-local`.
name: ci

on:
# A branch is checked through its pull request; push runs only for main, so a
# PR's commit is not tested twice.
push:
branches: [main]
pull_request:
workflow_dispatch:

# A newer push to the same PR cancels the run it supersedes.
concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
contents: read
Expand Down
10 changes: 8 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ make check-design # guard: DESIGN.md in sync with sources
make roadmap-view SORT=effort # print Planned table sorted by a column (read-only)
make check-shipped # guard: etc/sysforge, PKGBUILD*, hooks, completions, manpage parity
make check-standards
make surface # regenerate tests/data/surface.json after any user-facing change
make check-surface # guard: snapshot current; surface changes vs main named in release notes
make sync-config # adopt new shipped defaults into untracked live config (add-only)
make container-smoke[-cachyos] # packaging + portability checks in a container (needs make vm-pkg-stable first)
make ci-local # replay the CI job (.github/workflows/ci.yml) in a clean Arch container
Expand Down Expand Up @@ -75,19 +77,23 @@ Shipped-file edits must pass `make check-shipped`; doc/design edits `make check-
profiles`, profile store paths) updates its guide in the same change. Order: after README.
Concept pages (`docs/concepts/*.md`) explain the technique, not sysforge: no sysforge
vocabulary outside the closing "In sysforge" section, upstream sources cited, no numbers
measured on one machine; guides link them (and the glossary) rather than re-explaining.
measured on one machine (`tests/test_concept_pages.py` checks the closing sections, the upstream
links and the vocabulary); guides link them (and the glossary) rather than re-explaining.
- **`DOC` IDs are for user-facing docs only** (`docs/guides/`, `docs/concepts/`, README, man page) and file under
`## Changed` (patch; lint-enforced). Internal docs (design, CLAUDE.md, ROADMAP) get no ID;
wrong `--help`/man output is a `B`, since it is CLI behaviour.
- **`DEV` IDs are for contributor-only work** (only `tests/`, `tools/`, `Makefile`, `.claude/`,
dev docs) and file their release-note entry under `## Changed` only, like `DOC` (lint-enforced,
`3.4.0-STD1`). Touching `sysforge/` or a shipped file makes it `B`/`F`.
- **Completions stay in lockstep with the CLI** (`completions/_sysforge` + bash) in the same change.
- **A user-facing change regenerates `tests/data/surface.json`** (`make surface`) and names what
changed in the release notes; `make check-surface` (a required CI gate) enforces both.
- **Removing or renaming a flag, token or public name adds it to `tools/retired_names.toml`** in the
same change (unless the old spelling is still valid elsewhere); `make check-standards` then finds
every leftover, comments included. Written-down `sysforge …` commands and `§` references are
checked too (§Documentation consistency guards). Tests build `BuildOptions(...)`,
`RunOptions(...)` or `build_parser().parse_args([...])`, never a `SimpleNamespace` stand-in.
`RunOptions(...)` or `cli_args("state", "list", ...)` (`tests/cli_args.py`), never a
`SimpleNamespace` stand-in.
- **CLI verbs go through the Verb framework**: `Verb` subclass dispatched by `verbs.runner.run_verb`
(`pre_check`/`execute`/`post_validate`; `requires_sentinel=True` if it mutates). Its flags live
on the class (`add_parser` classmethod, ending `set_defaults(verb_cls=cls)`); register it in
Expand Down
35 changes: 29 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,41 @@ just as valuable — many features here started as workflow pain points.

## Ground rules for PRs

- `make test` and `make lint` must pass. Use the Makefile targets, not direct
`pytest`/`ruff` invocations.
- **`DESIGN.md` is generated** — edit the sources under `docs/design/*.md`, then run
Changes reach `main` by pull request, and the CI `gates` job is a required check: it runs
every gate in a clean Arch container, and a red run blocks the merge. Run the same set
locally with `make pre-release`, or reproduce CI exactly with `make ci-local` (podman).
`make install-hooks` adds a pre-commit hook running the fast gates, so most failures show
up before you push.

- Use the Makefile targets, not direct `pytest`/`ruff` invocations.
- **`DESIGN.md` is generated**: edit the sources under `docs/design/*.md`, then run
`make design`. Never edit `DESIGN.md` directly. Doc update order: `docs/design/*.md`
→ README.md → CLAUDE.md.
- CLI surface changes (new verb, flag, help text) must update
`completions/_sysforge` + `completions/sysforge.bash` and regenerate the man page
(`make man`) **in the same change**. `make check-shipped` verifies this.
- New logic that branches on the resolved compiler (gcc vs llvm/clang) ships with
tests for **both** paths.
- Keep behavior changes and refactors in separate commits where practical.

### Changing anything a user can see

A flag, command, config key, environment variable, `--json` field or log name is a
*surface*. Change one and, in the same PR:

| Also update | Enforced by |
|---|---|
| Both completion scripts (`completions/_sysforge`, `completions/sysforge.bash`) | `make check-shipped` (`completion_commands`) |
| The man page: `make man` (generated from the parser and the env/journal tables) | `make check-shipped` (`manpage`) |
| `tests/data/surface.json`: `make surface`; its diff is what a reviewer reads | `make check-surface` |
| A release-note entry in `docs/release-notes/unreleased.md` naming what changed | `make check-surface`, `make check-standards` |
| **Removing or renaming** a name: add the old one to `tools/retired_names.toml` (a config key: `RETIRED_KEYS` in `sysforge/primitives/config_schema.py`) | `make check-surface`, `make check-standards` (`retired_names`) |
| A **new config key**: document it in the shipped `etc/sysforge/*.toml` (and its twin under `tests/data/etc/sysforge/`) | `tests/test_config_keys_documented.py`, `make check-shipped` |
| A **new environment variable**: a row in `sysforge/primitives/env_vars.py` | `tests/test_env_vars.py` |
| A **new `--json` field**: its schema under `tests/data/json-schema/` | `tests/test_json_output.py` |
| The user guide for the feature (`docs/guides/`) | review only |

In tests, build the real objects: `BuildOptions(...)`, `RunOptions(...)`, or
`cli_args("state", "list", ...)` from `tests/cli_args.py` for a parsed command line.
`SimpleNamespace` stand-ins drift from the real thing (`tests/test_stand_ins.py`).

## Getting started

```bash
Expand Down
Loading
Loading