feat(agentid): Go port of the canonical o2r agent-id generator (parity with the aos test vector) #177

Closed
opened 2026-06-26 17:44:36 +00:00 by coilysiren · 4 comments
Owner

Goal

Provide the Go port of the canonical o2r agent-id generator so ward (which imports cli-guard) and cli-guard mint agent ids in the canonical form. The canonical rules + alphabet + test vector live in aos (#302); this is the verified Go port.

What

  • A small package (e.g. pkg/agentid) generating a lowercase 2-letter + 2-digit id over the same excluded-char alphabet as the aos canonical generator. crypto/rand-backed, uniform.
  • Vendor/sync the aos shared test vector (agent_id_vectors.json) and add a Go test asserting the port matches it byte-for-byte (seedable variant). A drift fails CI - this is the cross-language contract.

Scope note (do NOT touch these)

cli-guard ids that are not agent names stay as-is: the audit NewUUIDv7 SessionID (pkg/audit/audit.go) and the CLAUDE_SESSION_ID env (pkg/audit/session.go) are harness/audit identifiers, not agent names. This issue only adds the shared agent-id generator for name minting.

Acceptance

  • pkg/agentid generates canonical lowercase 2+2 ids; a Go test passes against the committed aos vector; CI fails on drift from the vector.

Files

new pkg/agentid/*.go, a vendored/synced agent_id_vectors.json, tests. Depends on aos #302; consumed by ward #387.

When done

Run the gate (build/vet/test, golangci-lint, godoc-current), commit, push to main, update docs/FEATURES.md, comment on ward #387 that the Go generator is available.

## Goal Provide the **Go port** of the canonical o2r agent-id generator so ward (which imports cli-guard) and cli-guard mint agent ids in the canonical form. The canonical rules + alphabet + test vector live in aos (#302); this is the **verified** Go port. ## What - A small package (e.g. `pkg/agentid`) generating a **lowercase 2-letter + 2-digit** id over the **same excluded-char alphabet** as the aos canonical generator. `crypto/rand`-backed, uniform. - Vendor/sync the aos **shared test vector** (`agent_id_vectors.json`) and add a Go test asserting the port matches it **byte-for-byte** (seedable variant). A drift fails CI - this is the cross-language contract. ## Scope note (do NOT touch these) cli-guard ids that are **not agent names** stay as-is: the audit `NewUUIDv7` SessionID (`pkg/audit/audit.go`) and the `CLAUDE_SESSION_ID` env (`pkg/audit/session.go`) are harness/audit identifiers, not agent names. This issue only **adds** the shared agent-id generator for name minting. ## Acceptance - `pkg/agentid` generates canonical lowercase 2+2 ids; a Go test passes against the committed aos vector; CI fails on drift from the vector. ## Files new `pkg/agentid/*.go`, a vendored/synced `agent_id_vectors.json`, tests. **Depends on aos #302**; consumed by ward #387. ## When done Run the gate (build/vet/test, golangci-lint, godoc-current), commit, push to `main`, update `docs/FEATURES.md`, comment on ward #387 that the Go generator is available.
Author
Owner

Held from the headless auto-dispatch batch: this is headless-eligible but blocked-on-dependency. It needs agentic-os#302 (the canonical o2r agent-id generator + shared test vector) to land first so the Go port can match the vector. Ready to dispatch once #302 closes.

(automated triage, coilyco-ops director session)

Held from the headless auto-dispatch batch: this is headless-eligible but blocked-on-dependency. It needs agentic-os#302 (the canonical o2r agent-id generator + shared test vector) to land first so the Go port can match the vector. Ready to dispatch once #302 closes. (automated triage, coilyco-ops director session)
Author
Owner

Unblocked: aos #302 has landed on canonical main (e5ccceb). The canonical generator and the shared test vector this Go port asserts against are now committed:

  • Generator: agentic_os/agent_id.py - lowercase 2-letter+2-digit over the dictatable alphabet (abcdefghjkmpqrstuvwxyz + 456789, confusables/homophones i l n o 0 1 2 3 dropped), lifted from the archived o2r source, secrets-backed.
  • Vector (the contract): agentic_os/agent_id_vectors.json - carries id_letters, id_digits, and a fixed seed->id map. The seedable algorithm is sha256(utf8(seed)) then index each sub-alphabet by the first four digest bytes mod its length (bytes 0,1 -> letters, 2,3 -> digits) - portable to Go byte-for-byte with sha256.Sum256([]byte(seed)). The exact spec string is in the vector's seed_algorithm field.

Vendor/sync that JSON and assert your crypto/rand port's seedable variant reproduces every row. A drift test on the aos side keeps the file honest.

Unblocked: aos #302 has landed on canonical `main` (e5ccceb). The canonical generator and the shared test vector this Go port asserts against are now committed: - **Generator:** `agentic_os/agent_id.py` - lowercase 2-letter+2-digit over the dictatable alphabet (`abcdefghjkmpqrstuvwxyz` + `456789`, confusables/homophones `i l n o 0 1 2 3` dropped), lifted from the archived o2r source, `secrets`-backed. - **Vector (the contract):** `agentic_os/agent_id_vectors.json` - carries `id_letters`, `id_digits`, and a fixed seed->id map. The seedable algorithm is `sha256(utf8(seed))` then index each sub-alphabet by the first four digest bytes mod its length (bytes 0,1 -> letters, 2,3 -> digits) - portable to Go byte-for-byte with `sha256.Sum256([]byte(seed))`. The exact spec string is in the vector's `seed_algorithm` field. Vendor/sync that JSON and assert your `crypto/rand` port's seedable variant reproduces every row. A drift test on the aos side keeps the file honest.
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-cli-guard-177 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-07T06:16:34Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

run seed context — what this run is carrying (ward#609)
  • Resolved: coilyco-flight-deck/cli-guard#177 · branch issue-177 · driver claude · workflow direct-main
  • Run: engineer-claude-cli-guard-177 · ward v0.419.0 · dispatched 2026-07-07T06:16:34Z
  • Comment thread: 2 included in the pre-flight read, 0 stripped (ward's own automated comments).

Issue body as seeded:

## Goal

Provide the **Go port** of the canonical o2r agent-id generator so ward (which imports cli-guard) and cli-guard mint agent ids in the canonical form. The canonical rules + alphabet + test vector live in aos (#302); this is the **verified** Go port.

## What

- A small package (e.g. `pkg/agentid`) generating a **lowercase 2-letter + 2-digit** id over the **same excluded-char alphabet** as the aos canonical generator. `crypto/rand`-backed, uniform.
- Vendor/sync the aos **shared test vector** (`agent_id_vectors.json`) and add a Go test asserting the port matches it **byte-for-byte** (seedable variant). A drift fails CI - this is the cross-language contract.

## Scope note (do NOT touch these)

cli-guard ids that are **not agent names** stay as-is: the audit `NewUUIDv7` SessionID (`pkg/audit/audit.go`) and the `CLAUDE_SESSION_ID` env (`pkg/audit/session.go`) are harness/audit identifiers, not agent names. This issue only **adds** the shared agent-id generator for name minting.

## Acceptance

- `pkg/agentid` generates canonical lowercase 2+2 ids; a Go test passes against the committed aos vector; CI fails on drift from the vector.

## Files

new `pkg/agentid/*.go`, a vendored/synced `agent_id_vectors.json`, tests. **Depends on aos #302**; consumed by ward #387.

## When done
Run the gate (build/vet/test, golangci-lint, godoc-current), commit, push to `main`, update `docs/FEATURES.md`, comment on ward #387 that the Go generator is available.

Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.419.0).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-cli-guard-177` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-07T06:16:34Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <details><summary>run seed context — what this run is carrying (ward#609)</summary> - **Resolved:** `coilyco-flight-deck/cli-guard#177` · branch `issue-177` · driver `claude` · workflow `direct-main` - **Run:** `engineer-claude-cli-guard-177` · ward `v0.419.0` · dispatched `2026-07-07T06:16:34Z` - **Comment thread:** 2 included in the pre-flight read, 0 stripped (ward's own automated comments). - included: @coilysiren (2026-07-01T04:38:43Z), @coilysiren (2026-07-04T09:10:52Z) **Issue body as seeded:** ``` ## Goal Provide the **Go port** of the canonical o2r agent-id generator so ward (which imports cli-guard) and cli-guard mint agent ids in the canonical form. The canonical rules + alphabet + test vector live in aos (#302); this is the **verified** Go port. ## What - A small package (e.g. `pkg/agentid`) generating a **lowercase 2-letter + 2-digit** id over the **same excluded-char alphabet** as the aos canonical generator. `crypto/rand`-backed, uniform. - Vendor/sync the aos **shared test vector** (`agent_id_vectors.json`) and add a Go test asserting the port matches it **byte-for-byte** (seedable variant). A drift fails CI - this is the cross-language contract. ## Scope note (do NOT touch these) cli-guard ids that are **not agent names** stay as-is: the audit `NewUUIDv7` SessionID (`pkg/audit/audit.go`) and the `CLAUDE_SESSION_ID` env (`pkg/audit/session.go`) are harness/audit identifiers, not agent names. This issue only **adds** the shared agent-id generator for name minting. ## Acceptance - `pkg/agentid` generates canonical lowercase 2+2 ids; a Go test passes against the committed aos vector; CI fails on drift from the vector. ## Files new `pkg/agentid/*.go`, a vendored/synced `agent_id_vectors.json`, tests. **Depends on aos #302**; consumed by ward #387. ## When done Run the gate (build/vet/test, golangci-lint, godoc-current), commit, push to `main`, update `docs/FEATURES.md`, comment on ward #387 that the Go generator is available. ``` Static container doctrine and seed boilerplate are identical every run and omitted here (they ride ward v0.419.0). </details> <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - pkg/agentid landed on main (d9e805e), Go port of the aos o2r agent-id generator with the vendored vector asserted byte-for-byte.

The core port was the easy part: the aos generator (agentic_os/agent_id.py) spells its seed algorithm out in the docstring precisely so a port cannot guess wrong, so SeededID matched all 24 committed vectors on the first go test run. The one thing I double-checked was modulo bias in the random minter - Python leans on secrets.choice, so I used crypto/rand + big.Int rejection sampling for NewID rather than a raw %, to keep it genuinely uniform.

What actually fought back was the pre-commit suite, not the code. The 2-line comment-block cap clipped every godoc I wrote (package doc is exempt, function docs are not), and the 4000-char cap on docs/FEATURES.md meant a single new bullet forced me to shave a dozen existing descriptions to claw back ~160 chars. Both are healthy constraints, just a lot of small iterations.

Confident in the result: the drift test is the real contract and it is green, alphabet + all vectors matched. Scope stayed tight - only the name-minting generator, the audit SessionID / CLAUDE_SESSION_ID identifiers were left alone per the issue. Posted the availability note on ward #387 (it is already closed, but the record is there); no follow-ups worth filing.

WARD-OUTCOME: done - pkg/agentid landed on main (d9e805e), Go port of the aos o2r agent-id generator with the vendored vector asserted byte-for-byte. The core port was the easy part: the aos generator (`agentic_os/agent_id.py`) spells its seed algorithm out in the docstring precisely so a port cannot guess wrong, so `SeededID` matched all 24 committed vectors on the first `go test` run. The one thing I double-checked was modulo bias in the *random* minter - Python leans on `secrets.choice`, so I used `crypto/rand` + `big.Int` rejection sampling for `NewID` rather than a raw `%`, to keep it genuinely uniform. What actually fought back was the pre-commit suite, not the code. The 2-line comment-block cap clipped every godoc I wrote (package doc is exempt, function docs are not), and the 4000-char cap on `docs/FEATURES.md` meant a single new bullet forced me to shave a dozen existing descriptions to claw back ~160 chars. Both are healthy constraints, just a lot of small iterations. Confident in the result: the drift test is the real contract and it is green, alphabet + all vectors matched. Scope stayed tight - only the name-minting generator, the audit SessionID / CLAUDE_SESSION_ID identifiers were left alone per the issue. Posted the availability note on ward #387 (it is already closed, but the record is there); no follow-ups worth filing.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/cli-guard#177
No description provided.