@attalabs/vinaya 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1513,15 +1513,58 @@ function pointerToPath(p) {
1513
1513
  return idx === -1 ? p : p.slice(0, idx);
1514
1514
  }
1515
1515
  var SEPARATOR = /(?:[ \t]*[—–][ \t]*|[ \t]+-[ \t]+)/.source;
1516
- function readDocAcks(body) {
1517
- const acks = [];
1518
- const re = new RegExp(`^[ \\t]*Doc-ack[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1516
+ function readPointerNoteField(body, field) {
1517
+ const out = [];
1518
+ const re = new RegExp(`^[ \\t]*${field}[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1519
1519
  for (const m of body.matchAll(re)) {
1520
- acks.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1520
+ out.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1521
+ }
1522
+ return out;
1523
+ }
1524
+ function readDocAcks(body) {
1525
+ return readPointerNoteField(body, "Doc-ack");
1526
+ }
1527
+ function readDocNeutrals(body) {
1528
+ return readPointerNoteField(body, "Doc-neutral");
1529
+ }
1530
+ var LANGUAGE_COMMENT_PREFIXES = [
1531
+ { test: /\.(ts|tsx|js|jsx|mjs|cjs)$/, prefixes: ["//"] },
1532
+ { test: /(^|\/)(pre-push|pre-commit|pre-merge-commit)$/, prefixes: ["#"] },
1533
+ { test: /\.(sh|bash)$/, prefixes: ["#"] },
1534
+ { test: /\.ya?ml$/, prefixes: ["#"] },
1535
+ { test: /\.py$/, prefixes: ["#"] }
1536
+ ];
1537
+ function commentPrefixesForPath(path) {
1538
+ for (const { test, prefixes } of LANGUAGE_COMMENT_PREFIXES) {
1539
+ if (test.test(path))
1540
+ return prefixes;
1521
1541
  }
1522
- return acks;
1542
+ return [];
1523
1543
  }
1524
- function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive) {
1544
+ function isNeutralDiffContentLine(line, prefixes) {
1545
+ const t = line.trim();
1546
+ if (t === "")
1547
+ return true;
1548
+ if (t.startsWith("#!"))
1549
+ return false;
1550
+ return prefixes.some((p) => t.startsWith(p));
1551
+ }
1552
+ function isMechanicallyNeutralDiff(diffText, path) {
1553
+ const prefixes = commentPrefixesForPath(path);
1554
+ let sawChange = false;
1555
+ for (const raw of diffText.split(`
1556
+ `)) {
1557
+ if (raw.startsWith("+++ ") || raw.startsWith("--- ") || raw.startsWith("@@"))
1558
+ continue;
1559
+ if (raw.startsWith("+") || raw.startsWith("-")) {
1560
+ if (!isNeutralDiffContentLine(raw.slice(1), prefixes))
1561
+ return false;
1562
+ sawChange = true;
1563
+ }
1564
+ }
1565
+ return sawChange;
1566
+ }
1567
+ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive, getDiff) {
1525
1568
  const out = { errors: [], notes: [] };
1526
1569
  if (docOwnersContent === null)
1527
1570
  return out;
@@ -1534,13 +1577,15 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1534
1577
  const fired = [];
1535
1578
  for (const b of bindings) {
1536
1579
  const re = globToRegex(b.glob);
1537
- if (codeFiles.some((f) => re.test(f)))
1538
- fired.push(b);
1580
+ const matchedFiles = codeFiles.filter((f) => re.test(f));
1581
+ if (matchedFiles.length > 0)
1582
+ fired.push({ binding: b, matchedFiles });
1539
1583
  }
1540
1584
  if (fired.length === 0)
1541
1585
  return out;
1542
1586
  const acks = readDocAcks(prBody);
1543
- for (const b of fired) {
1587
+ const neutrals = readDocNeutrals(prBody);
1588
+ for (const { binding: b, matchedFiles } of fired) {
1544
1589
  if (waiverActive) {
1545
1590
  out.notes.push(`C5 doc-waiver active for ${b.pointer} (binding ${DOC_OWNERS_PATH}:${b.lineNum})`);
1546
1591
  continue;
@@ -1557,9 +1602,22 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1557
1602
  out.errors.push(`C5 doc-owners-dangling: ${DOC_OWNERS_PATH}:${b.lineNum} points to ${b.pointer}, which does not exist on disk. Fix the binding or add the doc.`);
1558
1603
  continue;
1559
1604
  }
1560
- if (!changed.includes(pointerPath)) {
1561
- out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1605
+ if (changed.includes(pointerPath))
1606
+ continue;
1607
+ const declared = neutrals.find((n) => n.surface === b.pointer);
1608
+ if (declared) {
1609
+ const evidenced = getDiff !== undefined && matchedFiles.every((f) => {
1610
+ const diff = getDiff(f);
1611
+ return diff !== null && isMechanicallyNeutralDiff(diff, f);
1612
+ });
1613
+ if (evidenced) {
1614
+ out.notes.push(`C5 doc-neutral: ${b.pointer} not required for ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\`) — declared neutral ("${declared.note}"), diff of ${matchedFiles.join(", ")} confirmed comment/whitespace-only.`);
1615
+ continue;
1616
+ }
1617
+ out.errors.push(`C5 doc-neutral-unverified: ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}) declared \`Doc-neutral: ${b.pointer} — ${declared.note}\`, but the diff of ${matchedFiles.join(", ")} contains changes beyond comments/whitespace. Update ${pointerPath}, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1618
+ continue;
1562
1619
  }
1620
+ out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, declare \`Doc-neutral: ${b.pointer} — <why>\` if the change is genuinely mechanically-neutral, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1563
1621
  }
1564
1622
  return out;
1565
1623
  }
@@ -1514,15 +1514,58 @@ function pointerToPath(p) {
1514
1514
  return idx === -1 ? p : p.slice(0, idx);
1515
1515
  }
1516
1516
  var SEPARATOR = /(?:[ \t]*[—–][ \t]*|[ \t]+-[ \t]+)/.source;
1517
- function readDocAcks(body) {
1518
- const acks = [];
1519
- const re = new RegExp(`^[ \\t]*Doc-ack[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1517
+ function readPointerNoteField(body, field) {
1518
+ const out = [];
1519
+ const re = new RegExp(`^[ \\t]*${field}[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1520
1520
  for (const m of body.matchAll(re)) {
1521
- acks.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1521
+ out.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1522
+ }
1523
+ return out;
1524
+ }
1525
+ function readDocAcks(body) {
1526
+ return readPointerNoteField(body, "Doc-ack");
1527
+ }
1528
+ function readDocNeutrals(body) {
1529
+ return readPointerNoteField(body, "Doc-neutral");
1530
+ }
1531
+ var LANGUAGE_COMMENT_PREFIXES = [
1532
+ { test: /\.(ts|tsx|js|jsx|mjs|cjs)$/, prefixes: ["//"] },
1533
+ { test: /(^|\/)(pre-push|pre-commit|pre-merge-commit)$/, prefixes: ["#"] },
1534
+ { test: /\.(sh|bash)$/, prefixes: ["#"] },
1535
+ { test: /\.ya?ml$/, prefixes: ["#"] },
1536
+ { test: /\.py$/, prefixes: ["#"] }
1537
+ ];
1538
+ function commentPrefixesForPath(path) {
1539
+ for (const { test, prefixes } of LANGUAGE_COMMENT_PREFIXES) {
1540
+ if (test.test(path))
1541
+ return prefixes;
1522
1542
  }
1523
- return acks;
1543
+ return [];
1524
1544
  }
1525
- function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive) {
1545
+ function isNeutralDiffContentLine(line, prefixes) {
1546
+ const t = line.trim();
1547
+ if (t === "")
1548
+ return true;
1549
+ if (t.startsWith("#!"))
1550
+ return false;
1551
+ return prefixes.some((p) => t.startsWith(p));
1552
+ }
1553
+ function isMechanicallyNeutralDiff(diffText, path) {
1554
+ const prefixes = commentPrefixesForPath(path);
1555
+ let sawChange = false;
1556
+ for (const raw of diffText.split(`
1557
+ `)) {
1558
+ if (raw.startsWith("+++ ") || raw.startsWith("--- ") || raw.startsWith("@@"))
1559
+ continue;
1560
+ if (raw.startsWith("+") || raw.startsWith("-")) {
1561
+ if (!isNeutralDiffContentLine(raw.slice(1), prefixes))
1562
+ return false;
1563
+ sawChange = true;
1564
+ }
1565
+ }
1566
+ return sawChange;
1567
+ }
1568
+ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive, getDiff) {
1526
1569
  const out = { errors: [], notes: [] };
1527
1570
  if (docOwnersContent === null)
1528
1571
  return out;
@@ -1535,13 +1578,15 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1535
1578
  const fired = [];
1536
1579
  for (const b of bindings) {
1537
1580
  const re = globToRegex(b.glob);
1538
- if (codeFiles.some((f) => re.test(f)))
1539
- fired.push(b);
1581
+ const matchedFiles = codeFiles.filter((f) => re.test(f));
1582
+ if (matchedFiles.length > 0)
1583
+ fired.push({ binding: b, matchedFiles });
1540
1584
  }
1541
1585
  if (fired.length === 0)
1542
1586
  return out;
1543
1587
  const acks = readDocAcks(prBody);
1544
- for (const b of fired) {
1588
+ const neutrals = readDocNeutrals(prBody);
1589
+ for (const { binding: b, matchedFiles } of fired) {
1545
1590
  if (waiverActive) {
1546
1591
  out.notes.push(`C5 doc-waiver active for ${b.pointer} (binding ${DOC_OWNERS_PATH}:${b.lineNum})`);
1547
1592
  continue;
@@ -1558,9 +1603,22 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1558
1603
  out.errors.push(`C5 doc-owners-dangling: ${DOC_OWNERS_PATH}:${b.lineNum} points to ${b.pointer}, which does not exist on disk. Fix the binding or add the doc.`);
1559
1604
  continue;
1560
1605
  }
1561
- if (!changed.includes(pointerPath)) {
1562
- out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1606
+ if (changed.includes(pointerPath))
1607
+ continue;
1608
+ const declared = neutrals.find((n) => n.surface === b.pointer);
1609
+ if (declared) {
1610
+ const evidenced = getDiff !== undefined && matchedFiles.every((f) => {
1611
+ const diff = getDiff(f);
1612
+ return diff !== null && isMechanicallyNeutralDiff(diff, f);
1613
+ });
1614
+ if (evidenced) {
1615
+ out.notes.push(`C5 doc-neutral: ${b.pointer} not required for ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\`) — declared neutral ("${declared.note}"), diff of ${matchedFiles.join(", ")} confirmed comment/whitespace-only.`);
1616
+ continue;
1617
+ }
1618
+ out.errors.push(`C5 doc-neutral-unverified: ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}) declared \`Doc-neutral: ${b.pointer} — ${declared.note}\`, but the diff of ${matchedFiles.join(", ")} contains changes beyond comments/whitespace. Update ${pointerPath}, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1619
+ continue;
1563
1620
  }
1621
+ out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, declare \`Doc-neutral: ${b.pointer} — <why>\` if the change is genuinely mechanically-neutral, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1564
1622
  }
1565
1623
  return out;
1566
1624
  }
@@ -1514,15 +1514,58 @@ function pointerToPath(p) {
1514
1514
  return idx === -1 ? p : p.slice(0, idx);
1515
1515
  }
1516
1516
  var SEPARATOR = /(?:[ \t]*[—–][ \t]*|[ \t]+-[ \t]+)/.source;
1517
- function readDocAcks(body) {
1518
- const acks = [];
1519
- const re = new RegExp(`^[ \\t]*Doc-ack[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1517
+ function readPointerNoteField(body, field) {
1518
+ const out = [];
1519
+ const re = new RegExp(`^[ \\t]*${field}[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1520
1520
  for (const m of body.matchAll(re)) {
1521
- acks.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1521
+ out.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1522
+ }
1523
+ return out;
1524
+ }
1525
+ function readDocAcks(body) {
1526
+ return readPointerNoteField(body, "Doc-ack");
1527
+ }
1528
+ function readDocNeutrals(body) {
1529
+ return readPointerNoteField(body, "Doc-neutral");
1530
+ }
1531
+ var LANGUAGE_COMMENT_PREFIXES = [
1532
+ { test: /\.(ts|tsx|js|jsx|mjs|cjs)$/, prefixes: ["//"] },
1533
+ { test: /(^|\/)(pre-push|pre-commit|pre-merge-commit)$/, prefixes: ["#"] },
1534
+ { test: /\.(sh|bash)$/, prefixes: ["#"] },
1535
+ { test: /\.ya?ml$/, prefixes: ["#"] },
1536
+ { test: /\.py$/, prefixes: ["#"] }
1537
+ ];
1538
+ function commentPrefixesForPath(path) {
1539
+ for (const { test, prefixes } of LANGUAGE_COMMENT_PREFIXES) {
1540
+ if (test.test(path))
1541
+ return prefixes;
1522
1542
  }
1523
- return acks;
1543
+ return [];
1524
1544
  }
1525
- function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive) {
1545
+ function isNeutralDiffContentLine(line, prefixes) {
1546
+ const t = line.trim();
1547
+ if (t === "")
1548
+ return true;
1549
+ if (t.startsWith("#!"))
1550
+ return false;
1551
+ return prefixes.some((p) => t.startsWith(p));
1552
+ }
1553
+ function isMechanicallyNeutralDiff(diffText, path) {
1554
+ const prefixes = commentPrefixesForPath(path);
1555
+ let sawChange = false;
1556
+ for (const raw of diffText.split(`
1557
+ `)) {
1558
+ if (raw.startsWith("+++ ") || raw.startsWith("--- ") || raw.startsWith("@@"))
1559
+ continue;
1560
+ if (raw.startsWith("+") || raw.startsWith("-")) {
1561
+ if (!isNeutralDiffContentLine(raw.slice(1), prefixes))
1562
+ return false;
1563
+ sawChange = true;
1564
+ }
1565
+ }
1566
+ return sawChange;
1567
+ }
1568
+ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive, getDiff) {
1526
1569
  const out = { errors: [], notes: [] };
1527
1570
  if (docOwnersContent === null)
1528
1571
  return out;
@@ -1535,13 +1578,15 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1535
1578
  const fired = [];
1536
1579
  for (const b of bindings) {
1537
1580
  const re = globToRegex(b.glob);
1538
- if (codeFiles.some((f) => re.test(f)))
1539
- fired.push(b);
1581
+ const matchedFiles = codeFiles.filter((f) => re.test(f));
1582
+ if (matchedFiles.length > 0)
1583
+ fired.push({ binding: b, matchedFiles });
1540
1584
  }
1541
1585
  if (fired.length === 0)
1542
1586
  return out;
1543
1587
  const acks = readDocAcks(prBody);
1544
- for (const b of fired) {
1588
+ const neutrals = readDocNeutrals(prBody);
1589
+ for (const { binding: b, matchedFiles } of fired) {
1545
1590
  if (waiverActive) {
1546
1591
  out.notes.push(`C5 doc-waiver active for ${b.pointer} (binding ${DOC_OWNERS_PATH}:${b.lineNum})`);
1547
1592
  continue;
@@ -1558,9 +1603,22 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1558
1603
  out.errors.push(`C5 doc-owners-dangling: ${DOC_OWNERS_PATH}:${b.lineNum} points to ${b.pointer}, which does not exist on disk. Fix the binding or add the doc.`);
1559
1604
  continue;
1560
1605
  }
1561
- if (!changed.includes(pointerPath)) {
1562
- out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1606
+ if (changed.includes(pointerPath))
1607
+ continue;
1608
+ const declared = neutrals.find((n) => n.surface === b.pointer);
1609
+ if (declared) {
1610
+ const evidenced = getDiff !== undefined && matchedFiles.every((f) => {
1611
+ const diff = getDiff(f);
1612
+ return diff !== null && isMechanicallyNeutralDiff(diff, f);
1613
+ });
1614
+ if (evidenced) {
1615
+ out.notes.push(`C5 doc-neutral: ${b.pointer} not required for ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\`) — declared neutral ("${declared.note}"), diff of ${matchedFiles.join(", ")} confirmed comment/whitespace-only.`);
1616
+ continue;
1617
+ }
1618
+ out.errors.push(`C5 doc-neutral-unverified: ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}) declared \`Doc-neutral: ${b.pointer} — ${declared.note}\`, but the diff of ${matchedFiles.join(", ")} contains changes beyond comments/whitespace. Update ${pointerPath}, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1619
+ continue;
1563
1620
  }
1621
+ out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, declare \`Doc-neutral: ${b.pointer} — <why>\` if the change is genuinely mechanically-neutral, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1564
1622
  }
1565
1623
  return out;
1566
1624
  }
@@ -1515,15 +1515,58 @@ function pointerToPath(p) {
1515
1515
  return idx === -1 ? p : p.slice(0, idx);
1516
1516
  }
1517
1517
  var SEPARATOR = /(?:[ \t]*[—–][ \t]*|[ \t]+-[ \t]+)/.source;
1518
- function readDocAcks(body) {
1519
- const acks = [];
1520
- const re = new RegExp(`^[ \\t]*Doc-ack[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1518
+ function readPointerNoteField(body, field) {
1519
+ const out = [];
1520
+ const re = new RegExp(`^[ \\t]*${field}[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1521
1521
  for (const m of body.matchAll(re)) {
1522
- acks.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1522
+ out.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1523
+ }
1524
+ return out;
1525
+ }
1526
+ function readDocAcks(body) {
1527
+ return readPointerNoteField(body, "Doc-ack");
1528
+ }
1529
+ function readDocNeutrals(body) {
1530
+ return readPointerNoteField(body, "Doc-neutral");
1531
+ }
1532
+ var LANGUAGE_COMMENT_PREFIXES = [
1533
+ { test: /\.(ts|tsx|js|jsx|mjs|cjs)$/, prefixes: ["//"] },
1534
+ { test: /(^|\/)(pre-push|pre-commit|pre-merge-commit)$/, prefixes: ["#"] },
1535
+ { test: /\.(sh|bash)$/, prefixes: ["#"] },
1536
+ { test: /\.ya?ml$/, prefixes: ["#"] },
1537
+ { test: /\.py$/, prefixes: ["#"] }
1538
+ ];
1539
+ function commentPrefixesForPath(path) {
1540
+ for (const { test, prefixes } of LANGUAGE_COMMENT_PREFIXES) {
1541
+ if (test.test(path))
1542
+ return prefixes;
1523
1543
  }
1524
- return acks;
1544
+ return [];
1525
1545
  }
1526
- function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive) {
1546
+ function isNeutralDiffContentLine(line, prefixes) {
1547
+ const t = line.trim();
1548
+ if (t === "")
1549
+ return true;
1550
+ if (t.startsWith("#!"))
1551
+ return false;
1552
+ return prefixes.some((p) => t.startsWith(p));
1553
+ }
1554
+ function isMechanicallyNeutralDiff(diffText, path) {
1555
+ const prefixes = commentPrefixesForPath(path);
1556
+ let sawChange = false;
1557
+ for (const raw of diffText.split(`
1558
+ `)) {
1559
+ if (raw.startsWith("+++ ") || raw.startsWith("--- ") || raw.startsWith("@@"))
1560
+ continue;
1561
+ if (raw.startsWith("+") || raw.startsWith("-")) {
1562
+ if (!isNeutralDiffContentLine(raw.slice(1), prefixes))
1563
+ return false;
1564
+ sawChange = true;
1565
+ }
1566
+ }
1567
+ return sawChange;
1568
+ }
1569
+ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive, getDiff) {
1527
1570
  const out = { errors: [], notes: [] };
1528
1571
  if (docOwnersContent === null)
1529
1572
  return out;
@@ -1536,13 +1579,15 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1536
1579
  const fired = [];
1537
1580
  for (const b of bindings) {
1538
1581
  const re = globToRegex(b.glob);
1539
- if (codeFiles.some((f) => re.test(f)))
1540
- fired.push(b);
1582
+ const matchedFiles = codeFiles.filter((f) => re.test(f));
1583
+ if (matchedFiles.length > 0)
1584
+ fired.push({ binding: b, matchedFiles });
1541
1585
  }
1542
1586
  if (fired.length === 0)
1543
1587
  return out;
1544
1588
  const acks = readDocAcks(prBody);
1545
- for (const b of fired) {
1589
+ const neutrals = readDocNeutrals(prBody);
1590
+ for (const { binding: b, matchedFiles } of fired) {
1546
1591
  if (waiverActive) {
1547
1592
  out.notes.push(`C5 doc-waiver active for ${b.pointer} (binding ${DOC_OWNERS_PATH}:${b.lineNum})`);
1548
1593
  continue;
@@ -1559,9 +1604,22 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1559
1604
  out.errors.push(`C5 doc-owners-dangling: ${DOC_OWNERS_PATH}:${b.lineNum} points to ${b.pointer}, which does not exist on disk. Fix the binding or add the doc.`);
1560
1605
  continue;
1561
1606
  }
1562
- if (!changed.includes(pointerPath)) {
1563
- out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1607
+ if (changed.includes(pointerPath))
1608
+ continue;
1609
+ const declared = neutrals.find((n) => n.surface === b.pointer);
1610
+ if (declared) {
1611
+ const evidenced = getDiff !== undefined && matchedFiles.every((f) => {
1612
+ const diff = getDiff(f);
1613
+ return diff !== null && isMechanicallyNeutralDiff(diff, f);
1614
+ });
1615
+ if (evidenced) {
1616
+ out.notes.push(`C5 doc-neutral: ${b.pointer} not required for ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\`) — declared neutral ("${declared.note}"), diff of ${matchedFiles.join(", ")} confirmed comment/whitespace-only.`);
1617
+ continue;
1618
+ }
1619
+ out.errors.push(`C5 doc-neutral-unverified: ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}) declared \`Doc-neutral: ${b.pointer} — ${declared.note}\`, but the diff of ${matchedFiles.join(", ")} contains changes beyond comments/whitespace. Update ${pointerPath}, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1620
+ continue;
1564
1621
  }
1622
+ out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, declare \`Doc-neutral: ${b.pointer} — <why>\` if the change is genuinely mechanically-neutral, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1565
1623
  }
1566
1624
  return out;
1567
1625
  }
@@ -1513,15 +1513,58 @@ function pointerToPath(p) {
1513
1513
  return idx === -1 ? p : p.slice(0, idx);
1514
1514
  }
1515
1515
  var SEPARATOR = /(?:[ \t]*[—–][ \t]*|[ \t]+-[ \t]+)/.source;
1516
- function readDocAcks(body) {
1517
- const acks = [];
1518
- const re = new RegExp(`^[ \\t]*Doc-ack[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1516
+ function readPointerNoteField(body, field) {
1517
+ const out = [];
1518
+ const re = new RegExp(`^[ \\t]*${field}[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1519
1519
  for (const m of body.matchAll(re)) {
1520
- acks.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1520
+ out.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1521
+ }
1522
+ return out;
1523
+ }
1524
+ function readDocAcks(body) {
1525
+ return readPointerNoteField(body, "Doc-ack");
1526
+ }
1527
+ function readDocNeutrals(body) {
1528
+ return readPointerNoteField(body, "Doc-neutral");
1529
+ }
1530
+ var LANGUAGE_COMMENT_PREFIXES = [
1531
+ { test: /\.(ts|tsx|js|jsx|mjs|cjs)$/, prefixes: ["//"] },
1532
+ { test: /(^|\/)(pre-push|pre-commit|pre-merge-commit)$/, prefixes: ["#"] },
1533
+ { test: /\.(sh|bash)$/, prefixes: ["#"] },
1534
+ { test: /\.ya?ml$/, prefixes: ["#"] },
1535
+ { test: /\.py$/, prefixes: ["#"] }
1536
+ ];
1537
+ function commentPrefixesForPath(path) {
1538
+ for (const { test, prefixes } of LANGUAGE_COMMENT_PREFIXES) {
1539
+ if (test.test(path))
1540
+ return prefixes;
1521
1541
  }
1522
- return acks;
1542
+ return [];
1523
1543
  }
1524
- function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive) {
1544
+ function isNeutralDiffContentLine(line, prefixes) {
1545
+ const t = line.trim();
1546
+ if (t === "")
1547
+ return true;
1548
+ if (t.startsWith("#!"))
1549
+ return false;
1550
+ return prefixes.some((p) => t.startsWith(p));
1551
+ }
1552
+ function isMechanicallyNeutralDiff(diffText, path) {
1553
+ const prefixes = commentPrefixesForPath(path);
1554
+ let sawChange = false;
1555
+ for (const raw of diffText.split(`
1556
+ `)) {
1557
+ if (raw.startsWith("+++ ") || raw.startsWith("--- ") || raw.startsWith("@@"))
1558
+ continue;
1559
+ if (raw.startsWith("+") || raw.startsWith("-")) {
1560
+ if (!isNeutralDiffContentLine(raw.slice(1), prefixes))
1561
+ return false;
1562
+ sawChange = true;
1563
+ }
1564
+ }
1565
+ return sawChange;
1566
+ }
1567
+ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive, getDiff) {
1525
1568
  const out = { errors: [], notes: [] };
1526
1569
  if (docOwnersContent === null)
1527
1570
  return out;
@@ -1534,13 +1577,15 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1534
1577
  const fired = [];
1535
1578
  for (const b of bindings) {
1536
1579
  const re = globToRegex(b.glob);
1537
- if (codeFiles.some((f) => re.test(f)))
1538
- fired.push(b);
1580
+ const matchedFiles = codeFiles.filter((f) => re.test(f));
1581
+ if (matchedFiles.length > 0)
1582
+ fired.push({ binding: b, matchedFiles });
1539
1583
  }
1540
1584
  if (fired.length === 0)
1541
1585
  return out;
1542
1586
  const acks = readDocAcks(prBody);
1543
- for (const b of fired) {
1587
+ const neutrals = readDocNeutrals(prBody);
1588
+ for (const { binding: b, matchedFiles } of fired) {
1544
1589
  if (waiverActive) {
1545
1590
  out.notes.push(`C5 doc-waiver active for ${b.pointer} (binding ${DOC_OWNERS_PATH}:${b.lineNum})`);
1546
1591
  continue;
@@ -1557,9 +1602,22 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1557
1602
  out.errors.push(`C5 doc-owners-dangling: ${DOC_OWNERS_PATH}:${b.lineNum} points to ${b.pointer}, which does not exist on disk. Fix the binding or add the doc.`);
1558
1603
  continue;
1559
1604
  }
1560
- if (!changed.includes(pointerPath)) {
1561
- out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1605
+ if (changed.includes(pointerPath))
1606
+ continue;
1607
+ const declared = neutrals.find((n) => n.surface === b.pointer);
1608
+ if (declared) {
1609
+ const evidenced = getDiff !== undefined && matchedFiles.every((f) => {
1610
+ const diff = getDiff(f);
1611
+ return diff !== null && isMechanicallyNeutralDiff(diff, f);
1612
+ });
1613
+ if (evidenced) {
1614
+ out.notes.push(`C5 doc-neutral: ${b.pointer} not required for ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\`) — declared neutral ("${declared.note}"), diff of ${matchedFiles.join(", ")} confirmed comment/whitespace-only.`);
1615
+ continue;
1616
+ }
1617
+ out.errors.push(`C5 doc-neutral-unverified: ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}) declared \`Doc-neutral: ${b.pointer} — ${declared.note}\`, but the diff of ${matchedFiles.join(", ")} contains changes beyond comments/whitespace. Update ${pointerPath}, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1618
+ continue;
1562
1619
  }
1620
+ out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, declare \`Doc-neutral: ${b.pointer} — <why>\` if the change is genuinely mechanically-neutral, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1563
1621
  }
1564
1622
  return out;
1565
1623
  }
@@ -1513,15 +1513,58 @@ function pointerToPath(p) {
1513
1513
  return idx === -1 ? p : p.slice(0, idx);
1514
1514
  }
1515
1515
  var SEPARATOR = /(?:[ \t]*[—–][ \t]*|[ \t]+-[ \t]+)/.source;
1516
- function readDocAcks(body) {
1517
- const acks = [];
1518
- const re = new RegExp(`^[ \\t]*Doc-ack[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1516
+ function readPointerNoteField(body, field) {
1517
+ const out = [];
1518
+ const re = new RegExp(`^[ \\t]*${field}[ \\t]*:[ \\t]*(.+?)${SEPARATOR}(.+?)[ \\t]*$`, "gim");
1519
1519
  for (const m of body.matchAll(re)) {
1520
- acks.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1520
+ out.push({ surface: (m[1] ?? "").trim(), note: (m[2] ?? "").trim() });
1521
+ }
1522
+ return out;
1523
+ }
1524
+ function readDocAcks(body) {
1525
+ return readPointerNoteField(body, "Doc-ack");
1526
+ }
1527
+ function readDocNeutrals(body) {
1528
+ return readPointerNoteField(body, "Doc-neutral");
1529
+ }
1530
+ var LANGUAGE_COMMENT_PREFIXES = [
1531
+ { test: /\.(ts|tsx|js|jsx|mjs|cjs)$/, prefixes: ["//"] },
1532
+ { test: /(^|\/)(pre-push|pre-commit|pre-merge-commit)$/, prefixes: ["#"] },
1533
+ { test: /\.(sh|bash)$/, prefixes: ["#"] },
1534
+ { test: /\.ya?ml$/, prefixes: ["#"] },
1535
+ { test: /\.py$/, prefixes: ["#"] }
1536
+ ];
1537
+ function commentPrefixesForPath(path) {
1538
+ for (const { test, prefixes } of LANGUAGE_COMMENT_PREFIXES) {
1539
+ if (test.test(path))
1540
+ return prefixes;
1521
1541
  }
1522
- return acks;
1542
+ return [];
1523
1543
  }
1524
- function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive) {
1544
+ function isNeutralDiffContentLine(line, prefixes) {
1545
+ const t = line.trim();
1546
+ if (t === "")
1547
+ return true;
1548
+ if (t.startsWith("#!"))
1549
+ return false;
1550
+ return prefixes.some((p) => t.startsWith(p));
1551
+ }
1552
+ function isMechanicallyNeutralDiff(diffText, path) {
1553
+ const prefixes = commentPrefixesForPath(path);
1554
+ let sawChange = false;
1555
+ for (const raw of diffText.split(`
1556
+ `)) {
1557
+ if (raw.startsWith("+++ ") || raw.startsWith("--- ") || raw.startsWith("@@"))
1558
+ continue;
1559
+ if (raw.startsWith("+") || raw.startsWith("-")) {
1560
+ if (!isNeutralDiffContentLine(raw.slice(1), prefixes))
1561
+ return false;
1562
+ sawChange = true;
1563
+ }
1564
+ }
1565
+ return sawChange;
1566
+ }
1567
+ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive, getDiff) {
1525
1568
  const out = { errors: [], notes: [] };
1526
1569
  if (docOwnersContent === null)
1527
1570
  return out;
@@ -1534,13 +1577,15 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1534
1577
  const fired = [];
1535
1578
  for (const b of bindings) {
1536
1579
  const re = globToRegex(b.glob);
1537
- if (codeFiles.some((f) => re.test(f)))
1538
- fired.push(b);
1580
+ const matchedFiles = codeFiles.filter((f) => re.test(f));
1581
+ if (matchedFiles.length > 0)
1582
+ fired.push({ binding: b, matchedFiles });
1539
1583
  }
1540
1584
  if (fired.length === 0)
1541
1585
  return out;
1542
1586
  const acks = readDocAcks(prBody);
1543
- for (const b of fired) {
1587
+ const neutrals = readDocNeutrals(prBody);
1588
+ for (const { binding: b, matchedFiles } of fired) {
1544
1589
  if (waiverActive) {
1545
1590
  out.notes.push(`C5 doc-waiver active for ${b.pointer} (binding ${DOC_OWNERS_PATH}:${b.lineNum})`);
1546
1591
  continue;
@@ -1557,9 +1602,22 @@ function evaluateC5(changed, docOwnersContent, prBody, fileExists, waiverActive)
1557
1602
  out.errors.push(`C5 doc-owners-dangling: ${DOC_OWNERS_PATH}:${b.lineNum} points to ${b.pointer}, which does not exist on disk. Fix the binding or add the doc.`);
1558
1603
  continue;
1559
1604
  }
1560
- if (!changed.includes(pointerPath)) {
1561
- out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1605
+ if (changed.includes(pointerPath))
1606
+ continue;
1607
+ const declared = neutrals.find((n) => n.surface === b.pointer);
1608
+ if (declared) {
1609
+ const evidenced = getDiff !== undefined && matchedFiles.every((f) => {
1610
+ const diff = getDiff(f);
1611
+ return diff !== null && isMechanicallyNeutralDiff(diff, f);
1612
+ });
1613
+ if (evidenced) {
1614
+ out.notes.push(`C5 doc-neutral: ${b.pointer} not required for ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\`) — declared neutral ("${declared.note}"), diff of ${matchedFiles.join(", ")} confirmed comment/whitespace-only.`);
1615
+ continue;
1616
+ }
1617
+ out.errors.push(`C5 doc-neutral-unverified: ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}) declared \`Doc-neutral: ${b.pointer} — ${declared.note}\`, but the diff of ${matchedFiles.join(", ")} contains changes beyond comments/whitespace. Update ${pointerPath}, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1618
+ continue;
1562
1619
  }
1620
+ out.errors.push(`C5 doc-coverage: code change matched ${DOC_OWNERS_PATH}:${b.lineNum} (glob \`${b.glob}\` → ${b.pointer}), but ${pointerPath} is not in the PR diff. Update it, declare \`Doc-neutral: ${b.pointer} — <why>\` if the change is genuinely mechanically-neutral, or have a principal apply the \`${WAIVER_LABEL}\` label.`);
1563
1621
  }
1564
1622
  return out;
1565
1623
  }