docs(host): close five first-install run-sheet gaps (#1822)
This commit is contained in:
1 parent
4ec279dc43
commit
a1b13c60e1
2 files changed
+148
-1
No files matched your search
@@ -0,0 +1,56 @@
|
||||
# Row 326 / #1822 — five run-sheet gaps
|
||||
|
||||
Goldie, 2026-10-24. Branch goldie/row-run-sheet in /home/jwoltje/.t3/worktrees/mosaic-stack/goldie-row-run-sheet. Base local refactor4ec279dc43922b338a94718a2afdaba87ef89c15, explicitly assigned by sage-3893. Brief docs/plans/2026-10-24_run-sheet-doc-brief.md at4ec279dc4, blobce3e24fa, section Brief: five run-sheet gaps. Reviewer Gladstone; Sage posts review and owns landing/full gate.
|
||||
|
||||
## Before / after and choices
|
||||
|
||||
Before: the sheet omitted proof bytes/newline handling, treated render refusal without distinguishing metadata/content, omitted missing-project warning consequences and a pre-install key check, offered no first-install retry form, and omitted the bus-relative backup checksum form.
|
||||
|
||||
After: the sheet covers all five cases in their existing sections6/9. Numbered section headings are unchanged. Only this BUILD.md and docs/guides/host-run-sheet.md are edited, per the brief's explicit two-file boundary. Session/build-phase registration and the manifest are recorded here rather than adding changes to SESSIONS.md, BUILD-LOG.md or a third manifest file. No host action or credential read. No suite or product command executed, and no CLEAR needed for this doc-only row (decision137).
|
||||
|
||||
| Gap / claim | Source read and how it supports the text |
|
||||
| --- | --- |
|
||||
| Proof format, optional LF | webui/src/serve.mjs:257-267 opens no-follow, checks regular/uid/mode600-or400, strips exactly one trailing LF at263, then requires32+ ASCII base64url chars at264. Table states the allowed alphabet and one optional trailing LF. Extra newline/CR is outside that alphabet. |
|
||||
| Render versus start | case2-unit.sh:397-408 explicitly stats/realpaths the proof and never opens it. webui/src/serve.mjs:267 throws the content error; webui/src/cli.mjs:138-140 catches and sets exit2. Table now distinguishes metadata refusal at render from bad bytes at Console start. |
|
||||
| Missing project warning | business/src/cli.mjs:74-78 reports absent plus the no-project-variables warning, then continues. case2-install.sh:217-221 captures validate output and prints business-validates on success. Text makes that incomplete install possible and tells operators to stop on the missing-file warning, per Duckworth row323 N2. |
|
||||
| Pre-install key check | business/src/cli.mjs:71-82 checks every file-backed project, skips kind library, and requires loaded id==business key at80. Read-only inline Node uses only builtins and section2's pinned node, as mosaic. It reads the exact intended business input and files under each project's root, prints a match, and exits nonzero with STOP for read/JSON/id failure. Expected .53 output comes from .mosaic/project.json:3 and case1-business.mosaic-stack.json:10-11. Fixing business rather than project id is mos-1563. |
|
||||
| Why check before install | case2-install.sh:178 makes the copy before validation at217. New check is explicitly before case2-install.sh and needs no existing Mosaic config, npm modules or installed wrapper. |
|
||||
| Refused first-install residue | case2-install.sh:172/174 creates/bootstraps the config; bootstrap.sh:13 dispatches to mosaic-config.mjs, whose412-424 creates config.json or validates an existing one without rewriting it. case2-install.sh:200-211 may create businesses/file and library slots. case2-persona-import.mjs:300-308 may create library personas. Validation cleanup at case2-install.sh:217-219 removes only this run's new business file, retaining dirs. Copy may already exist under the path at install:80/178; stack-copy.sh:68 reuses an existing copy. |
|
||||
| Retry paths / refs | Mos-1565/ops-0291, as pinned in the brief, names exactly root checkout, mosaic clone and default config dir to move aside. UTC-suffixed mv is root-only documentation; no delete, chown or chmod. Destination collision/move failure prints STOP. Retry starts section6's first-install block again. The existing upgrade fetch targets only refs/remotes/origin/refactor; stack-copy.sh:44-48 requires reachability from both it and refs/heads/refactor. |
|
||||
| Credential re-placement | Existing sheet section9 names claude-session.env, library proof and library-gitea with owner/mode. Moving config aside preserves them but the new config needs Jason to re-place any already-filled files, under mos-1565. Existing per-agent slots still require credentials issue/Approve, never hand placement. No value or command to read a credential added. |
|
||||
| Backup hand check | stack-release.sh:475-482 creates activation/bus and writes SHA256SUMS from inside bus. restore at502 and rehearsal at2244 cd bus and check ../SHA256SUMS. New hand command does the same as mosaic, without --quiet so the expected bus.sqlite:OK is visible; ops-0292 records why checking in activation itself fails. |
|
||||
|
||||
## Read-only grep gate
|
||||
|
||||
Executed after editing, with no test/suite run:
|
||||
|
||||
```
|
||||
git grep -n host-run-sheet -- 'packages/*/tests/*' 'scripts/*'
|
||||
# no output, exit1
|
||||
|
||||
git grep -n case1-business.mosaic-stack.json -- 'packages/*/tests/*' 'scripts/*'
|
||||
packages/business/tests/case1-business-file.test.mjs:13:const DOCUMENT = join(REPO, "docs/guides/case1-business.mosaic-stack.json");
|
||||
packages/business/tests/case1-project-key.test.mjs:9:const CASE1 = join(REPO, "docs/guides/case1-business.mosaic-stack.json");
|
||||
# exit0: positive control, same command form, both tests read this document
|
||||
|
||||
git grep -n -E '(host-run-sheet.*[0-9a-f]{64}|[0-9a-f]{64}.*host-run-sheet)' -- 'packages/*/tests/*'
|
||||
# no output, exit1: no 64-hex test pin beside the sheet name
|
||||
```
|
||||
|
||||
An earlier positive control with case2-install.sh also found the real installer spawn in case1-business-file.test.mjs:39 and the CLI installer tests. The sheet-name search finds no reference at all in tests/scripts, stronger than just finding no same-line pin. No read/pin blocker.
|
||||
|
||||
Static syntax only: extracted the three new shell snippets, replaced only the version placeholder for parsing, and ran bash-n3/3. Extracted Node heredoc parsed with node --check --input-type=module. No snippet body executed. git diff --check passes. Source citations checked against this base; no new em dash and section numbering unchanged.
|
||||
|
||||
## Session / claimant receipt
|
||||
|
||||
2026-10-24 | Goldie a13dd6d5-5e73-4b7d-8318-02abeff24940 | Row326/#1822 doc-only build | Five gaps documented with source lines and grep control; no suites/host/credential action. Claim goldie-0326-start-1 rev3793, briefed→in-progress. In-review follows the pushed candidate; expected tokenless pre-send failure will be handed to Sage.
|
||||
|
||||
## Inline manifest
|
||||
|
||||
Only the sheet needs a content pin; BUILD.md is this receipt in the same candidate commit. An inline manifest honors the brief's two-file limit:
|
||||
|
||||
```
|
||||
e4c14516edff3bfbc81ea553a5a6ccebb6154942473540659d4681c2d56c9711 docs/guides/host-run-sheet.md
|
||||
```
|
||||
|
||||
Reviewer validates the five source chains and operational order. Sage's landing gate owns suites. No code row265 work started; its brief comes separately.
|
||||
@@ -207,6 +207,43 @@ install -o mosaic -g mosaic -m 0600 /root/<sha>.bundle /srv/mosaic/incoming/<sha
|
||||
sudo -u mosaic -H git clone -q -b refactor /srv/mosaic/incoming/<sha>.bundle /srv/mosaic/src/mosaic-stack
|
||||
```
|
||||
|
||||
If the first install refuses, use Mos's retry path (mos-1565, ops-0291). Bootstrap can already have
|
||||
written `/srv/mosaic/.config/mosaic-dev/config.json` (`scripts/case2-install.sh:174`,
|
||||
`scripts/bootstrap.sh:13`, `scripts/mosaic-config.mjs:412-424`). The config dir can also hold
|
||||
`businesses/`, the business file, and library persona files and slot dirs
|
||||
(`scripts/case2-install.sh:200-211`, `scripts/case2-persona-import.mjs:300-308`). A validation refusal
|
||||
removes only the business file this run created; its directory remains (`scripts/case2-install.sh:217-219`).
|
||||
The copy may already exist under `/srv/mosaic/.local/share/mosaic-stack/copies/<sha>`
|
||||
(`scripts/case2-install.sh:80`, `scripts/stack-copy.sh:68`).
|
||||
|
||||
As root, move these three paths aside with a UTC suffix. Move, never delete, so their owner and mode
|
||||
stay with them (mos-1565). This is the default-instance retry for the paths in this sheet:
|
||||
|
||||
```sh
|
||||
(
|
||||
cd / || exit 1
|
||||
retry_stamp="$(date -u +%Y%m%dT%H%M%SZ)" || exit 1
|
||||
for retry_path in /root/mosaic-stack /srv/mosaic/src/mosaic-stack /srv/mosaic/.config/mosaic-dev; do
|
||||
if [ -e "$retry_path" ] || [ -L "$retry_path" ]; then
|
||||
retry_saved="$retry_path.$retry_stamp"
|
||||
if [ -e "$retry_saved" ] || [ -L "$retry_saved" ]; then
|
||||
echo "STOP: retry destination already exists: $retry_saved" >&2
|
||||
exit 1
|
||||
fi
|
||||
mv -T -- "$retry_path" "$retry_saved" || exit 1
|
||||
fi
|
||||
done
|
||||
) || echo "STOP: could not move the first-install paths aside; do not continue"
|
||||
```
|
||||
|
||||
Then rerun the first-install block from its first line. Never use the upgrade fetch below on clones
|
||||
whose first install has not finished: it updates `refs/remotes/origin/refactor`, while copy requires
|
||||
the commit to be reachable from both that ref and `refs/heads/refactor` (`scripts/stack-copy.sh:44-48`; mos-1565).
|
||||
Recheck section 9 before starting units. If Jason already filled `claude-session.env`, the library
|
||||
proof file or `library-gitea`, have him re-place those files under the new config dir with section 9's
|
||||
owner and mode. Per-agent slots still use `mosaic credentials issue` or Approve, never a hand copy
|
||||
(section 9; mos-1565). The moved config dir preserves the earlier files.
|
||||
|
||||
After a first install, once both units are running (section 10), adopt the installed copy before
|
||||
any activate or upgrade. This step runs only on Mos's go, with Jason or Mos running it
|
||||
(`scripts/stack-release.sh:14`):
|
||||
@@ -254,6 +291,19 @@ When a run doesn't exit 0, send Mos the exit and the last lines of `/var/log/mos
|
||||
the old copy. The next run refuses `args-differ`, and a render from that file would put the old copy back.
|
||||
Move the file the result line names into place with `mv -f`. The two differ only in the `--copy` value.
|
||||
|
||||
To check a backup by hand before rollback or restore, run as the stack's user from its `bus/` directory:
|
||||
|
||||
```sh
|
||||
sudo -u mosaic -H /bin/sh -c \
|
||||
'cd "<dataRoot>/backups/stack/<activation>/bus" && sha256sum -c ../SHA256SUMS'
|
||||
```
|
||||
|
||||
Expect `bus.sqlite: OK`; stop on a failed check. The set holds `bus/bus.sqlite`, and `SHA256SUMS` names
|
||||
`bus.sqlite` relative to `bus/` (`scripts/stack-release.sh:475-482`). Running `sha256sum -c SHA256SUMS`
|
||||
from the backup set's directory looks for `bus.sqlite` one directory too high (ops-0292). Restore and
|
||||
rehearsal use the same `bus/` form
|
||||
(`scripts/stack-release.sh:502`, `scripts/stack-release.sh:2244`).
|
||||
|
||||
After `case2-install.sh` succeeds, create the human CLI wrapper before running
|
||||
`stack-copy.sh check --units external`. Creating this wrapper is a separate live
|
||||
step requiring Mos's go (`scripts/stack-copy.sh:3`); the install does not create it. Run only on that go:
|
||||
@@ -275,11 +325,52 @@ it. The wrapper must name the same `<sha>` copy as the units.
|
||||
Precheck lines: none. Root's checkout at `<sha>` and the stack's user's clone: precheck line missing.
|
||||
After install, `stack-copy.sh check --units external` reads the copy the units run.
|
||||
|
||||
Before running `case2-install.sh`, check the exact file you will pass as `--business-file`. Each
|
||||
non-library `projects` key must equal the `id` in `<root>/.mosaic/project.json`, and that file must exist
|
||||
in the stack's user's clone. Library entries are skipped by validate (`packages/business/src/cli.mjs:72`).
|
||||
Run this read-only check as `mosaic` with section 2's pinned node:
|
||||
|
||||
```sh
|
||||
sudo -u mosaic -H /opt/mosaic-stack/node-<v>/bin/node --input-type=module - '<business-file>' <<'MOSAIC_PROJECT_KEYS'
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
try {
|
||||
const business = JSON.parse(readFileSync(process.argv[2], 'utf8'));
|
||||
const projects = Object.entries(business.projects);
|
||||
if (!projects.length) throw new Error('business file declares no projects');
|
||||
for (const [id, entry] of projects) {
|
||||
if (entry.kind === 'library') continue;
|
||||
const file = join(entry.root, '.mosaic', 'project.json');
|
||||
const project = JSON.parse(readFileSync(file, 'utf8'));
|
||||
if (project.id !== id)
|
||||
throw new Error(`project file ${file} has id ${project.id}, but business ${business.id} declares it as ${id}`);
|
||||
console.log(`ok project ${id}: ${file} has id ${project.id}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`STOP: ${error.message}; do not install`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
MOSAIC_PROJECT_KEYS
|
||||
```
|
||||
|
||||
For .53 expect `ok project stack: /srv/mosaic/src/mosaic-stack/.mosaic/project.json has id stack`
|
||||
(`.mosaic/project.json:3`, `docs/guides/case1-business.mosaic-stack.json:10-11`). Any STOP or nonzero exit
|
||||
stops the install. Fix a mismatched business key, not the project id (mos-1563). The install otherwise
|
||||
reaches that refusal at step 7, after making the copy (`packages/business/src/cli.mjs:80`,
|
||||
`scripts/case2-install.sh:178`, `scripts/case2-install.sh:217`).
|
||||
|
||||
The stack's user's `scripts/case2-install.sh` (C2-13b, design 10 step 2b) makes the first copy with
|
||||
`stack-copy.sh copy <sha>`. The copy runs `npm ci` from `package-lock.json`, which installs the pinned
|
||||
harness, so the host needs to reach the npm registry during the install. The install runs no
|
||||
`release.sh package` or `activate`.
|
||||
|
||||
A missing `.mosaic/project.json` only warns: `project <id>: no project file at <path>; it has no project
|
||||
variables`. Validate reports that project `absent` and continues (`packages/business/src/cli.mjs:74-78`).
|
||||
An install can therefore pass step 7 without the project's variables. It captures validate's output
|
||||
and prints `business <id> validates` (`scripts/case2-install.sh:217-221`). Treat the missing-file warning as a stop,
|
||||
place the correct project file and repeat the check above before continuing (Duckworth 323 N2;
|
||||
`scripts/case2-install.sh:217-221`).
|
||||
|
||||
## 7. The args file
|
||||
|
||||
`/etc/mosaic-stack/dev.args` holds the `case2-unit.sh` arguments, one per line, with the serve flags after a
|
||||
@@ -318,7 +409,7 @@ file with `stat -c '%U %a %n' PATH`, never `cat`. `<business>` is the host's bus
|
||||
| Path | File | Mode | Owner | Profile | Precheck line |
|
||||
|---|---|---|---|---|---|
|
||||
| `/srv/mosaic/.config/mosaic-dev/secrets/` | `claude-session.env`, one line `ZAI_API_KEY=...` | 0600 | mosaic | library | `<path> sets ZAI_API_KEY` |
|
||||
| `/srv/mosaic/.config/mosaic-dev/secrets/` | the Console's proof file, the path the args file's `--proof-file` names | 0600 or 0400 | mosaic | library | none. `case2-unit.sh` refuses at render. Precheck line missing. |
|
||||
| `/srv/mosaic/.config/mosaic-dev/secrets/` | the Console's proof file, the path the args file's `--proof-file` names: one base64url line, at least 32 `[A-Za-z0-9_-]` characters, with one optional trailing LF (`packages/webui/src/serve.mjs:263-264`) | 0600 or 0400 | mosaic | library | none. Render checks metadata only and never opens the file (`scripts/case2-unit.sh:397-408`). Bad bytes refuse at Console start with exit 2 (`packages/webui/src/serve.mjs:267`, `packages/webui/src/cli.mjs:138-140`). Precheck line missing. |
|
||||
| `/srv/mosaic/.config/mosaic-dev/secrets/<business>/` | `library-gitea` | 0600 | mosaic | library | After a unit start, wait for loopback `/healthz` with the bounded retry in section 10 before `case2-precheck.sh --business <business> --library-status`: `library-last-error library-credential-missing` until it's placed, then `library <project> last fetched ...` |
|
||||
| `/srv/mosaic/.config/mosaic-dev/secrets/agents/<business>/<agent>/` | one file per service | 0600, dirs 0700 | mosaic | both | none. Filled only by `mosaic credentials issue`, or Approve after #436. Never by hand. |
|
||||
|
||||
|
||||
Reference in new issue
Block a user