This is an automated email from the ASF dual-hosted git repository. spmallette pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit fd352cac0bbab0c01387aed867b25d7aec5628d8 Author: Stephen Mallette <[email protected]> AuthorDate: Tue Oct 13 11:08:25 2026 -0400 Use relates-to instead of related for beads links Assisted-by: Claude Code:claude-opus-5-5 --- .beads/PRIME.md | 10 ++++++---- .skills/tinker-review/references/schema.md | 4 ++-- .skills/tinker-review/scripts/discovery/beads.js | 10 +++++----- .skills/tinker-review/scripts/enrichment/api.js | 4 ++-- .skills/tinker-review/scripts/renderer/render.js | 4 ++-- .skills/tinker-review/test/beads.test.js | 10 +++++----- bin/beads-commits.py | 2 +- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/.beads/PRIME.md b/.beads/PRIME.md index c707737c87..7ff9cda6ab 100644 --- a/.beads/PRIME.md +++ b/.beads/PRIME.md @@ -60,7 +60,7 @@ bd create --type=decision --parent=<root> --title="Chose X" --metadata '{"reject # An approach you tried and abandoned is the strongest sibling — someone already walked it. bd create --type=decision --parent=<root> --title="Y" --metadata '{"rejected":true}' \ --description="what Y concretely was, why it lost, what settled it" -bd dep add <decision> <alternative> -t related # never put either of these on a task bead +bd dep add <decision> <alternative> -t relates-to # never put either of these on a task bead bd close <decision> <alternative> # both: a decision is resolved the moment you write it ``` @@ -247,7 +247,7 @@ root (feature/epic/task) ├─parent-child─▶ record apache/tinkerpop#2891 ├─parent-child─▶ record apache/tinkerpop@374b0c76d0 (written at merge) ├─parent-child─▶ decision "chose X" {rejected: false} - │ └─related─▶ decision "Y" {rejected: true} + │ └─relates-to─▶ decision "Y" {rejected: true} ├─parent-child─▶ task A "implement X" ──caused-by──▶ decision "chose X" ├─parent-child─▶ task B ──blocks──▶ task A (B waits for A) └─parent-child─▶ task C (no blocker: starts with A) @@ -275,7 +275,7 @@ a list, and `bd ready` cannot tell you anything useful about it. and `bd search <ref> --status all` finds a ticket id but not a URL. For any ref, `bd search tp --external-contains <ref> --status all` works — `tp` matches every bead id. The PR record is written at merge (section 4), not by hand. When a second root needs an - artifact that already has a record, add `bd dep add <root> <record> -t related` rather than + artifact that already has a record, add `bd dep add <root> <record> -t relates-to` rather than a duplicate. `--suggest` on that root will not see it, so supply those commits by hand at merge. - Records are the only link between beads and code; commit messages carry no bead ID. The @@ -283,6 +283,8 @@ a list, and `bd ready` cannot tell you anything useful about it. `bd query 'notes="<sha>"' --all` returns the record and its `parent`, for any commit in the landing. Quote the sha: an unquoted one starting with a digit is lexed as a number and the query fails to parse. +- **Write `relates-to` with `bd dep add -t relates-to`, never `bd dep relate`** — `relate` writes + the edge in both directions, and every consumer reads one row per link. - Only **one dependency type per pair** — `blocks` and `discovered-from` cannot coexist between the same two beads. - Never construct a bead ID; use whatever `bd create` returns. Child IDs encode birth @@ -357,7 +359,7 @@ bd query "metadata.rejected=true" --all # roads not taken; --all or closed b bd comment <id> "..." # a fact with no fork in it (never on a task bead) bd create --type=... --parent=<root> --description=... --labels=... bd dep add <task> <blocker> # default type is blocks: <task> waits for <blocker> -bd dep add <a> <b> -t caused-by|related|discovered-from|supersedes +bd dep add <a> <b> -t caused-by|relates-to|discovered-from|supersedes bd dep cycles # a plan with a cycle cannot execute bd update <id> --claim | -s pinned | --external-ref=TINKERPOP-NNNN bd search <text> diff --git a/.skills/tinker-review/references/schema.md b/.skills/tinker-review/references/schema.md index 5fdb3f0f75..08506be14f 100644 --- a/.skills/tinker-review/references/schema.md +++ b/.skills/tinker-review/references/schema.md @@ -123,7 +123,7 @@ records. `labels` is the comma-joined label list. `rootRole` is set only on roots: `primary` — the root of this PR's own record (`apache/tinkerpop#N`); `owner` — the root a matched JIRA/dev@/proposal record -belongs to; `shared` — a root that links a matched record with `related` +belongs to; `shared` — a root that links a matched record with `relates_to` (connected work). Query the PR's own work with `.has("rootRole", "primary")` and a root's subtree with `.has("root", id)`. @@ -213,4 +213,4 @@ All `EXTRACTED` except `governs`: each is a fact in the beads database. | `child_of` | Bead | Bead | bd's parent-child tree: the bead belongs to its parent | | `records` | Bead (record) | Discussion | The record's external ref names this Discussion (the PR, a JIRA, a dev@ thread, a proposal). Only drawn to Discussions discovery created. | | `governs` | Bead | Function, Type or File | The bead — usually a decision — is about this code. Written in Phase 2 by `linkBead`, so it is `INFERRED` by default, unlike the rest of this table. | -| `blocks`, `caused_by`, `related`, `supersedes`, `discovered_from`, … | Bead | Bead | bd's other dependency types, carried over with `-` written as `_`. `related` pairs a decision with the alternative it was chosen over; `caused_by` runs from a task to the decision that shaped it; `supersedes` from a newer decision to the one it replaces. Drawn only between loaded beads. | +| `blocks`, `caused_by`, `relates_to`, `supersedes`, `discovered_from`, … | Bead | Bead | bd's other dependency types, carried over with `-` written as `_`. `relates_to` pairs a decision with the alternative it was chosen over; `caused_by` runs from a task to the decision that shaped it; `supersedes` from a newer decision to the one it replaces. Drawn only between loaded beads. | diff --git a/.skills/tinker-review/scripts/discovery/beads.js b/.skills/tinker-review/scripts/discovery/beads.js index 0e7eee2a1d..059e958725 100644 --- a/.skills/tinker-review/scripts/discovery/beads.js +++ b/.skills/tinker-review/scripts/discovery/beads.js @@ -22,7 +22,7 @@ // puts every external artifact — JIRA, PR, dev@ thread, proposal — on a `record` // bead that is a parent-child child of its root, and only records carry an // external ref. A second root that needs the same artifact links to the existing -// record with a `related` edge. So a record whose ref names one of the PR's +// record with a `relates-to` edge. So a record whose ref names one of the PR's // artifacts leads to the owning root and any sharing roots, and everything // reached that way is EXTRACTED. // @@ -56,7 +56,7 @@ export const BEADS_REQUIRED_MESSAGE = * @property {string|null} closedAt * @property {string} root - Id of the root this bead belongs to. * @property {{ to: string, type: string }[]} edges - Outgoing bd dependencies other than - * parent-child (`blocks`, `caused-by`, `related`, `supersedes`, `discovered-from`, ...). + * parent-child (`blocks`, `caused-by`, `relates-to`, `supersedes`, `discovered-from`, ...). */ /** @@ -65,7 +65,7 @@ export const BEADS_REQUIRED_MESSAGE = * @property {string} id - Root bead id. * @property {"primary"|"owner"|"shared"} role - `primary`: the root of this PR's own record * (`apache/tinkerpop#N`), the work the PR delivers. `owner`: the root a matched record belongs - * to. `shared`: a root that links a matched record with `related` — connected work elsewhere. + * to. `shared`: a root that links a matched record with `relates-to` — connected work elsewhere. * @property {string[]} via - Ids of the matched records that reached this root. */ @@ -186,7 +186,7 @@ function toBead(raw) { * is also applied, as a title/ID match, so it is the project's ID prefix — which * every bead matches — rather than the ref, which a record's title need not repeat. * 2. Each matched record's top-most ancestor is its owner root; every bead that - * links the record with `related` leads to a shared root. A PR record's owner + * links the record with `relates-to` leads to a shared root. A PR record's owner * root is primary. Every root reached is loaded — connected work is context. * 3. Load each root's subtree. `bd children --json` returns one level only (its * text output is the tree), so the candidates come from @@ -248,7 +248,7 @@ export async function discoverBeads({ seeds, prRef, run }) { for (const { seed, record } of result.matches) { reach(await topOf(record), seed === prRef ? "primary" : "owner", record); - const sharers = (await run(["dep", "list", record, "--direction", "up", "-t", "related"])) || []; + const sharers = (await run(["dep", "list", record, "--direction", "up", "-t", "relates-to"])) || []; for (const s of sharers) reach(await topOf(s.id), "shared", record); } result.roots = [...roots.values()].sort((a, b) => RANK[a.role] - RANK[b.role]); diff --git a/.skills/tinker-review/scripts/enrichment/api.js b/.skills/tinker-review/scripts/enrichment/api.js index fc0dc14630..cd044cad1f 100644 --- a/.skills/tinker-review/scripts/enrichment/api.js +++ b/.skills/tinker-review/scripts/enrichment/api.js @@ -185,7 +185,7 @@ export async function listExternalRefs(g) { * and the alternatives they turned down — so the reviewer can read the change * against them. Roots come first (primary, then owner, then shared), then each * root's decisions, tasks and records. A decision lists the rejected - * alternatives it was chosen over (`related` to a rejected decision) and any + * alternatives it was chosen over (a `relates-to` edge to a rejected decision) and any * decision that supersedes it; judge the code against the newest decision in a * supersedes chain. `governs` lists code already linked with `linkBead`. * Empty when no record named the PR or its discussions. @@ -204,7 +204,7 @@ export async function listBeads(g, filter = {}) { if (filter.status) t = t.has("status", filter.status); const rows = await t.project("bead", "alternatives", "supersededBy", "governs") .by(__.valueMap()) - .by(__.both("related").has("rejected", true).values("beadId").fold()) + .by(__.both("relates_to").has("rejected", true).values("beadId").fold()) .by(__.in_("supersedes").values("beadId").fold()) .by(__.out("governs").coalesce(__.values("path"), __.values("name")).fold()) .toList(); diff --git a/.skills/tinker-review/scripts/renderer/render.js b/.skills/tinker-review/scripts/renderer/render.js index 012af4ef87..a986db4879 100644 --- a/.skills/tinker-review/scripts/renderer/render.js +++ b/.skills/tinker-review/scripts/renderer/render.js @@ -250,12 +250,12 @@ function renderDecisions(decisions, beadsById) { for (const d of decisions) { for (const e of d.edges || []) if (e.type === "supersedes") supersededBy.set(e.to, d.id); } - // A chosen decision and its rejected alternatives are joined by `related`, in either direction. + // A chosen decision and its rejected alternatives are joined by `relates-to`, in either direction. const rejectedOf = new Map(); const paired = new Set(); for (const d of decisions) { for (const e of d.edges || []) { - if (e.type !== "related") continue; + if (e.type !== "relates-to") continue; const other = beadsById.get(e.to); if (!other || other.type !== "decision") continue; const [chosen, alt] = d.rejected === false && other.rejected === true ? [d, other] diff --git a/.skills/tinker-review/test/beads.test.js b/.skills/tinker-review/test/beads.test.js index 6e3094c7ac..086a07da26 100644 --- a/.skills/tinker-review/test/beads.test.js +++ b/.skills/tinker-review/test/beads.test.js @@ -48,17 +48,17 @@ const DB = [ bead("tp-a", "feature", { comments: 2 }), bead("tp-a.1", "record", { parent: "tp-a", ref: "TINKERPOP-1234", title: "PR and JIRA" }), bead("tp-a.2", "record", { parent: "tp-a", ref: "https://lists.apache.org/thread/abc", title: "dev@ thread: topic" }), - bead("tp-a.3", "decision", { parent: "tp-a", rejected: false, deps: [["tp-a.4", "related"]], comments: 1 }), + bead("tp-a.3", "decision", { parent: "tp-a", rejected: false, deps: [["tp-a.4", "relates-to"]], comments: 1 }), bead("tp-a.4", "decision", { parent: "tp-a", rejected: true }), bead("tp-a.5", "task", { parent: "tp-a", deps: [["tp-a.3", "caused-by"]] }), bead("tp-a.5.1", "task", { parent: "tp-a.5" }), // A second root that shares tp-a's JIRA record instead of duplicating it. - bead("tp-b", "epic", { deps: [["tp-a.1", "related"]] }), + bead("tp-b", "epic", { deps: [["tp-a.1", "relates-to"]] }), bead("tp-b.1", "record", { parent: "tp-b", ref: "apache/tinkerpop#99" }), bead("tp-b.2", "decision", { parent: "tp-b", rejected: false }), // Unrelated work that relates to a bead inside tp-a: reachable by bd dep tree // from tp-a, but not part of tp-a's subtree. - bead("tp-c", "task", { deps: [["tp-a.3", "related"]] }), + bead("tp-c", "task", { deps: [["tp-a.3", "relates-to"]] }), // Substring trap for --external-contains. bead("tp-d", "feature"), bead("tp-d.1", "record", { parent: "tp-d", ref: "TINKERPOP-12345" }), @@ -172,7 +172,7 @@ test("beads carry the rejected flag, external ref and non-tree edges", async () assert.equal(get("tp-a.4").rejected, true); assert.equal(get("tp-a.5").rejected, null, "only decisions have a rejected flag"); assert.equal(get("tp-a.1").externalRef, "TINKERPOP-1234"); - assert.deepEqual(get("tp-a.3").edges, [{ to: "tp-a.4", type: "related" }]); + assert.deepEqual(get("tp-a.3").edges, [{ to: "tp-a.4", type: "relates-to" }]); assert.deepEqual(get("tp-a.5").edges, [{ to: "tp-a.3", type: "caused-by" }]); assert.equal(get("tp-a.5.1").parent, "tp-a.5"); }); @@ -230,7 +230,7 @@ const found = { beads: [ shaped("tp-a", "feature", { status: "open", labels: ["gremlin-core", "3.7.7"] }), shaped("tp-a.1", "record", { parent: "tp-a", externalRef: "apache/tinkerpop#99" }), - shaped("tp-a.2", "decision", { parent: "tp-a", edges: [{ to: "tp-a.3", type: "related" }] }), + shaped("tp-a.2", "decision", { parent: "tp-a", edges: [{ to: "tp-a.3", type: "relates-to" }] }), shaped("tp-a.3", "decision", { parent: "tp-a", rejected: true }), shaped("tp-a.4", "decision", { parent: "tp-a", edges: [{ to: "tp-a.2", type: "supersedes" }] }), shaped("tp-a.5", "task", { parent: "tp-a", status: "in_progress" }), diff --git a/bin/beads-commits.py b/bin/beads-commits.py index d74684714e..a7c231e205 100755 --- a/bin/beads-commits.py +++ b/bin/beads-commits.py @@ -186,7 +186,7 @@ def record_pr(root, ref, dry_run): elif dry_run: print(f"--dry-run: would relate {root} to {bead['id']} ({ref})") else: - bd("dep", "add", root, bead["id"], "-t", "related") + bd("dep", "add", root, bead["id"], "-t", "relates-to") print(f"related {root} to {bead['id']}, which records {ref} under {bead.get('parent')}") return if dry_run:
