mesh/merge-gate pass: builds mesh-vault → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery failed: its walk failed: a gate on a first machine (what it carried put back), a build, a machine
A condition told the operator to type the node-engine's binary at the machine, and nothing held the catalogue's texts to ADR 0272. The words check gains retired-lines — the controller's and the node-engine's commands, copied from hq's words.py --list lines, which compares it — and refuses one in any string a module's tools can show or any manifest description. The vault's and the route adapter's texts now say the nox line.
74 lines
2.8 KiB
Go
74 lines
2.8 KiB
Go
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
|
|
}
|