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 3f1b8af39a1b099bc8bd9d2eaa420ab7d359a01f
Author: Stephen Mallette <[email protected]>
AuthorDate: Fri Oct 9 15:44:06 2026 -0400

    Cut noise from tinker-review discussion discovery
    
    Module and package names no longer count as search keywords, and an 
explicitly
    linked dev@ thread arrives with its subject and opening message.
    
    Assisted-by: Claude Code:claude-opus-5-5
---
 .../tinker-review/scripts/discovery/discussions.js | 28 ++++++++++++++++++----
 .skills/tinker-review/scripts/review.js            | 13 ++++++++--
 .skills/tinker-review/test/discovery.test.js       | 14 +++++++++++
 3 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/.skills/tinker-review/scripts/discovery/discussions.js 
b/.skills/tinker-review/scripts/discovery/discussions.js
index 1fd5ebc9b5..aff7c158b5 100644
--- a/.skills/tinker-review/scripts/discovery/discussions.js
+++ b/.skills/tinker-review/scripts/discovery/discussions.js
@@ -229,6 +229,26 @@ async function resolveExplicitProposals(repoPath, 
proposalPaths) {
   return out;
 }
 
+// An explicitly linked dev@ thread arrives as a bare URL. Fill in its subject
+// and opening message from the archive's thread API, so the agent has 
something
+// to read; on failure the placeholder title stays.
+async function fetchDevThread(thread) {
+  const id = thread.url.match(/\/thread\/([^/?#]+)/)?.[1];
+  if (!id) return thread;
+  try {
+    const data = JSON.parse(await 
httpGet(`https://lists.apache.org/api/thread.lua?id=${encodeURIComponent(id)}`));
+    const t = data.thread || {};
+    return {
+      ...thread,
+      title: t.subject || thread.title,
+      body: (t.body || "").slice(0, 1000),
+      date: t.epoch ? new Date(t.epoch * 1000).toISOString().slice(0, 10) : 
undefined,
+    };
+  } catch {
+    return thread;
+  }
+}
+
 function extractLinksFromText(text) {
   const jiraRefs = [...new 
Set([...text.matchAll(TINKERPOP_JIRA_PATTERN)].map((m) => m[0]))];
   const devListRefs = [...new 
Set([...text.matchAll(DEV_LIST_LINK_PATTERN)].map((m) => m[0]))];
@@ -257,14 +277,14 @@ async function followLinks(discussions) {
 
     for (const url of devListRefs) {
       if (discussions.some((d) => d.url === url)) continue;
-      secondary.push({
+      secondary.push(await fetchDevThread({
         url,
         source: "devlist",
         title: "(referenced thread)",
         body: "",
         found_in: `${disc.source}_body`,
         found_via: disc.id || disc.url,
-      });
+      }));
     }
   }
 
@@ -311,13 +331,13 @@ export async function discoverDiscussions(params) {
 
   // --- Dev list (direct) ---
   const devListLinks = [...new 
Set([...allText.matchAll(DEV_LIST_LINK_PATTERN)].map((m) => m[0]))];
-  const explicitDevList = devListLinks.map((url) => ({
+  const explicitDevList = await Promise.all(devListLinks.map((url) => 
fetchDevThread({
     url,
     source: "devlist",
     title: "(linked thread)",
     body: "",
     found_in: "pr",
-  }));
+  })));
 
   let searchedDevList = [];
   let devListSearchPerformed = false;
diff --git a/.skills/tinker-review/scripts/review.js 
b/.skills/tinker-review/scripts/review.js
index 905004268e..a179f0ff70 100644
--- a/.skills/tinker-review/scripts/review.js
+++ b/.skills/tinker-review/scripts/review.js
@@ -210,14 +210,23 @@ function tokenizeName(name) {
 // words (the human statement of intent) lead so they can't be truncated by the
 // cap, then distinctive tokens from changed-file basenames. Structural names,
 // generic verbs, and repo-ubiquitous tokens are filtered out so we don't 
search
-// on noise like "NOTICE" or "gremlin-server". Exported for testing.
+// on noise like "NOTICE" or "gremlin-server". So are location words: any token
+// of a changed file's directory path (a module such as tinkergraph-gremlin, a
+// package such as structure/storage) says where the change is, not what it is
+// about, and matches every proposal that mentions the module. Exported for 
testing.
 export function extractKeywords(changedFiles, prTitle) {
+  const location = new Set();
+  for (const file of changedFiles) {
+    for (const dir of file.split("/").slice(0, -1)) {
+      for (const tok of dir.toLowerCase().split(/[^a-z0-9]+/)) 
location.add(tok);
+    }
+  }
   const keywords = [];
   const seen = new Set();
   const push = (word) => {
     const k = word.toLowerCase();
     if (k.length < 3 || seen.has(k)) return;
-    if (GENERIC_WORDS.has(k) || UBIQUITOUS_TOKENS.has(k)) return;
+    if (GENERIC_WORDS.has(k) || UBIQUITOUS_TOKENS.has(k) || location.has(k)) 
return;
     seen.add(k);
     keywords.push(k);
   };
diff --git a/.skills/tinker-review/test/discovery.test.js 
b/.skills/tinker-review/test/discovery.test.js
index b2fd2b4950..67208bc84f 100644
--- a/.skills/tinker-review/test/discovery.test.js
+++ b/.skills/tinker-review/test/discovery.test.js
@@ -95,3 +95,17 @@ test("a title keyword matches at INFERRED strength; a lone 
body mention does not
     },
   );
 });
+
+test("extractKeywords drops words that only name where the change is (module 
and package dirs)", () => {
+  const kws = extractKeywords(
+    [
+      
"tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/storage/GraphBinaryStorage.java",
+      
"tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerStorageGraph.java",
+    ],
+    "TINKERPOP-3282 TinkerStorageGraph",
+  );
+  assert.ok(!kws.includes("tinkergraph"), "module name excluded");
+  assert.ok(!kws.includes("storage"), "package name excluded");
+  assert.ok(kws.includes("tinkerstoragegraph"), "title topic kept");
+  assert.ok(kws.includes("binary"), "a basename token that is not a location 
is kept");
+});

Reply via email to