Repository navigation
Surface guards: config check/clean/reset, generated docs, and drift checks (3.5.0-F18, B127, B128, B129, DOC13, DEV13-DEV18) - #5
Merged
Conversation
New check_shipped group completion_commands. The old completions group only walked top-level commands, so after F15 left group parents with no flags, no subcommand flag was checked, and presence meant "anywhere in the file". Now each command is checked where it is completed (its zsh function, minus description text; its bash case arm): every long flag offered, nothing it lacks offered, every argparse choice value offered, and code-derived lists (desktop catalog, PROFILE_METHODS) equal to their constants. B127: its first run found bash offering no values for `run toolchain --rebuild-soname-consumers`; fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…8, DOC13) primitives/env_vars.py lists every environment variable sysforge reads, as user settings or diagnostic switches; the man page's ENVIRONMENT section is generated from it. It listed 3 of 11 before, with a stale editor order and pager flags, and SYSFORGE_PROFILE_STORE was documented nowhere. journal.JOURNAL_FIELDS names the fields of the journal record (record_verb now builds from its constants), and a new JOURNAL man section is generated from it, with which commands write one and two journalctl queries. tests/test_env_vars.py fails on an unregistered SYSFORGE_* name in the code and on a registered variable nothing reads. gen_options keeps `[`/`|`/`-` words off the start of a line, which scdoc would read as a table or list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An upgrade never rewrites live config files, so retired settings stayed, silently ignored, and misspelt keys were never reported. primitives/config_schema.py is the one home for what a live file may hold: the section/top-key schema (moved from tools/check_shipped.py, which now imports it), the user-named open sections, keys valid because the shipped default documents them (active or commented), and RETIRED_KEYS / RETIRED_VALUES. The pristine defaults ship in the wheel (sysforge/_data/config-defaults) since /etc/sysforge holds the user's copies. Edits are line-based (comments survive), re-parsed with tomllib before writing, and written atomically. - config check: retired and unknown settings with their line; exits 1. - config clean: renames retired keys (or drops one whose replacement is set, saying so), rewrites retired values; --unknown removes unknown ones. - config reset FILE [KEY...]: keys back to the shipped line, or the whole file with a FILE.bak-<time> copy. - doctor system --config: the same inspection in the default sweep (the help text's axis list and count are now pinned by a test). The first run found toolchain.toml's reuse_unchanged and profile_store missing from the schema; profile_store is now documented in the shipped file, and the toolchain allowlist test accounts for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…0-DEV15) New check_standards group citations runs the claude_md resolver over docs/design/ and the tracked .claude/ agents, skills and rules. The resolver learned path/module.symbol citations, placeholders, symbols in any same-named module, and make targets (a missing one counts only as a near miss of ours); it checks paths only when their first segment is in the repo and skips bare .sh names. Inline code is paired per line with fences dropped, for both groups: a ``` fence used to shift every pairing after it. Fixed what it found: design 09's prompt passage (removed partition.py and _confirm_or_abort, inverted eof_default facts, stale per-file call counts), build_resolved_deps under the wrong module, `make vm-install`, and stale paths in the pkgbuild-reviewer agent and the pkgbuild-spec-check skill. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each concept page but the glossary closes with Further reading (one upstream link at least) then In sysforge, and uses no sysforge vocabulary before it. Upstream tools' flags stay allowed. The rule lived in CLAUDE.md only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cked (3.5.0-DEV15) DEV15 skipped paths whose first segment is not in the repo, to pass over `root/usr/bin` and `and/or`; that also skipped a citation into a top-level directory that is gone entirely (test_missing_path_citation_is_error). The repo's own directory names now always count as repo paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-hotplug-drivers (3.5.0-DEV13, B129) tests/cli_args.py: cli_args(*argv, **fields) parses a real command line and sets fields the command has, failing on any it lacks. The 31 SimpleNamespace stand-ins for parsed arguments are converted (and the toolchain/kernel stage ones to RunOptions); test_stand_ins keeps one deliberate case, with its reason, in the shrinking allowlist. What the conversion found: - B129: `run kernel --[no-]keep-hotplug-drivers` was parsed and dropped: RunOptions had no field and run kernel never copied it, so the stage always used kernel.toml. Fixed, with test_every_run_stage_flag_reaches_the_stage checking every run stage's flags reach the stage. - The sentinel-gate dry-run test exercised `build --dry-run` and `setup --dry-run`, which do not exist; it now covers update and run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two checks over the whole package. A field read on an options object (by attribute or getattr with a literal) must be a RunOptions or BuildOptions field; a missing one silently returns its default, which is 3.5.0-B129's shape, and the check reports B129 on the pre-fix code. And every command's parsed flag must be read through its argument object, except the dispatch fields and two named indirect readers (doctor's _AXIS_FLAGS, pinned to the axis flags, and PKG_KEY_BUILD_FROM_SOURCE). Both pass today. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…(3.5.0-DEV15) Citations without a module (`_confirm_or_abort`) could not be resolved, so they were never checked. Now a code-shaped name (_private, snake_case, CamelCase) must appear in a tracked non-doc file; other software's names and deliberate history are listed. Fixed what it found: 48 private names design 07 kept after the 3.2.0 split made them public (renamed in place), the reconfigure editor-persist prompt (now _offer_persist_editor, writing sysforge.toml and/or EDITOR/VISUAL), and design 15's invalidate_on_toolchain_change, a setting that never existed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es as code (3.5.0-DEV15) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…efault (3.5.0-F18) config check treats a fixed-section key as valid when the shipped default documents it, so an undocumented key the code reads would be called unknown and deleted by `config clean --unknown`. tests/test_config_keys_documented.py scans fixed-section reads off config-like objects and the schema's top-level keys, and requires each to be documented. It found profiles.toml's extends_system (read from a user file) undocumented; it is now, in the shipped file and the fixture. _documented now scopes a commented example table to its own comment block, so a top-level key documented after the header's examples stays top-level. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`config check --json` prints one config-check document (config dir, and each issue's file, line, kind, setting, message and fix) with the exit code unchanged; tests/data/json-schema/config-check.schema.json, standards row 32, completions and man page updated. A new test pins every json_out.emit kind to its schema file and back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
….5.0-DEV13) Every caller passes its stage's RunOptions, which always has abi_check, so the getattr default only ever hid a would-be rename behind a silent False, the shape of B129. Read it directly, drop the test that fed it a stand-in to prove the dead path, and pin _ARGS_STAND_INS empty. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
….0-DEV18) tools/surface.py generates tests/data/surface.json: every command's flags and values, environment variables, journal fields, config sections and keys, --json fields and run-log names. `make check-surface` (in GATES, so CI, pre-release and the release preflight run it) fails when the snapshot is stale; against the base (merge-base with main, or HEAD^ on main) it requires every added or removed entry to be named in text the change adds to unreleased.md, and a name that leaves the product entirely to be registered in retired_names.toml or RETIRED_KEYS. Those were the two gaps no other check could see. CI's `gates` job is now a required check on main (ruleset); ci.yml and design 17 say so. CONTRIBUTING.md gets a per-surface table naming what to update and what enforces it, .github/pull_request_template.md a checklist, and `make install-hooks` an optional pre-commit hook (tools/pre-commit.sh) running the fast gates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
release.sh's preflight now runs make check-surface; the fixture repo's stub Makefile lacked the target, so test_fresh_release_does_not_auto_resume_from_old_tag failed with "No rule to make target 'check-surface'". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…clean checkout (3.5.0-DEV15, 3.5.0-DEV18) The citation check resolved `man/sysforge.1.scd` on disk. The file is a gitignored build intermediate, present on a dev machine and absent in CI, so the gate passed locally and failed in CI. A gitignored path now counts as generated and is accepted either way. CI ran twice per PR commit (push and pull_request). Push now runs only for main, and a newer push to a PR cancels its superseded run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ties every user-facing surface to the code: each is now either generated from it or checked against it, and CI enforces both.
User-visible
sysforge config check/clean/reset, plus adoctor system --configaxis andconfig check --json. Finds retired or misspelt settings in the live config files, rewrites retired ones keeping comments (--unknownalso drops unknown keys), and restores keys or whole files to the shipped default (with a.bak-<time>copy). Diffs are shown first; writes need consent or--yes. The shipped defaults now ship in the wheel.run toolchain --rebuild-soname-consumersvalues.run kernel --[no-]keep-hotplug-driversnow takes effect (it was parsed and dropped).Contributor checks
.claude/resolve, including bare code names andmaketargets.SimpleNamespacestand-ins;tests/cli_args.pybuilds real parsed command lines.tests/data/surface.jsonsnapshot withmake check-surface(a new gate): stale snapshot, unrecorded surface changes and unregistered removals fail.CONTRIBUTING.mdsurface table, PR template,make install-hooks.Docs fixed along the way: about 60 stale design-doc citations, a cache setting design 15 described that never existed, and two
.claudefiles citing missing paths.Notes for review
check-surfaceskips its base comparison on this PR, sincemainhas no snapshot yet. It enforces from the next PR on.86445b38(7,480 passed); the run covering the last commit (049d2149) was still going when this PR was opened, so CI is the confirmation for it.🤖 Generated with Claude Code