# AGENTS.md — internal/wire (ADDRESSES) **How this project addresses one repository and one issue, and nothing else.** Two types, `Repo` and `Key`, and the parsing that reads them. **Imports the standard library and nothing else** — no HTTP, no filesystem, no configuration, no SDK, and above all not [`issue`](../issue/AGENTS.md). An identifier that reached for any of those would drag every user of it into that layer. Two tests hold it, see [`internal/AGENTS.md`](../AGENTS.md). | file | what is in it | |---|---| | `key.go` | `Repo`, `Key`, `ParseRepo`, `ParseKey`, `Key.In`, and the `String` methods | | `key_test.go` | every spelling above, and what a malformed one answers | | `layering_test.go` | the two tests that keep this package at the bottom | ## Four spellings, one address ```go wire.ParseKey("42") // Key{Number: 42} — repo zero: "this project's" wire.ParseKey("#42") // the same, copied out of a body wire.ParseKey("owner/repo#42") // qualified, out of the ledger wire.ParseKey("https://git.example.com/owner/repo/issues/42") ``` All four because all four are what somebody has in hand — a number from a receipt, a `#42` copied out of an issue body, a qualified key out of the ledger, a URL pasted from a browser. Refusing three of them buys nothing. **`Key.Repo` is zero when the caller named a number and nothing else**, which is the common case on a command line: `42` means "42 in this project's repository", and which repository that is, is the client's business. `Key.In(repo)` fills it in. `Repo.Zero()` requires both halves — half a name addresses nothing. ## Why a key is not a bare number `Key` has to survive being written to a file and read back: it is what the number → slug ledger is keyed by and what the `gitea:` metadata field holds. **A number is ambiguous the moment a dependency lives in another repository, and dependencies are allowed to.** So a key is a repository and a number, always, and `String()` spells it `owner/repo#42`. ## Why this package still exists after the SDK The JSON shapes used to live here too, because the transport and the bridge both had to name a Gitea issue and neither may import the other. They are `code.gitea.io/sdk/gitea`'s now. **What the SDK has no answer for is addressing.** It takes an owner, a name and an `int64`, and never parses. So the parsing stays, and so does the pair of types it produces — the values that go into the ledger, into the `gitea:` field, and into every receipt. The longer version of that history is in [`internal/AGENTS.md`](../AGENTS.md). ## What does not belong here Anything that *does* something with an address: fetching, storing, resolving a repository from configuration. This package parses and prints. Callers are [`gitea`](../gitea/AGENTS.md), [`mapping`](../mapping/AGENTS.md) and [`cmd`](../cmd/AGENTS.md). ## Keeping this file true - **Scope:** `key.go` and its tests — the two types and the spellings they accept. - **Update it when** a spelling is added or dropped, a type gains a field, or the zero-value meaning of `Key.Repo` changes. - **Do not** add a third type here without an argument for why it is an *address*. Anything that is a payload belongs to the SDK; anything that is a fact about work belongs to the domain.