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:
2026-09-18 07:52:35 -05:00
co-authored by Claude Fable 5.1
parent 1685deb423
commit 1949ed8d31
23 changed files with 1284 additions and 48 deletions
+45
View File
@@ -2508,3 +2508,48 @@ and pi environment verified; Jason's first web turn worked. Records of the
live setup live in the sage seat evidence directory, never in the repo.
Follow-ups: a failed turn record should carry its partial tool calls; row
24 (git verbs) is next.
## 2026-09-18 — Discord git verbs for the shared-signals root (#1509, QUEUE row 24)
Before: a write from Discord landed in Jason's clone and waited for him to
commit it from the terminal. After: a writable root that is a git work
tree may carry a `git` object in the binding, and the Discord Sage gets
`git_status`, `git_commit`, `git_pull` and `git_push`, plus `reserve_id`
under the shared-signals record protocol. Every verb is one `git` child
with a fixed argument list inside the root, 60 s, output capped and
masked. A commit stages exactly the paths named (one to fifty regular
files under the root, no dot segment, no symlink), refuses when the index
already holds someone's staged work, commits as `Sage <[email protected]>`
with a `Requested-by:` trailer naming the Discord author's server name,
and pushes at once (D6). A push that fails is still a commit and is said
so; the next commit's push carries both. Pull is ff-only; push is one
branch, never force. The guard refuses off the named branch, a detached
head, a merge, rebase, cherry-pick, revert or bisect in progress, and any
conflicted path. Under `protocol: "vault"`, writes take the clone lock
for the path around the write, a commit runs `vault_lock.py check` and
`validate_vault.py` first, and `reserve_id` appends the registry line.
The requester comes from a new `requester="…"` field the connector writes
into the envelope line and the extension reads on `before_agent_start`.
Correction to the brief's draft (D5 mechanism): the fleet helper
`git-credential-mosaic` serves 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 may act for Sage, so git children run with
no host config at all (`GIT_CONFIG_GLOBAL=/dev/null`, `GIT_CONFIG_NOSYSTEM=1`,
no askpass, no prompt) and one helper set through `GIT_CONFIG_COUNT`, the
package's own `bin/git-credential.mjs`, which answers `get` over https
from the 0600 token file the binding names. The connector checks that
file's mode and never reads it; its path reaches git only for push, pull
and reserve, through the environment. The identity D5 named is unchanged.
Verification: `scripts/test-discord.sh` 58/58 and node tests 143 pass on
the frozen bytes (`tests/git.test.mjs` against a local bare remote with
stand-in vault scripts; a spy spawn asserts no argv holds the token or its
path; the credential helper is driven as a child; the real pi is shown
the verbs with a sandbox work tree and refuses `git` on a read-only
root). Review: rev-code-02 round 1 pinned as #1509 comment 26374, tree
82ab962f6a1baa0bb010f36da92645f80da67c13. rev-code-02 APPROVED round 1 on 2026-09-18T12:50:33Z (#1509 comment 26375).
The binding change and the live check follow the local commit; the
binding stays private. Jason's shared-signals clone holds his own
uncommitted files; explicit-path staging leaves them alone, and Sage
cannot commit while his index holds staged work.