From fc0d9c26fcdd4ca8faac46cdde697ada61f256d5 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Wed, 21 Oct 2026 06:43:17 -0500 Subject: [PATCH] row 218: C2-12 setup sheet for Melanie and the library survey run sheet (#1719) Doc only. docs/case2/SETUP-SHEET.md and docs/case2/SURVEY-RUN.md, with claim sources and rulings in agents/sage/work/queue-218/BUILD.md. Survey flags, output lines and exit codes from packages/library/src/survey.mjs and scripts/mosaic:37-41. --- agents/sage/work/queue-218/BUILD.md | 129 ++++++++++++++++++++++++++++ docs/case2/SETUP-SHEET.md | 124 ++++++++++++++++++++++++++ docs/case2/SURVEY-RUN.md | 111 ++++++++++++++++++++++++ 3 files changed, 364 insertions(+) create mode 100644 agents/sage/work/queue-218/BUILD.md create mode 100644 docs/case2/SETUP-SHEET.md create mode 100644 docs/case2/SURVEY-RUN.md diff --git a/agents/sage/work/queue-218/BUILD.md b/agents/sage/work/queue-218/BUILD.md new file mode 100644 index 000000000..f0a99e1bb --- /dev/null +++ b/agents/sage/work/queue-218/BUILD.md @@ -0,0 +1,129 @@ +# Row 218 draft notes: claims and sources + +Drafts for `docs/case2/SETUP-SHEET.md` and `docs/case2/SURVEY-RUN.md`. Repo base: `refactor` at +947101d8a, which holds 29ce1e360 (row 231). "Design" means +`git show 75fb3e10e:agents/gosalyn/work/case2/DESIGN.md`, cited as `D:`. "Brief" means +`docs/plans/2026-10-20_case2-rows.md`. Code paths are relative to the repo root. Nothing was run +except reads, greps and `git merge-base --is-ancestor 29ce1e360 HEAD`. + +## SETUP-SHEET.md + +| Claim | Source | +|---|---| +| She keeps writing in Obsidian, obsidian-git pushes to git.mosaicstack.dev, nothing changes on her machine, nothing commits to her repo | D:939-940 (7.1) | +| Agents read what she pushed; a push reaches them in about a minute | D:1006-1007 (7.5); D:972-973 (60-second sync timer) | +| Agents read `.md` notes inside book folders only | D:457-461 (1.2); `packages/library/src/scope.mjs:9-19` | +| Not read: top-level notes, `.canvas`, `.base`, attachments, anything outside a book folder | D:461 | +| Other repos under `~/src` are not read | D:489 (1.3), D:494-497 (N4) | +| Agents can't write to her repo: canon, playground, anything | D:389 (D3); D:1008 | +| Folder roles live in the `projects` entry of the business file, hand-edited, agents can't change it | D:409-429, D:443-451 (1.1, M9) | +| Jason asks her to confirm the mapping first | D:431; D:1324-1328 (10 step 7) | +| A folder named in `playground` is her playground | Brief:22; D:434 | +| Each playground prefix sits inside one book folder | D:434-436; `packages/library/src/mapping.mjs:77-80` | +| One per book, e.g. `/playground/`; until then everything mapped is canon | D:438-439 | +| Agents search canon unless they ask for the playground | D:463 | +| Playground may back an idea or question, not a fact, finding or correction; refused before she sees it | D:858 (`playground-cited-as-canon`); D:378-382, D:835-839 (guard runs before store) | +| Only the folder decides; a tag or property can't change scope | D:388 (D2); D:440-441; `scope.mjs:1` | +| Graph colour group via Groups and a `path:` query, her own vault setting, changes nothing for agents | Brief:23; D:941-943. Obsidian UI steps from the task prompt, not the design | +| Path starts with the books repo folder because the vault is `~/src` | D:939 | +| N2: moving a note into a book folder makes it canon, agents may cite it as fact | D:944-945; D:259 | +| Rough drafts outside the playground are canon | Inference from D:460 (scope rule) | +| N4: Obsidian resolves short links across `~/src`, the reader sees one repo, the two can differ, the reader can't tell | D:494-497; D:262-263 | +| A name only in another repo leads nowhere for agents | D:489 (R4); `packages/library/src/links.mjs:61-87` | +| A full-path link resolves the same in both | D:497-498. Hub side: `links.mjs:77-78` (`vault-prefix` step) | +| "New link format: Absolute path in vault" setting | Obsidian UI knowledge. Not in design or code. Reviewer may strike it | +| `appears_in` and `relationships` links are read as links | D:489-490; `packages/library/src/reader.mjs:15`, `:153-162` | +| Quoted flow list `["[[A]]", "[[B]]"]` parses | `reader.mjs:81-96` (flow), `:66-73` (quoted scalar), `:159` | +| Block list with quoted items parses | `reader.mjs:117-122`, `:66-73` | +| Unquoted `[[[A]], [[B]]]` is R3 | Brief:28-29; `reader.mjs:87` (bracket inside a flow list stops parsing), `:137` | +| R3 effect: whole front matter unread, note still indexed by path, name and body, listed as a problem | D:480; `reader.mjs:103-105`, `:193`; `packages/library/README.md:69` | +| Problems show in Mosaic's status | D:473-474; D:999-1000 (7.4 status line) | +| A value without `[[ ]]` is a name | D:489-490; `reader.mjs:159` | +| Bean and Chet keep names and personalities | D:660-661 (Q180) | +| Hermes: free text and story text. Mosaic: short cited items, a prose request gets a question or idea | D:778-781 (design 4) | +| Bean and Chet's item kinds: idea, question, finding, fact; web cites allowed | D:649 (`companion`); D:860 (`citation-unfetched`) | +| Limits 10 items, 5 ideas of 200, others 300 | D:819 (M5) | +| She or Jason can ask for lower limits | D:1329-1330 (10 step 8); D:831 | +| "No cited answer" notice | D:870-871, D:996-997 | +| One item can't mix two worlds | D:859 (`citation-cross-universe`) | +| She talks to them in the Console; Hermes keeps running until she moves over; stopping it is her choice | D:381-382; D:1331 | +| Five more helpers; she chooses the start set and can add one later | D:647-654; D:783-784; D:1327-1328 | +| What Jason will ask | D:1325-1327 (10 step 7) | + +## SURVEY-RUN.md + +| Claim | Source | +|---|---| +| Runs on `` 10.1.1.54 under design 10 step 7, after step 4 | D:1324; D:1266 (host) | +| Prints names and counts, never note text, property values, file names or link targets | `packages/library/src/survey.mjs:1-6`; README:118-125 | +| Sending to Melanie is Jason's call | Brief:36; D:1324-1328 | +| Token slot `library-gitea` is step 4 | D:1314-1316 | +| Run as `sudo -u mosaic -H` from `localadmin`; `mosaic` has no login shell | D:1195-1197; D:1281-1282 | +| Copy at `/srv/mosaic/.local/share/mosaic-stack/copies/`, `` = commit in Jason's go | D:1286-1292 (2c); `docs/TOOLS.md:417`; home `/srv/mosaic` per D:1314-1315 | +| The copy carries `packages/library/src` | `scripts/stack-copy.sh:36` | +| Row 231 adds the control and bidi escapes | `git log` 29ce1e360; `survey.mjs:78-82`; README:121-122 | +| `` is the `--node` directory of step 2c; `scripts/mosaic` execs `node` from PATH | D:1290-1291; `scripts/mosaic:41` | +| Dispatch: `mosaic library survey` goes to `survey.mjs` with `survey ` | `scripts/mosaic:37-41` (one `shift` leaves `survey` as argv[0]); `survey.mjs:102-103` | +| Command and flags: `` plus optional `--mapping ` once; anything starting with `-` refuses | `survey.mjs:16`, `:104-110` | +| No fetch; reads `HEAD` | `survey.mjs:5-6`, `:27`; `reader.mjs:22-24` | +| Top folder only: ceiling is the path's parent | `packages/project/src/git.mjs:12`, `:62` | +| Owner must be `mosaic`: git gets no global config | `packages/seat/src/checkout.mjs:79-89` (`GIT_CONFIG_GLOBAL=/dev/null`, `GIT_CONFIG_NOSYSTEM=1`). The dubious-ownership refusal is git's own behaviour | +| Bus mirror path `/projects//` | Brief:300; `packages/project/src/paths.mjs:34-40` | +| C2-04 and C2-03a not landed | `grep` of `packages/*/src` finds no library entry handling or `refs/heads/served`; `docs/guides/host-run-sheet.md:269` says "not landed" | +| Served ref `refs/heads/served` | D:963 (7.2); Brief:676 | +| Token kept out of URL, config, argv, logs | D:955-956 (7.2) | +| Mapping file is the entry alone; `remote`, `branch` required | `survey.mjs:114-116`; `mapping.mjs:38-47` | +| Output lines and fields | `survey.mjs:83-97`; data from `:26-76` | +| Folder lines list folders that directly hold an entry, full path | `survey.mjs:30-35` | +| Key names: short identifiers print, others as `(other key)` | `survey.mjs:17-20`, `:47` | +| `unresolved` equals the R4 count | `survey.mjs:72` | +| Scope counts cover all tree entries | `survey.mjs:66` | +| Refusal exit codes 0, 2, 3, 4 | `survey.mjs:99-124`; README:127-129 | +| Mapping checked before repo | `survey.mjs:112-121` | +| stderr format `library survey: ` | `survey.mjs:101`; `problems.mjs:3-5` | +| `(project-git)` suffix on git failures | `reader.mjs:18-20`; `paths.mjs:4-6` | +| `library-playground-outside-book` message | `mapping.mjs:79-80` | +| 100-second git timeout | `checkout.mjs:49`, `:52`; `git.mjs:68` | +| Exit 127 when `node` is missing | `scripts/mosaic:18`, `:41` (bash `exec` failure). Not run | +| Other errors rethrow as a stack trace | `survey.mjs:117`, `:123`, `:128-131` | +| Don't work around a refusal | AGENTS.md invariant 6 | + +## Code and design disagreements + +1. Design 1.1 shows the mapping nested in `"projects": {"books": {...}}` (D:412-429). The survey's + `--mapping` file must be the inner entry alone (`survey.mjs:114-116`). The run sheet follows the code. +2. Design 1.3 calls `vaultPrefix` part of the mapping (D:418). The code makes it optional + (`mapping.mjs:48`, README:30). Without it, a full vault path link, the N4 advice, resolves to + nothing in the hub (`links.mjs:73-87`: `root` fails, `vault-prefix` is skipped, `shortest` refuses a + `/`). The setup sheet's full-path advice holds only when Jason sets `vaultPrefix` to her books repo + folder name. +3. The task prompt calls the unquoted form "refused". R3 is not a refusal. It is a reported problem, + and the note stays indexed (D:473, D:480). The sheet says what happens instead. + +## Open questions + +1. Where `` comes from on .54. The survey reads a local repo's `HEAD` and never fetches. The bus + mirror needs C2-04 and C2-03a, neither landed. C2-03a moves `refs/heads/served`, not `HEAD`, so the + mirror's `HEAD` may name no commit and the survey would refuse with exit 2. The sync also needs a + checked mapping with at least one book (`mapping.mjs:59`, `:70`), and the mapping's values are + meant to come from this survey (D:431). Sage needs to rule: a placeholder mapping for the first + sync, a `HEAD` the sync sets, a `--commit` flag on the survey, or another source. +2. The brief says Obsidian's property editor writes `appears_in: ["[[A]]", "[[B]]"]` (Brief:28-29, + webby-0041 N4). I didn't read webby-0041 or check Obsidian's output. Both the flow and the block + quoted forms parse, so the sheet shows both and says only that the editor adds the quotes. +3. Whether `/srv/mosaic/.npm-global/bin/mosaic` exists on .54. The run sheet uses the copy's + `scripts/mosaic` by full path to avoid depending on a wrapper. + +## Sage's rulings on the open questions (2026-10-21) + +1. Survey source: the bus's bare mirror after the first `library.sync`, the only copy on the host + (design 2.1). The C2-03a brief now requires the mirror's `HEAD` to be a symbolic ref to + `refs/heads/served`, with a test (5c6f73ed7), so the survey reads the served commit with no ref flag. +2. Property list forms: the sheet shows both quoted forms, since both parse. Webby checks the claim + that Obsidian's property editor writes the quoted form. +3. The "New link format: Absolute path in vault" tip stays. It is an Obsidian setting, not a design + claim, and Webby may strike it. +4. The run sheet calls the copy's `scripts/mosaic` by full path. That holds whether or not a wrapper + is on `PATH`. +5. `vaultPrefix`: the run sheet's step 4 tells Jason to set it, because the setup sheet's full-path + link advice depends on it. diff --git a/docs/case2/SETUP-SHEET.md b/docs/case2/SETUP-SHEET.md new file mode 100644 index 000000000..8c15059b3 --- /dev/null +++ b/docs/case2/SETUP-SHEET.md @@ -0,0 +1,124 @@ +# Your books in Mosaic: a setup sheet + +This sheet is for you, Melanie. You keep writing in Obsidian the way you do now. Mosaic reads your +books repo after obsidian-git pushes it to git.mosaicstack.dev. It changes nothing on your machine and +commits nothing to your repo. + +## What the agents read + +The agents read your books repo as you last pushed it. A push reaches them in about a minute. + +They read notes, the `.md` files, inside your book folders. They don't read: +- notes at the top of the repo, outside any book folder +- `.canvas` and `.base` files, even inside a book folder +- images and other attachments +- anything in your other repos under `~/src` + +They can't write to your repo at all. That covers canon, the playground and everything else. + +Which folders are book folders, and which hold characters, places, research, your tracker or chapter +summaries, is set in one place. It is the `projects` entry of your business file in Mosaic. Jason +edits it by hand, and the agents can't change it. He will ask you to confirm it before the agents start. + +## Your playground + +A folder named in the `playground` list of that entry is your playground. Each playground folder sits +inside one book folder, so one per book works well, for example `/playground/`. You choose the +names and tell Jason. Until you have one, every note in a book folder is canon. + +What the playground means for the agents: +- They search canon unless they ask for the playground on purpose. +- An agent may quote a playground note in an idea or a question. It may not use one to back a fact, + a finding or a correction. Mosaic refuses that reply before you see it. +- Only the folder decides. A tag or a property can't make a note playground or canon. + +### Colour the playground in your graph + +This is a setting of your own vault. It changes nothing for the agents. + +1. Open the graph view and open its settings panel. +2. Under Groups, choose New group. +3. In the query box, type the playground's path with `path:`. Your vault is `~/src`, so the path + starts with your books repo folder: `path:"//"`. +4. Pick a colour. + +Add one group per playground folder. + +## Two things you might not expect + +### Moving a note into a book folder makes it canon + +The folder decides, so a move changes what the agents may do with a note. Once you move a note out of +the playground into a book folder and push, it is canon. The agents may then cite it as fact. A note +that isn't settled yet belongs in the playground. Any note in a book folder outside the playground is +canon, rough drafts included. + +### A short link can point somewhere else for the agents + +Obsidian looks up a short link like `[[Mara]]` across your whole vault, `~/src`. The agents see only +your books repo. Say a note called `Mara` exists in your books repo and also in another of your repos. +Obsidian and the agents can then open different notes for the same link, and the agents can't tell. +If the name exists only in the other repo, the link leads nowhere for the agents. + +A link with the full path from the top of your vault reaches the same note in both: + +``` +[[///Mara]] +``` + +Obsidian can write new links this way. In Settings, open Files and links and set New link format to +Absolute path in vault. + +## Lists of links in properties + +The agents read the links in two properties, `appears_in` and `relationships`. Put quotes around each +link in the list: + +```yaml +appears_in: ["[[A]]", "[[B]]"] +``` + +One link per line works too: + +```yaml +appears_in: + - "[[A]]" + - "[[B]]" +``` + +Obsidian's property editor adds the quotes for you. If you type the list by hand, don't leave them out: + +```yaml +appears_in: [[[A]], [[B]]] +``` + +The agents' reader can't read that form. It then ignores every property of that note and lists the +note as a problem in Mosaic's status. It still finds the note by its path, its name and its text. A +value written without `[[ ]]` counts as a plain name, not a link. + +## What changes for Bean and Chet + +They keep their names and personalities. How they answer changes. + +In Hermes they answer in free text and may write story text when you ask. In Mosaic every reply is a +short list of items. Each item is an idea, a question, a finding or a fact. Each one quotes a line +from your repo or from a web page the agent read for you. + +They don't write passages. If you ask for prose, you get a question or an idea instead. + +Today a reply holds at most 10 items. It has at most 5 ideas of up to 200 characters each. A question, +finding or fact runs up to 300 characters. You or Jason can ask for lower limits. When an agent can't +back an answer with a quote, you see "No cited answer" instead. + +Each book world stays separate. One item can't mix quotes from two worlds. + +You talk to them in the Console. Hermes keeps running until you have moved over, and stopping it is +your choice. + +Five more helpers can join them: ideas, research, proofreader, fact-checker and continuity. You +choose which ones to start with, and you can add one later. + +## What Jason will ask you + +He will ask you to confirm your book folders and type folders, which books share a world, the name of +each playground folder, and which helpers to start with and when. diff --git a/docs/case2/SURVEY-RUN.md b/docs/case2/SURVEY-RUN.md new file mode 100644 index 000000000..f00f46fe1 --- /dev/null +++ b/docs/case2/SURVEY-RUN.md @@ -0,0 +1,111 @@ +# Survey run sheet for the library host + +This sheet is for whoever runs `mosaic library survey` on ``, 10.1.1.54, under design 10 step +7. The survey reads one commit of a git repo and prints names and counts. It never prints note text, +property values, file names or link targets. Jason fills in the mapping for Melanie's books repo +from its output and her answers. + +Out of scope: sending anything to Melanie. Design 10 step 7 makes that Jason's call. + +## Before you start + +- Jason's go for step 7. Step 4, the bot token in the `library-gitea` slot, comes first. +- You run as `mosaic` with `sudo -u mosaic -H` from `localadmin`. `mosaic` has no login shell. +- The stack copy from step 2 is in place at `/srv/mosaic/.local/share/mosaic-stack/copies/`. + `` is the full commit id in Jason's go. It must hold row 231, which escapes control and bidi + characters in folder names. In a canonical checkout, `git merge-base --is-ancestor 29ce1e360 ` + exits 0 when it does. +- ``, the directory that holds `node`. It is the directory of the `--node` path given to + `case2-unit.sh` in step 2c. `scripts/mosaic` runs `node` from `PATH`. +- ``, an absolute path. See the next section. + +## The repo to survey + +The survey reads a local repo. It doesn't fetch. `` must: +- be the repo's top folder, or a bare repo's own folder. A folder inside a repo refuses, because the + survey stops git from looking above the path's parent. +- belong to `mosaic`. The survey gives git no global config, so a `safe.directory` entry can't + admit a repo another user owns. +- have a `HEAD` that names a commit. The survey reads `HEAD` and has no flag for another ref. + +`` is the bus's bare mirror at `/projects//`, which C2-04 (row 215) +creates and C2-03a (row 222) fetches into. It is the only copy of her repo on the host (design 2.1), and +`mosaic` owns it. Survey it after the first `library.sync` succeeds. The mirror's `HEAD` points at +`refs/heads/served` (C2-03a brief), so the survey reads the commit the agents are served. + +Don't survey anything else. A hand clone with the bot token would put the token where design 7.2 keeps +it out, and the mirror's refs belong to the bus. If `HEAD` names no commit, stop and report to Sage. + +## Steps + +1. `ssh localadmin@10.1.1.54`. +2. Run the survey without a mapping: + + ```sh + cd / + sudo -u mosaic -H env PATH=":/usr/bin:/bin" \ + /srv/mosaic/.local/share/mosaic-stack/copies//scripts/mosaic library survey + echo "exit $?" + ``` + +3. On exit 0, give the output to Jason. On any other exit, see "Refusals" below. +4. When Jason has a draft mapping, run it again with `--mapping`. The file holds the library entry + alone, `{"kind": "library", "remote": ..., "branch": ..., ...}`, without the business file or the + `"projects"` wrapper around it. `remote` and `branch` are required even though the survey doesn't + fetch. `mosaic` must be able to read the file. Set `vaultPrefix` to her books repo's folder name + in her vault. Without it, a link with the full path from the top of her vault resolves to nothing, + and the setup sheet tells her to write links that way. + + ```sh + sudo -u mosaic -H env PATH=":/usr/bin:/bin" \ + /srv/mosaic/.local/share/mosaic-stack/copies//scripts/mosaic library survey --mapping + echo "exit $?" + ``` + +The usage line is `mosaic library survey [--mapping ]`. `--mapping ` is the only +flag, and it may appear once. `--mapping=` and every other flag refuse. + +## What the output holds + +Plain text on stdout, one line per item: + +| Line | What it holds | +|---|---| +| `commit ` | the 40-hex commit `HEAD` names | +| `entries ` | every entry in that commit's tree | +| `folders (direct children: md canvas base other)` | then one line per folder that holds a file directly: its path as a JSON string and four counts. `(root)` is the repo's top | +| `markdown files, read, ...` | `.md` files, how many were read, how many have no front matter, how many have front matter the reader can't fully parse | +| `front matter key sets` | then ` []` per set of property names. A name that isn't a short identifier prints as `(other key)` | +| `body links plain .., label .., heading .., embed .., self .., markdown ..; attachment ..` | link forms in note bodies, and embeds of a target with an extension other than `.md` | +| `field appears_in wikilink .., name ..` | values written as links and as plain names. A `relationships` line follows | + +With `--mapping` three lines follow: + +| Line | What it holds | +|---|---| +| `scopes canon .., playground .., unmapped ..; indexed ..` | tree entries per scope, and notes indexed | +| `resolved root .., vault-prefix .., relative .., shortest .., unresolved ..` | links per resolver step. `unresolved` is the R4 count | +| `problems R1 .., ..., R7 ..` | problems per rule | + +Folder paths and short property names are the only words from her repo in the output. A folder name with a control or bidi +character prints it as `\uXXXX`. + +## Refusals + +A refusal prints nothing on stdout and one line on stderr. The survey checks the mapping before the +repo, so a bad mapping gives exit 3 even when the repo path is wrong too. + +| Exit | stderr | Cause | What to do | +|---|---|---|---| +| 4 | `library survey: usage: mosaic library survey [--mapping ]` | no repo, two repos, an unknown flag, `--mapping` without a file or twice | Fix the command | +| 3 | `library survey: library-mapping-invalid: is not a readable JSON file` | missing, unreadable by `mosaic`, or not JSON | Fix the file or its mode | +| 3 | `library survey: library-mapping-invalid: ` | the entry breaks the schema. The reason names the key | Give it to Jason for the draft | +| 3 | `library survey: library-playground-outside-book: universes..playground "" is not inside one of its books` | a playground prefix outside its universe's books | Give it to Jason for the draft | +| 2 | `library survey: library-git: is not a directory` | wrong path | Check `` | +| 2 | `library survey: library-git: repository has no readable HEAD commit (project-git)` | not a repo, a folder inside one, another owner, no commits, a `HEAD` with no commit, or no `git` on `PATH` | Check each. If `` is the bus mirror, stop and report to Sage | +| 2 | `library survey: library-git: `, such as `tree listing refused (project-git)` | git failed or ran past 100 seconds | Report to Sage | +| 127 | a line ending `exec: node: not found` | `node` isn't in `` | Fix `` | +| other | a Node stack trace | a fault in the survey | Stop and report the exit code to Sage | + +A refusal is the answer, not an obstacle. Don't run as another user, change modes on her repo or edit +its refs to get past one.