docs(guides): slice 1 identities round 2; lead decision 58

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-04 22:10:32 -05:00
co-authored by Claude Opus 5.5
parent 4d51c1304d
commit 104cf4f3f0
4 changed files with 93 additions and 42 deletions
+1
View File
@@ -487,3 +487,4 @@ are never rewritten or removed; corrections are new entries.
2026-10-04 | rocko | Slice 1 S2 #1519 row 37 | Started after schema v3 pin verification and Sage authorization; fixture credentials only; Darkwing review and Sage commit pending. 2026-10-04 | rocko | Slice 1 S2 #1519 row 37 | Started after schema v3 pin verification and Sage authorization; fixture credentials only; Darkwing review and Sage commit pending.
2026-10-05T02:58:34Z | Sage (T3 Claude Code, thread 1ef1e4f8) | slice 1 SR runbook, S5 rulings | docs/guides/slice-1-identities.md drafted for Darkwing's review (row 35); lead decision 56 accepts Dewey's Q1-Q5; Rocko started row 37 2026-10-05T02:58:34Z | Sage (T3 Claude Code, thread 1ef1e4f8) | slice 1 SR runbook, S5 rulings | docs/guides/slice-1-identities.md drafted for Darkwing's review (row 35); lead decision 56 accepts Dewey's Q1-Q5; Rocko started row 37
2026-10-05T03:03:02Z | Sage (T3 Claude Code, thread 1ef1e4f8) | schema v3a | Darkwing's v3a (29daa482) rerun matched on Node 26; lead decision 57; row 37 note 2026-10-05T03:03:02Z | Sage (T3 Claude Code, thread 1ef1e4f8) | schema v3a | Darkwing's v3a (29daa482) rerun matched on Node 26; lead decision 57; row 37 note
2026-10-05T03:10:32Z | Sage (T3 Claude Code, thread 1ef1e4f8) | row 35 SR round 2 | guide revised per Darkwing's round 1 (comment 26709): mint error path, jq strings, read -rs Gitea tokens, business-prefixed bot names; PRD 0.4 REQ-CRED-1 naming; lead decision 58
+71 -38
View File
@@ -32,47 +32,69 @@ GITEA=https://git.example # your Gitea base URL
EXP=$(date -u -d '+90 days' +%Y-%m-%dT00:00:00Z) # Vikunja token expiry EXP=$(date -u -d '+90 days' +%Y-%m-%dT00:00:00Z) # Vikunja token expiry
``` ```
Write `EXP` down. It goes in the business file as each Vikunja token's Write down the date part of `EXP`. It goes in the business file as
`expires`. each Vikunja token's `expires`, in `YYYY-MM-DD` form. The broker treats
00:00Z on that date as the expiry, the same instant `EXP` names.
The commands need curl 7.76 or later, for `--fail-with-body`.
## 1. Gitea: four bot users and their tokens ## 1. Gitea: four bot users and their tokens
Gitea tokens don't expire, and the HTTP route for creating one needs a Gitea tokens don't expire, and the HTTP route for creating one needs a
password, so this part uses the web UI. password, so this part uses the web UI.
1. As a site admin, create the users `pm-bot`, `cto-bot`, `coder-bot` 1. As a site admin, create the users `mosaic-stack-pm-bot`,
and `reviewer-bot` (Site Administration, User Accounts, Create). Give `mosaic-stack-cto-bot`, `mosaic-stack-coder-bot` and
`mosaic-stack-reviewer-bot` (Site Administration, User Accounts,
Create). Gitea usernames are global to the instance, so the business
id in the name keeps one business's bots, and revoking them, apart
from another's. Give
each a long random password, which you won't need again after step 3. each a long random password, which you won't need again after step 3.
None of them is an admin. None of them is an admin.
2. In `mosaicstack/stack`, add each bot as a collaborator: 2. In `mosaicstack/stack`, add each bot as a collaborator:
| Bot | Repository access | | Bot | Repository access |
|---|---| |---|---|
| pm-bot | Write (labels, assignees and closing need it) | | mosaic-stack-pm-bot | Write (labels, assignees and closing need it) |
| cto-bot | Write | | mosaic-stack-cto-bot | Write |
| coder-bot | Write | | mosaic-stack-coder-bot | Write |
| reviewer-bot | Read | | mosaic-stack-reviewer-bot | Read |
No bot is on a protected branch's push or merge allowlist. Pushing to No bot is on a protected branch's push, merge or approvals allowlist.
a protected branch is a gated action, and it stays Jason's. Pushing to a protected branch is a gated action, and merges stay
Jason's. Reviewer-bot's approvals in Gitea are advisory and don't
count toward required approvals. The review verdict that gates a row
lives in the queue and the bus.
3. Log in as each bot, go to Settings, Applications, and generate one 3. Log in as each bot, go to Settings, Applications, and generate one
token named `mosaic-stack-<role>-<date>` with these scopes: token named `mosaic-stack-<role>-<date>` with these scopes:
| Bot | Scopes | | Bot | Scopes |
|---|---| |---|---|
| pm-bot | `write:issue`, `read:repository`, `read:user` | | mosaic-stack-pm-bot | `write:issue`, `read:repository`, `read:user` |
| cto-bot | `write:issue`, `write:repository`, `read:user` | | mosaic-stack-cto-bot | `write:issue`, `write:repository`, `read:user` |
| coder-bot | `write:issue`, `write:repository`, `read:user` | | mosaic-stack-coder-bot | `write:issue`, `write:repository`, `read:user` |
| reviewer-bot | `write:issue`, `write:repository`, `read:user` | | mosaic-stack-reviewer-bot | `write:issue`, `write:repository`, `read:user` |
Leave every other scope unset, and set none to "public only". Leave every other scope unset, and set none to "public only".
Reviewer-bot's `write:repository` is there because Gitea files pull Reviewer-bot's `write:repository` is there because Gitea checks pull
request reviews under the repository scope. Its Read collaborator request reviews against the repository scope. Its Read collaborator
access is what stops it pushing. Row SR's review checks that before access stops pushes to branches and tags. It does not stop an AGit
anyone relies on it. push to `refs/for/<branch>`, which opens a pull request. That's
4. Copy each token into its file with an editor, never `echo`: acceptable only because the broker holds the token and offers the
`$S/pm-gitea.token`, `$S/cto-gitea.token`, `$S/coder-gitea.token`, reviewer no push action.
`$S/reviewer-gitea.token`. One line, the token only. 4. Write each token to its file from a silent prompt, in the same
`umask 077` shell. Paste the token at the prompt and press Enter:
```sh
for r in pm cto coder reviewer; do
printf '%s token: ' "$r"; read -rs t; echo
printf %s "$t" > "$S/$r-gitea.token"; unset t
done
```
`read` and `printf` are shell builtins, so the value never reaches
`ps` or the history. Don't use an editor, which can leave a swap or
backup copy behind.
5. Log out of each bot account. Record today's date as each Gitea 5. Log out of each bot account. Record today's date as each Gitea
token's `rotateBy` base. Section 5 has the rotation schedule. token's `rotateBy` base. Section 5 has the rotation schedule.
@@ -110,9 +132,13 @@ docker exec -it mosaic-vikunja /app/vikunja/vikunja user create -u jason -e you@
VK=http://127.0.0.1:3456 VK=http://127.0.0.1:3456
``` ```
`user create` asks for the password when you leave out `-p`. If your `user create` asks for the password when you leave out `-p`. Keep `-it`,
build doesn't prompt, stop and set it some other way. Don't put the because without a terminal the command exits instead of prompting. Never
password on the command line. put the password on the command line.
Both mounts are required. The container runs as your uid, and
`/app/vikunja` isn't writable to it, so Vikunja needs the files mount
for its startup write check and the db mount for its database.
### Owner login for this guide ### Owner login for this guide
@@ -135,8 +161,8 @@ print("owner header written")
PY PY
``` ```
The probes logged in at `/api/v2/login`. The `token` field name is The `token` field is confirmed in the v2.7.0 source (`auth_login.go`).
assumed from v1, so the script stops if it's missing. Section 4 deletes The script still stops if it's missing. Section 4 deletes
the header file. the header file.
## 3. Vikunja: the project, the board and the bots ## 3. Vikunja: the project, the board and the bots
@@ -150,9 +176,9 @@ In the web UI, as the owner:
`blocked`. Each title appears once. `blocked`. Each title appears once.
3. In the view's settings, check that the done bucket is `done` and the 3. In the view's settings, check that the done bucket is `done` and the
default bucket is `todo`. Leave bucket configuration on manual. default bucket is `todo`. Leave bucket configuration on manual.
4. Create the labels the business file template lists, and note each id. 4. Slice 1 needs no labels, since the requirement id lives in the task,
The business file names labels by id until row S3 settles which not in a label. If you create any, note each id. The business file
labels a bot can see. names labels by id until row S3 settles which labels a bot can see.
```sh ```sh
P=<project id> P=<project id>
@@ -213,8 +239,10 @@ mint() { # mint ROLE BOT_ID SCOPES_FILE
local r=$1 id=$2 sc=$3 resp="$S/.mint-$1.json" local r=$1 id=$2 sc=$3 resp="$S/.mint-$1.json"
jq -n --arg t "$BIZ-$r-$(date +%F)" --argjson o "$id" --arg e "$EXP" --slurpfile p "$sc" \ jq -n --arg t "$BIZ-$r-$(date +%F)" --argjson o "$id" --arg e "$EXP" --slurpfile p "$sc" \
'{title:$t, owner_id:$o, expires_at:$e, permissions:$p[0]}' | '{title:$t, owner_id:$o, expires_at:$e, permissions:$p[0]}' |
api -X POST "$VK/api/v2/tokens" --data-binary @- -o "$resp" && curl -s --fail-with-body -H @"$S/vikunja-owner.hdr" -H 'Content-Type: application/json' \
jq -j .token "$resp" > "$S/$r-vikunja.token" && -X POST "$VK/api/v2/tokens" --data-binary @- -o "$resp" ||
{ jq -c '{code, message}' "$resp"; rm -f "$resp"; return 1; }
jq -je '.token | strings' "$resp" > "$S/$r-vikunja.token" &&
jq -c '{id, owner_id, expires_at, starts_tk: (.token | startswith("tk_"))}' "$resp" jq -c '{id, owner_id, expires_at, starts_tk: (.token | startswith("tk_"))}' "$resp"
rm -f "$resp" rm -f "$resp"
} }
@@ -226,9 +254,11 @@ mint sync <sync id> "$S/scopes-sync.json"
``` ```
Check that each line shows `starts_tk: true` and the `expires_at` you Check that each line shows `starts_tk: true` and the `expires_at` you
set. Vikunja accepts a past expiry without complaint, so read it. A 400 set. Vikunja accepts a past expiry without complaint, so read it. On an
with code 14002 means a scope name is wrong. Fix the scope file and mint error, `mint` prints the response's `code` and `message`, which carry no
again. token. Code 14002 means a scope name is wrong. Fix the scope file and
mint again. If the response has no `token` field, `mint` writes nothing
usable and stops; delete the empty file before you retry.
## 4. Check and clean up ## 4. Check and clean up
@@ -261,14 +291,17 @@ role. The stack never writes this file.
## 5. Rotation ## 5. Rotation
- **Vikunja**, before `expires`: log in as the owner (section 2), mint a - **Vikunja**, before `expires`: in a new shell, rerun section 0, the
new token for the same bot with `mint`, update `expires` in the owner login in section 2, and the `api` and `mint` definitions in
business file, and restart the broker. Then revoke the old token: section 3. Mint a new token for the same bot, update `expires` in the
business file, restart the broker, and finish with section 4's
`rm -f`. Then revoke the old token:
`api -X DELETE "$VK/api/v2/tokens/<old id>"`. The broker refuses to `api -X DELETE "$VK/api/v2/tokens/<old id>"`. The broker refuses to
start with a token past its `expires`, and it treats any 401 as a start with a token past its `expires`, and it treats any 401 as a
refusal, never a retry. refusal, never a retry.
- **Gitea**, every 90 days or at once if a token may have leaked: log in - **Gitea**, every 90 days or at once if a token may have leaked: log in
as the bot, generate the replacement, write it to the file, restart as the bot, generate the replacement, write it to the file with the
`read -rs` loop from section 1, restart
the broker, then delete the old token in the same settings page. the broker, then delete the old token in the same settings page.
Update `rotateBy`. Each rotation gets one line in Update `rotateBy`. Each rotation gets one line in
`docs/SESSIONS.md`: date, who, which identities, and no values. `docs/SESSIONS.md`: date, who, which identities, and no values.
+16
View File
@@ -952,3 +952,19 @@ which stay with him. Each item names who decided it and what happened.
- The broker, not a trigger, links `action.*` and `review.*` events - The broker, not a trigger, links `action.*` and `review.*` events
to a task, because the kind alone doesn't say when one is about a to a task, because the kind alone doesn't say when one is about a
task. task.
58. **Row SR round 1 rulings (2026-10-04).** Source: Darkwing's review,
#1517 comment 26709, record `agents/darkwing/work/slice1-sr-review-r1-2026-10-04.md`.
Every change requested is taken into the guide.
- Bot names carry the business id on both services, because usernames
are global to each instance: Gitea `<business>-<role>-bot`, Vikunja
`bot-<business>-<role>`. PRD draft 0.4's REQ-CRED-1 wording changes
to match. That is a naming correction inside a draft, not a new
requirement.
- Reviewer-bot's Gitea approvals are advisory. It joins no approvals
allowlist, merges stay Jason's, and the verdict that gates a row
lives in the queue and the bus.
- The guide says plainly that reviewer-bot's token can open a pull
request through an AGit push. That's acceptable only because the
broker holds the token and gives the reviewer no push action.
- Slice 1 needs no Vikunja labels. The business file example comes
from row S1, and the template file waits for it.
+5 -4
View File
@@ -122,10 +122,11 @@ parent requirement is refused.
(Gitea, Vikunja). The broker holds them, and they never enter an agent's (Gitea, Vikunja). The broker holds them, and they never enter an agent's
environment or files. In v1 Jason creates them by hand from a runbook environment or files. In v1 Jason creates them by hand from a runbook
Sage writes (round 3, 1A): Sage writes (round 3, 1A):
- in Gitea, a new bot user per role: pm-bot, cto-bot, coder-bot and - in Gitea, a new bot user per role, named `<business>-<role>-bot`,
reviewer-bot (round 3, 2A); for example `mosaic-stack-pm-bot` (round 3, 2A; lead decision 58);
- in Vikunja, a `bot-<role>` user per role, plus one read-only - in Vikunja, a `bot-<business>-<role>` user per role, plus one
`bot-<business>-sync` that does all polling (lead decision 52). read-only `bot-<business>-sync` that does all polling (lead
decisions 52 and 58).
- **REQ-CRED-2.** A session that finds only founder credentials stops. - **REQ-CRED-2.** A session that finds only founder credentials stops.
### Decisions ### Decisions