Merge pull request 'Refuse a daemon's line in what a module shows: the operator types nox (hq ADR 0272, issue 356)' (#165) from fix/356-the-operator-types-nox-lines-checked into main

This commit was merged in pull request #165.
This commit is contained in:
2026-10-09 17:34:09 +00:00
5 changed files with 236 additions and 4 deletions
+73
View File
@@ -0,0 +1,73 @@
package main
import (
"fmt"
"regexp"
"sort"
"strings"
)
// The daemons' lines (novox/hq ADR 0272, its insight of 2026-10-09): the operator types one command, `nox`
// (`mesh-cli`). The node-engine (`nox-mesh-host`) and the controller (`mesh-controller`) are daemons, and a
// person never types their names — so no text a module can show names a line of theirs. The list is the
// copy in retired-lines at the catalogue's root, which novox/hq's words.py prints (`--list lines`) and
// compares; one line each, `<daemon> <command>`, and a trailing ` …` for a command that is a line only with
// an argument after it (`mesh-controller module check` is a line; "the mesh-controller module" is prose).
// retiredLine is one daemon's line: the daemon, its command, and whether an argument must follow.
type retiredLine struct {
daemon, command string
withArgument bool
}
// readLines reads retired-lines: one line a line; blank lines and lines starting with # are not lines.
func readLines(path string) ([]retiredLine, error) {
entries, err := readList(path)
if err != nil {
return nil, err
}
var out []retiredLine
for _, e := range entries {
withArgument := strings.HasSuffix(e, " …")
e = strings.TrimSuffix(e, " …")
parts := strings.Fields(e)
if len(parts) != 2 {
return nil, fmt.Errorf("retired-lines: %q is not `<daemon> <command>`", e)
}
out = append(out, retiredLine{daemon: parts[0], command: parts[1], withArgument: withArgument})
}
return out, nil
}
// linePattern matches the line whole: the daemon, white space, the command. A command that is a line only
// with an argument is matched as a line is written — at the start of a line or a code span, a prompt allowed,
// with an argument after it — so prose that names the daemon beside the word ("the mesh-controller module is
// assigned") is not one.
func linePattern(l retiredLine) *regexp.Regexp {
daemon, command := regexp.QuoteMeta(l.daemon), regexp.QuoteMeta(l.command)
if l.withArgument {
tick := "`"
return regexp.MustCompile(`(?m)(?:^|` + tick + `)[ \t]*(?:\$[ \t]*)?(` + daemon + `\s+` + command + `\s+[^\s` + tick + `])`)
}
return regexp.MustCompile(`(?:^|[^\w-])(` + daemon + `\s+` + command + `)(?:$|[^\w-])`)
}
// checkLines finds every daemon's line in the texts.
func checkLines(lines []retiredLine, texts []text) []string {
var out []string
for _, l := range lines {
rx := linePattern(l)
for _, t := range texts {
if m := rx.FindStringSubmatchIndex(t.s); m != nil {
line := t.line
if line > 0 {
line += strings.Count(t.s[:m[2]], "\n")
}
out = append(out, fmt.Sprintf("%s:%d: `%s %s` is a daemon's line — the operator types `nox …` (novox/hq "+
"ADR 0272) — in %q", t.file, line, l.daemon, l.command, excerpt(t.s, m[2], m[3])))
}
}
}
sort.Strings(out)
return out
}
+23 -2
View File
@@ -2,7 +2,9 @@
// 0244): no word the glossary retired for the tools' descriptions — the copy in retired-words at the
// catalogue's root — in any text a module's tools can show. That text is every string literal in a module's
// own code that is not a test (a tool's description, the notes and errors it answers with) and every
// description in its manifest. Comments are not read: an agent never sees them.
// description in its manifest. Comments are not read: an agent never sees them. And no daemon's line
// (novox/hq ADR 0272, lines.go): the copy in retired-lines, the lines a person would otherwise be told to
// type of the node-engine's or the controller's binary, where the operator's command is `nox`.
//
// A word is matched whole and in any case, a space in it matching any run of white space, and its plural
// (`s` or `es` on its last part) is matched as the word. A vendor word is
@@ -97,7 +99,26 @@ func main() {
fmt.Printf("words: %d use(s) of a word the glossary retired (novox/hq ADR 0244) — say it in the glossary's word\n", len(findings))
os.Exit(1)
}
fmt.Printf("words: %d retired words, none in the %d strings of %d files\n", len(words), len(texts), files)
// And no daemon's line (novox/hq ADR 0272): what a module tells the operator to type is a `nox` line.
lines, err := readLines(filepath.Join(root, "retired-lines"))
if err != nil {
fmt.Fprintln(os.Stderr, "words:", err)
os.Exit(2)
}
if len(lines) == 0 {
fmt.Fprintln(os.Stderr, "words: retired-lines lists no line — the check would pass on anything")
os.Exit(2)
}
if findings := checkLines(lines, texts); len(findings) > 0 {
for _, f := range findings {
fmt.Println(f)
}
fmt.Printf("words: %d daemon's line(s) in what a module shows — the operator types one command, nox (novox/hq ADR 0272)\n",
len(findings))
os.Exit(1)
}
fmt.Printf("words: %d retired words and %d daemons' lines, none in the %d strings of %d files\n", len(words), len(lines),
len(texts), files)
}
// readList reads retired-words: one word or phrase a line; blank lines and lines starting with # are not words.
+64 -1
View File
@@ -1,6 +1,9 @@
package main
import "testing"
import (
"os"
"testing"
)
// A retired word's plural is the word; anything else joined on is another word.
func TestPatternMatchesTheWordAndItsPlural(t *testing.T) {
@@ -24,3 +27,63 @@ func TestPatternMatchesTheWordAndItsPlural(t *testing.T) {
}
}
}
// A daemon's line is found whole — the daemon, its command, and an argument where the command is a line only with
// one — and prose that merely names the daemon beside a word is not one (novox/hq ADR 0272).
func TestADaemonsLineIsFoundWhole(t *testing.T) {
push := retiredLine{daemon: "mesh-controller", command: "push"}
module := retiredLine{daemon: "mesh-controller", command: "module", withArgument: true}
handOver := retiredLine{daemon: "nox-mesh-host", command: "hand-over"}
cases := []struct {
line retiredLine
text string
want bool
}{
{push, "run `mesh-controller push laptop` after", true},
{push, "mesh-controller push", true},
{push, "mesh-controller\n push", true},
{push, "mesh-controller pushed it", false},
{push, "the mesh-controller pushes", false},
{push, "mesh-controller-push", false},
{module, "`mesh-controller module check modules/*/module.json`", true},
{module, "run\n $ mesh-controller module check x", true},
{module, "the mesh-controller module is assigned", false},
{module, "mesh-controller module", false},
{module, "`mesh-controller module`", false},
{handOver, "`nox-mesh-host hand-over /srv/x` at the machine", true},
{handOver, "`nox node hand-over laptop /srv/x`", false},
{retiredLine{daemon: "mesh-host", command: "hand-over"}, "nox-mesh-host hand-over", false},
}
for _, c := range cases {
if got := linePattern(c.line).MatchString(c.text); got != c.want {
t.Errorf("%s %s on %q = %v, want %v", c.line.daemon, c.line.command, c.text, got, c.want)
}
}
found := checkLines([]retiredLine{push, module}, []text{{file: "m/a.go", line: 3, s: "say\n`mesh-controller push`"},
{file: "m/b.go", line: 1, s: "the mesh-controller module"}})
if len(found) != 1 || found[0] != "m/a.go:4: `mesh-controller push` is a daemon's line — the operator types `nox …` (novox/hq ADR 0272) — in \"say `mesh-controller push`\"" {
t.Fatalf("found %q", found)
}
}
// The list's lines read as `<daemon> <command>`, a trailing ` …` meaning an argument must follow; anything else is
// refused rather than read as some line.
func TestRetiredLinesAreReadAsDaemonAndCommand(t *testing.T) {
dir := t.TempDir()
path := dir + "/retired-lines"
if err := os.WriteFile(path, []byte("# the list\nmesh-controller push\nmesh-controller module …\n\nnox-mesh-host hand-over\n"), 0o644); err != nil {
t.Fatal(err)
}
lines, err := readLines(path)
if err != nil || len(lines) != 3 || lines[0] != (retiredLine{daemon: "mesh-controller", command: "push"}) ||
lines[1] != (retiredLine{daemon: "mesh-controller", command: "module", withArgument: true}) ||
lines[2] != (retiredLine{daemon: "nox-mesh-host", command: "hand-over"}) {
t.Fatalf("read %+v, %v", lines, err)
}
if err := os.WriteFile(path, []byte("mesh-controller\n"), 0o644); err != nil {
t.Fatal(err)
}
if _, err := readLines(path); err == nil {
t.Fatal("a line with no command was read")
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ export function getVaultTools(ledger: Ledger, receives: string | undefined, root
"The mesh's root secrets as this vault keeps them: every secret a module holds for itself, " +
"sealed to the operator's key (novox/hq ADR 0085, amended). Ciphertext — nothing here can " +
"open a line of it; the operator, holding the private key off the mesh, recovers one with " +
"`mesh-controller secret recover --from-export`. Also lists what is NOT recoverable: secrets " +
"`nox secret recover --from-export` on the control-node. Also lists what is NOT recoverable: secrets " +
"made before the mesh had an operator key.",
input: {
sealed: {
+75
View File
@@ -0,0 +1,75 @@
# The daemons' lines a text for the operator never names (novox/hq ADR 0272, its insight of 2026-10-09): the
# operator types one command, nox (mesh-cli); the node-engine and the controller are daemons. One line each,
# `<daemon> <command>`; a trailing ` …` marks a command that is a line only with an argument after it. A copy,
# so a catalogue merge needs nothing else; novox/hq's words.py compares it. Regenerate with:
# python3 00-META/checks/words.py --list lines
mesh-controller adopt
mesh-controller artifacts …
mesh-controller ask …
mesh-controller assign
mesh-controller broker
mesh-controller builds …
mesh-controller bus …
mesh-controller cancel
mesh-controller cleanup
mesh-controller collect
mesh-controller collection …
mesh-controller conditions
mesh-controller converge
mesh-controller data …
mesh-controller delivery …
mesh-controller doctor
mesh-controller durations
mesh-controller hand-act
mesh-controller hand-acts
mesh-controller healers
mesh-controller identity
mesh-controller images …
mesh-controller kill
mesh-controller licence
mesh-controller migrate
mesh-controller mirrors …
mesh-controller module …
mesh-controller node …
mesh-controller operator
mesh-controller overlay …
mesh-controller pause
mesh-controller pin
mesh-controller plan
mesh-controller plans …
mesh-controller prepare
mesh-controller push
mesh-controller queue …
mesh-controller rebuild
mesh-controller rehearse
mesh-controller replay
mesh-controller resume
mesh-controller retire
mesh-controller rollout
mesh-controller rotate
mesh-controller seat …
mesh-controller seats …
mesh-controller secret
mesh-controller settings
mesh-controller status
mesh-controller take …
mesh-controller token
mesh-controller unassign
mesh-controller unpin
mesh-controller upgrade
mesh-controller version …
mesh-host apply
mesh-host bundle
mesh-host enrol
mesh-host enroll
mesh-host hand-over
mesh-host help
mesh-host inventory
mesh-host key
mesh-host overlay
mesh-host owned
mesh-host profile
mesh-host reconcile
mesh-host run
mesh-host version
nox-mesh-host hand-over