Skip to content

Commit 2f619e6

Browse files
committed
docs: config-format guide + release checklist; honest INDEX statuses
Two concrete, accurate docs written from the code hardened in this series: - docs/developer/CONFIG-FORMATS.adoc — the 8 formats, most-specific-first detection order (incl. the INI-vs-JSON and YAML-vs-KeyValue disambiguation), the addField invariants (non-empty keys, secret redaction), the YAML subset scope, and how to add a parser. Marked live in INDEX (was 'planned'). - docs/maintainer/RELEASE-CHECKLIST.adoc — the actual CI gates (six test suites + the ABI-contract regen/diff/comptime + Idris typecheck), the version/license/docs pre-tag gates, the manual gates, and the tag steps. Marked live in INDEX (was 'planned'). INDEX also records why the empty-scaffolding prune is deferred: verification/, docs/theory/, docs/reports/, docs/wikis/ are referenced by the governance layer (ANCHOR.a2ml, MAINTENANCE-CHECKLIST, panic-attacker), so deleting them needs a reviewed change that updates those references in lockstep — not an automated docs pass. The remaining planned docs (FFI module reference, panel-extension guide, architecture rationale, CI/CD guide, security runbook) stay 'planned'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TaWWedv6VQqeZaPvc94keN
1 parent e6fa040 commit 2f619e6

3 files changed

Lines changed: 184 additions & 2 deletions

File tree

docs/INDEX.adoc

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ _You build GSA, extend it, or contribute code across the Gossamer GUI → Zig FF
4040
| FFI module reference | *planned* | Per-module docs for the 11 FFI modules (signatures, the 18 result codes, examples)
4141
| Panel extension guide | *planned* | The PanLL clade system; registering a new panel; inheriting base clades
4242
| Game-profile authoring | *thin* | Expand the README snippet: field types, validation, port/protocol, debugging
43-
| Config-format guide | *planned* | How to add a parser to the 8-format `config_extract`
43+
| `docs/developer/CONFIG-FORMATS.adoc` | live | The 8 formats, detection order, `addField` invariants, YAML scope, and how to add a parser
4444
| Architecture rationale | *planned* | Why Ephapax / Idris2 / Zig / VeriSimDB; when to touch each layer
4545
|===
4646

@@ -55,7 +55,7 @@ _You release, run CI/CD, operate containers, and manage governance + security sc
5555
| `docs/architecture/THREAT-MODEL.adoc` | live | STRIDE, assets, trust boundaries, mitigations
5656
| `docs/DEPLOYMENT-RUNBOOK.adoc` | live | Build, container, VeriSimDB main+backup, health, backup/restore
5757
| `SECURITY.md` | live | Vulnerability reporting
58-
| Release checklist | *planned* | v1.0.0 must/should/could + sign-off criteria
58+
| `docs/maintainer/RELEASE-CHECKLIST.adoc` | live | CI gates (6 suites + ABI contract), version/license/docs gates, manual gates, tag steps
5959
| CI/CD guide | *planned* | `.github/workflows/` structure, standards-estate reusables (pins `4ddc926`), staleness check, adding a check
6060
| Security-scanning runbook | *planned* | Running/interpreting Hypatia + panic-attack + Scorecard; the `.hypatia-ignore` suppression mechanism (NOT `.hypatia-baseline.json` — see `NEUROSYM.a2ml`)
6161
| Container/quadlet ops | *thin* | Expand the runbook: `.container` format, systemd user units, day-to-day ops
@@ -78,3 +78,11 @@ subtrees (`theory/`, `reports/`, parts of `practice/`).
7878
*Decision pending:* either populate `docs/wikis/` and sync it, **or** (recommended)
7979
consolidate all narrative under `docs/` using the three audience paths above and
8080
prune the empty scaffolding. Until then, this index is the single navigation point.
81+
82+
NOTE: a mechanical prune is **not** clean — `verification/`, `docs/theory/`,
83+
`docs/reports/`, and `docs/wikis/` are referenced by the governance layer
84+
(`.machine_readable/anchors/ANCHOR.a2ml`, `docs/governance/MAINTENANCE-CHECKLIST`,
85+
`features/panic-attacker/`). Deleting the trees without updating those references
86+
risks breaking governance/CI expectations, so the prune is deferred to a
87+
dedicated, reviewed change that updates the references in lockstep rather than
88+
bundled into an automated docs pass.

docs/developer/CONFIG-FORMATS.adoc

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: CC-BY-SA-4.0
2+
// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
3+
= GSA Config-Format Guide
4+
:toc:
5+
:source-highlighter: rouge
6+
7+
How `src/interface/ffi/src/config_extract.zig` detects and parses game-server
8+
configuration files, and how to add support for a new format.
9+
10+
== Overview
11+
12+
GSA extracts a game server's configuration into a flat list of typed fields
13+
(`ParsedConfig.fields`), which the A2ML emitter then serialises with provenance.
14+
Every server config — whatever its on-disk syntax — is normalised into the same
15+
`ConfigField { key, value, field_type, label, default_val, range_min,
16+
range_max, is_secret }` shape.
17+
18+
Two entry points:
19+
20+
* `detectFormat(data) ConfigFormat` — sniff the format from the bytes.
21+
* `parseAuto(allocator, data) !ParsedConfig` — detect, then dispatch to the
22+
matching parser.
23+
24+
== The eight formats
25+
26+
[cols="1,3,2",options="header"]
27+
|===
28+
| `ConfigFormat` | Detection signal | Parser
29+
| `XML` | `<?xml` prefix, or `<` followed by a letter | `parseXML`
30+
| `JSON` | leading `{`, or `[` followed by `{`/`"`/digit/`-`/`tr`/`fa`/`nu` | `parseJSON` (delegates to `std.json`)
31+
| `TOML` | `[[table]]` headers, or `[section]` + dotted `a.b = c` keys | `parseTOML`
32+
| `INI` | `[section]` headers (no dotted keys) | `parseINI`
33+
| `ENV` | `export KEY=...` lines | `parseENV`
34+
| `Lua` | `key = { ... }` table literals | `parseLua`
35+
| `YAML` | leading `---`, or `key: value` mappings / `- item` sequences with **no** `=` lines | `parseYAML`
36+
| `KeyValue` | fallback: `key=value` / `key: value` with no other signal | `parseKeyValue`
37+
|===
38+
39+
Detection is deliberately ordered most-specific-first. The ambiguous cases are
40+
handled explicitly:
41+
42+
* `[network]` is INI, not a JSON array — the JSON branch requires a 2-character
43+
lookahead (`[tr`, `[fa`, `[nu`) before treating `[` + letter as JSON.
44+
* A `key: value` file with no `=` and no `[section]` is YAML, not KeyValue — but
45+
a bare `a=1` file stays KeyValue. `eq_lines == 0` is the discriminator, so a
46+
colon in a value (a URL, a sentence) does not trip YAML detection.
47+
48+
== Parser conventions
49+
50+
All parsers funnel field creation through `ParsedConfig.addField`. Two
51+
invariants are enforced there, once, for every format:
52+
53+
* **Non-empty keys.** A field whose key is empty (a lone `=value` line, a JSON
54+
key of `""`) is silently dropped — it would break `getField` lookup and A2ML
55+
emission. This invariant is asserted by the config fuzz harness
56+
(`zig build fuzz`).
57+
* **Secret redaction.** Keys containing `password`, `secret`, `token`, or
58+
`rcon.password` are flagged `is_secret = true`; the A2ML emitter renders their
59+
values as `[REDACTED]`.
60+
61+
Nested structures flatten to dotted keys: `server.rcon.password`,
62+
`worlds.0`, `worlds.1`. This is uniform across TOML, Lua, JSON, and YAML so
63+
downstream code never has to care which syntax a value came from.
64+
65+
=== YAML scope
66+
67+
`parseYAML` is a *scoped subset*, not a full YAML 1.2 implementation — the same
68+
level as `parseTOML`/`parseLua`. It handles:
69+
70+
* block mappings (indentation → dotted keys),
71+
* block sequences of scalars (`- item` → `parent.N`),
72+
* scalar values with optional single/double quotes,
73+
* `#` comments and `---` / `...` document markers.
74+
75+
Out of scope (documented, not silently wrong): anchors/aliases, flow
76+
collections (`{a: 1}`, `[1, 2]`), and multi-line/folded scalars.
77+
78+
== Adding a new format
79+
80+
. Add a variant to `ConfigFormat` (keep the integer stable — it crosses the
81+
ABI as a `u8`; mirror it in `GameServerAdmin.ABI.Types.ConfigFormat`).
82+
. Write `parseXYZ(allocator, data) !ParsedConfig`, routing every field through
83+
`addField` so the invariants above hold for free.
84+
. Add a detection branch to `detectFormat`, ordered by specificity, and be
85+
explicit about any ambiguity with existing formats.
86+
. Add the dispatch arm to `parseAuto`.
87+
. Add tests: a detection test (including a negative case proving you don't
88+
steal from an adjacent format) and a parse test asserting the flattened keys.
89+
The fuzz harness (`src/fuzz_config.zig`) will exercise the new parser on
90+
arbitrary bytes automatically once it is reachable from `parseAuto`.
91+
92+
== See also
93+
94+
* `docs/developer/ABI-FFI-README.adoc` — the ABI these fields cross.
95+
* `src/interface/ffi/test/integration_test.zig` — per-format parse tests.
96+
* `src/interface/ffi/src/fuzz_config.zig` — the fuzz harnesses.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// SPDX-License-Identifier: CC-BY-SA-4.0
2+
// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
3+
= GSA Release Checklist
4+
:toc:
5+
6+
The steps to cut a GSA release. The release itself is automated —
7+
`.github/workflows/release.yml` fires on a `v*` tag, builds `libgsa` + the
8+
`gsa` CLI with Zig, packages a tarball, generates a `git-cliff` changelog, and
9+
attaches SLSA build-provenance. This checklist is what to verify *before*
10+
pushing the tag.
11+
12+
== Gate 1 — CI is green on `main`
13+
14+
All must pass on the commit you intend to tag:
15+
16+
* `Cross-Platform Build & Test` — `zig build` + the six test suites: `test`,
17+
`test-integration`, `test-smoke`, `test-property`, `test-behavioral`,
18+
`test-cli` (plus the `fuzz` seed corpus).
19+
* `ABI Contract` — `zig-contract` (regenerates `abi_layout_expected.zig` +
20+
`result_codes_expected.zig` from the Idris2 model and fails on drift; runs the
21+
comptime cross-check) **and** `idris-typecheck` (type-checks
22+
`src/interface/abi/gsa-abi.ipkg` in the pinned `idris2-pack` container).
23+
* `CodeQL`, `Scorecard`, SonarCloud quality gate, Hypatia scan (critical=0,
24+
high=0).
25+
26+
`panic-attack assail .` is the local pre-commit gate; the static-analysis CI
27+
workflow covers it when the estate tool is installed.
28+
29+
== Gate 2 — Version is reconciled
30+
31+
There is not yet a single-source-of-truth version. Before tagging, confirm the
32+
following agree on the release number: `src/interface/ffi/src/main.zig`
33+
(`VERSION`, `BUILD_INFO`), `src/interface/ffi/build.zig` (`.version` ×2),
34+
`run.js`, `panels/manifest.json`, `panels/*/panel.json`, and
35+
`.machine_readable/6a2/*.a2ml`. (Follow-up: a `scripts/check_version_drift.sh`
36+
CI gate once the canonical location is chosen.)
37+
38+
== Gate 3 — License is settled
39+
40+
*Blocking, one-time.* The LICENSE file + all Zig/Idris source SPDX headers are
41+
MPL-2.0; the panel descriptors and `META.a2ml` declare AGPL-3.0-or-later. Pick a
42+
direction, reconcile every artifact, and record it in `docs/legal/` before the
43+
first tagged release. See `.machine_readable/6a2/META.a2ml` for the flagged
44+
conflict.
45+
46+
== Gate 4 — Docs reflect reality
47+
48+
* `.machine_readable/6a2/STATE.a2ml` completion % and session history updated.
49+
* `docs/INDEX.adoc` statuses (`live`/`thin`/`planned`) match the tree.
50+
* `CHANGELOG` / release notes — `git-cliff` generates these from Conventional
51+
Commit messages, so confirm the commit log is clean.
52+
53+
== Manual gates (outside CI — see also the project human checklist)
54+
55+
These cannot be done by an agent and gate a *feature-complete* v1.0.0, not the
56+
mechanics of tagging:
57+
58+
[cols="1,3",options="header"]
59+
|===
60+
| Gate | Action
61+
| CryoFall staging (B4) | `STEAM_USER=… just cryofall-stage-verpex` (Steam password + Guard 2FA, ~3 GB, on Verpex), then `just cryofall-watchdog-install`
62+
| Bitbucket mirror (B2) | provision the SSH key / token; `mirror.yml` is already wired
63+
| OpenSSF badge | register at bestpractices.dev, add the badge to `README.md`
64+
| Merged-branch cleanup | `git push origin --delete <branch>` for the merged feature branches (Hypatia GS007)
65+
| Ephapax parser gaps | tracked externally (`nextgen-languages/ephapax`) — 2/25 Gossamer chain tests
66+
|===
67+
68+
== Cut the release
69+
70+
[source,bash]
71+
----
72+
git checkout main && git pull
73+
git tag -a vX.Y.Z -m "GSA vX.Y.Z"
74+
git push origin vX.Y.Z # release.yml does the rest
75+
----
76+
77+
Then verify the GitHub Release has the tarball, changelog, and provenance
78+
attestation attached, and that the `mirror.yml` run propagated the tag.

0 commit comments

Comments
 (0)