feat(discord): git verbs for the Discord Sage on the shared-signals root, seat identity through a package credential helper, vault record protocol (#1509)
Row 24. A writable root that is a git work tree may carry a git object in the binding; the seat then has git_status, git_commit (explicit paths, seat author, Requested-by trailer from the envelope requester, push at once per D6), git_pull (ff-only) and git_push (one branch, never force), plus reserve_id and per-write clone locks under protocol vault. Git children run with no host config and one credential helper, bin/git-credential.mjs, reading the 0600 seat token file named in the binding; the fleet helper serves only the Gitea hosts. Suite 58/58, node 143. rev-code-02 APPROVED round 1 (#1509 comment 26375, tree 82ab962f). Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
@@ -19,9 +19,11 @@ fixed argument list, run only in a root that is marked `"write": true`
|
||||
and is a git work tree. No verb takes free-form arguments.
|
||||
|
||||
- `git_status(root)`: branch, ahead/behind, changed paths. Read only.
|
||||
- `git_commit(root, message, paths?)`: stages the named paths (or every
|
||||
change under the root when omitted), refuses a dot-prefixed path or a
|
||||
path outside the root, refuses an empty message or one over 500
|
||||
- `git_commit(root, message, paths)`: stages exactly the named paths
|
||||
(one to fifty; the "every change when omitted" form of the first draft
|
||||
was dropped for section 6's explicit-path rule, since the root is
|
||||
Jason's own clone), refuses a dot-prefixed path or a
|
||||
path outside the root, refuses when the index already holds staged work, refuses an empty message or one over 500
|
||||
characters, refuses when nothing is staged, commits with author
|
||||
`Sage <[email protected]>` and a trailer naming the Discord author
|
||||
by role (`Requested-by: Jason` or `Carmen`, never an id). Returns the
|
||||
@@ -38,18 +40,34 @@ the one the binding names (`"branch": "main"`), so a detached head or
|
||||
another branch refuses; 60 s timeout; stdout and stderr are captured,
|
||||
trimmed to 4 KiB and returned as data; exit codes become fixed refusals.
|
||||
|
||||
Credentials: the connector already runs with `MOSAIC_AGENT_NAME=sage`.
|
||||
The engine adds `MOSAIC_GIT_IDENTITY=sage` to the child environment and
|
||||
the repository's existing helper (`git-credential-mosaic`) resolves the
|
||||
seat's GitHub token at push time. The token is never read, printed,
|
||||
journaled or passed as an argument; a push failure returns git's message
|
||||
with any `https://…@` form masked.
|
||||
Credentials, as built (2026-09-18; the draft above said the fleet helper
|
||||
would serve): `~/.mosaic/tools/git/git-credential-mosaic` answers only
|
||||
the two Gitea hosts and exits silently for github.com, and the host's
|
||||
global git config sends github.com to Jason's own `gh` login. Neither is
|
||||
acceptable for Sage, so the verbs run git with `GIT_CONFIG_GLOBAL=/dev/null`,
|
||||
`GIT_CONFIG_NOSYSTEM=1`, no askpass, no prompt, and one helper set
|
||||
through `GIT_CONFIG_COUNT`: the package's `bin/git-credential.mjs`,
|
||||
which answers `get` over https from the 0600 file the binding names in
|
||||
`tokenFile`. The connector checks the file's mode at load and never reads
|
||||
it; the path reaches git only for push, pull and reserve, through the
|
||||
environment, never as an argument. The token is never read by the
|
||||
connector, printed, journaled or passed as an argument; a push failure
|
||||
returns git's message with any `https://…@` form and token shape masked.
|
||||
The D5 identity (seat token, `Sage <[email protected]>`) is unchanged;
|
||||
only the mechanism that presents it differs from the draft.
|
||||
|
||||
Binding (`tools` key, fixed):
|
||||
The requester in the trailer is the Discord author's server name, which
|
||||
the connector now writes into the envelope line (`requester="…"`) and the
|
||||
extension reads on `before_agent_start`. A turn without a requester
|
||||
cannot commit.
|
||||
|
||||
Binding (`tools` key, fixed), as built:
|
||||
|
||||
```json
|
||||
{ "name": "shared-signals", "path": "…/shared-signals", "write": true,
|
||||
"git": { "branch": "main", "identity": "sage" } }
|
||||
"git": { "branch": "main", "identity": "sage",
|
||||
"tokenFile": "…/secrets/github-jetrich-sage.token",
|
||||
"author": "Sage <[email protected]>", "protocol": "vault" } }
|
||||
```
|
||||
|
||||
Without `git` on a root, no git verbs are offered for it. The prompt
|
||||
|
||||
@@ -372,3 +372,4 @@ git history + Gitea issues.
|
||||
- 2026-09-16 (coordinator, #1509 row 23): part 1 writes built: `write_file`/`edit_file` for roots marked `write: true`, temp file plus rename, same fences as reads plus parent-must-exist, no dot paths, no credential shapes; `enabledToolNames` drives `--tools`, the extension and the check line; suite 49/49. Pinned for rev-code-02 round 1 (tree in the #1509 comment). Live finding: after the prompt fix Sage still repeated "ruling Q16" and "two read-only folders" with zero tool calls, because pi resumed the session that held every earlier refusal; the old session file was archived to the sage evidence dir and the service restarted with a fresh session. Writes and web reach Sage only after row 23 lands in the binding.
|
||||
- 2026-09-16 (coordinator, #1509 row 23): part 2 web built: `src/web.mjs` with `webFetch` (https only, public addresses only, connection pinned to the vetted address, three re-vetted redirects, 1 MiB cap, html to text) and `webSearch` (SearXNG json, ten results); enabled only when the binding `tools.web` key is set. The full-suite hang was a race in `tests/engine.test.mjs` (busy asserted before `agent_settled`, fake pi never stopped); the test now waits for the settle and stops in `finally`. Suite 52/52, node 128. Round 2 pinned for rev-code-02 (comment 26358, aggregate 287af5da, tree 1721584c). Next: verdict, local commit of my 17 paths only, then SearXNG container on 127.0.0.1:8888 and the live check.
|
||||
- 2026-09-16 (coordinator, #1509 row 23): part 3 live: SearXNG container `mosaic-searxng` (image searxng/searxng:latest, settings in the data root, formats html and json, limiter off) on 127.0.0.1:8888; binding `tools.web` added (backup in the sage evidence dir); check ok; service restarted. Jason's first turn in #sage-admin searched, fetched who.is, listed the folder and wrote `vault/Businesses/naming.md`. Defect seen in the same exchange: his second message during the turn went to pi as a follow-up, pi folded it into the same run, the first answer was never posted and the second failed as settled-without-turn. Fixed in `engine-pi.mjs` (held prompts, one run each), fake pi now models real follow-up semantics, suite 52/52 node 129, round 3 pinned (comment 26361, aggregate e30c2319, tree dbd2ce9a), service restarted with the fix. Row 24 rulings: D5 seat identity with `[email protected]`, D6 push every commit (Jason: not pushing means stale data), D7 rev-code-02.
|
||||
- 2026-09-18 (coordinator, #1509 rows 23–24): row 23 committed as 1685deb4 and pushed (`90cb31f5..1685deb4`) at Jason's word. Row 24 built: `src/git.mjs` (git_status, git_commit with explicit paths, seat author and `Requested-by:` trailer, push after every commit per D6, git_pull ff-only, git_push one branch; guard for branch, detached head, in-progress operations and conflicts; index must be empty so Jason's terminal work is never swept), `bin/git-credential.mjs` (the package's own helper: `get` over https from the 0600 token file, since `git-credential-mosaic` serves only the Gitea hosts and the global config routes github.com to Jason's `gh`), git children run with no host config; vault protocol (`protocol: "vault"`): per-write clone lock, `check` and `validate_vault.py` before a commit, `reserve_id`; the connector writes `requester="<server name>"` into the envelope and the extension reads it on `before_agent_start`. Suite 58/58, node 143. Review requested from rev-code-02; binding change and live check follow the verdict.
|
||||
|
||||
+2
-1
@@ -47,7 +47,7 @@ Gaps found while working go to `docs/plans/DEFERRED.md`, not here.
|
||||
| 20 | Discord connector: per-user channel allowlist in the binding and Carmen enrolled (all listed rooms except #sage-admin) (MVP iteration 5) | coordinator | #1509 | done: caaef941 (`users[].channels` allowlist, `channel-not-for-user` drop); Carmen enrolled live by reload 00:03 UTC; her first message is the remaining check | Carmen gets a reply in #general and silence in #sage-admin; Jason unchanged | `2026-09-13_discord-connector-pilot.md` section 11 |
|
||||
| 21 | Discord connector: read-only tools for the Discord Sage through a Mosaic pi extension confined to declared roots (MVP iteration 6) | coordinator; reviewer per Q12 | #1509 | approved: rev-code-02 round 2 verdict 26276 (tree 43f0329b); committed locally; live check in #sage-admin with Jason next; Jason ruled R1–R7 2026-09-14 (roots docs/ and agents/sage/, Carmen included) | Sage answers a question from a file under a declared root with the reads in the turn record; a read outside the roots is refused and recorded | `2026-09-14_discord-readonly-tools.md` |
|
||||
| 23 | Discord connector: writes confined to the `shared-signals` root plus web fetch and search for the Discord Sage (MVP iteration 7) | coordinator; reviewer per Q12 | #1509 | in review: parts 1 and 2 (writes, web fetch and search) built 2026-09-16, suite 52/52, node 128; round 3 pinned for rev-code-02 on #1509 comment 26361 (supersedes rounds 1–2; adds the engine held-prompt fix); part 3 done live 2026-09-17 (SearXNG container on loopback, binding web key, restart; first live turn searched, fetched and wrote vault/Businesses/naming.md); Jason ruled D1–D4 2026-09-16 (SearXNG, Jason and Carmen write, any https host, rev-code-02) | Sage writes a naming shortlist into the repository from #ideas with the write and web calls in the turn record; a write outside the root is refused | `2026-09-16_discord-write-and-web-tools.md` |
|
||||
| 24 | Discord connector: git verbs (status, commit, pull ff-only, push) for the Discord Sage on the `shared-signals` root, seat identity through the existing credential helper (MVP iteration 8) | coordinator; reviewer per Q12 | #1509 | briefed 2026-09-16 at Jason's word ("Sage will need to have git tooling"); D5–D7 ruled 2026-09-16 evening (seat identity, push every commit, rev-code-02); starts after row 23 review | Sage commits and pushes a decision file from #ideas; GitHub shows Sage as author with a Requested-by trailer; no token in any record | `2026-09-16_discord-git-tools.md` |
|
||||
| 24 | Discord connector: git verbs (status, commit, pull ff-only, push) for the Discord Sage on the `shared-signals` root, seat identity through the existing credential helper (MVP iteration 8) | coordinator; reviewer per Q12 | #1509 | done 2026-09-18: built (src/git.mjs, bin/git-credential.mjs, extension params, envelope requester, context paragraph, vault protocol via reserve_id and per-write locks); suite 58/58, node 143; rev-code-02 APPROVED round 1 (#1509 comment 26375, tree 82ab962f); D5 mechanism changed: the fleet helper declines github.com, so the package ships its own credential helper reading the 0600 seat token file; binding change and live check next | Sage commits and pushes a decision file from #ideas; GitHub shows Sage as author with a Requested-by trailer; no token in any record | `2026-09-16_discord-git-tools.md` |
|
||||
|
||||
Start message for row 6, sent from the board to darkwing:
|
||||
"Read docs/plans/QUEUE.md, then the plan page section "Piece 5: darkwing on
|
||||
@@ -103,3 +103,4 @@ Gate F or when blocked."
|
||||
- 2026-09-16 — coordinator: row 23 part 2 (web_fetch, web_search via SearXNG, src/web.mjs) built; engine test busy/settled race fixed in the test; suite 52/52, node 128; round 2 pinned on #1509 comment 26358 for rev-code-02. Row 24 still waits on D5–D7.
|
||||
- 2026-09-16 — coordinator: row 23 part 3 live (SearXNG container mosaic-searxng on 127.0.0.1:8888, binding web key, restart); Jason's first web turn worked end to end but exposed a live defect: a second message during a turn was sent as a pi follow-up and lost the first answer. Engine now holds it until pi settles. Suite 52/52, node 129; round 3 pinned as #1509 comment 26361; service restarted with the fix. Row 24 rulings D5–D7 recorded.
|
||||
- 2026-09-17 — coordinator: shared-signals-05 briefed the new id registry and file lock protocol (jetrich/shared-signals 8f0d946); folded into the row 24 brief section 6 (validate before commit, reserve_id tool, per-write clone lock, explicit-path staging). No row changed.
|
||||
- 2026-09-18 — coordinator: row 23 pushed on Jason's word ("push as well"): refactor 90cb31f5..1685deb4, seven commits, identity jarvis. Row 24 built and under test: four git verbs plus reserve_id, package credential helper (the fleet helper cannot serve github.com), requester in the envelope, explicit-path staging; suite 58/58, node 143; review requested from rev-code-02 on #1509.
|
||||
|
||||
Reference in New Issue
Block a user