Skip to content

feat(ci): add deterministic PR convention checks#587

Draft
Raina451 wants to merge 9 commits into
mainfrom
feat/deterministic-pr-checks
Draft

feat(ci): add deterministic PR convention checks#587
Raina451 wants to merge 9 commits into
mainfrom
feat/deterministic-pr-checks

Conversation

@Raina451

@Raina451 Raina451 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Adds deterministic CI checks for recurring review feedback:

  • Sample app structure and config hygiene
  • ServiceModel/service JSDoc consistency
  • OAuth scope documentation coverage
  • Test hygiene checks

Source-aware checks use the TypeScript compiler API instead of regex-heavy parsing. The checks report all current violations; existing repo cleanup can happen in focused follow-up PRs.

…ng review feedback

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
Comment thread scripts/pr-checks/validate-samples.mjs Outdated
Comment thread scripts/pr-checks/check-jsdoc-sync.mjs Outdated
@claude

claude Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Two new findings from this review run: (1) unguarded JSON.parse on package.json in validate-samples.mjs line 115 crashes instead of recording a violation; (2) content.match() in check-jsdoc-sync.mjs line 67 only indexes the first class per file, silently skipping services that have a helper class declared before them. Inline suggestions posted on both.

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
@Raina451 Raina451 changed the title [Feat] Deterministic PR convention checks in CI feat(ci): add deterministic PR convention checks Jul 8, 2026
Comment thread scripts/pr-checks/check-hygiene.mjs Outdated
Comment thread scripts/pr-checks/check-docs-consistency.mjs Outdated
@claude

claude Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Two new findings this run (existing open threads on validate-samples.mjs:117 and check-jsdoc-sync.mjs:67 were skipped — already unresolved):

  1. check-hygiene.mjs:29integrationFiles includes tests/integration/config/ and tests/integration/utils/, where try/catch and console.warn are legitimate. Any future addition of a necessary try/catch to cleanup.ts will trigger a misleading "Fix the new occurrences" failure. Suggested scoping integrationFiles to .integration.test.ts files and tests/integration/shared/ only.

  2. check-docs-consistency.mjs:66trackRe cannot match a @track-decorated method when another decorator (e.g. @deprecated) is stacked between @track(...) and the method declaration. Such methods would silently skip the scope-row check. Suggested replacing \s*\n with [\s\S]*?\n (lazy) or an explicit decorator-skip group.

Raina451 and others added 3 commits July 8, 2026 12:35
… table

Move the @track-prefix to oauth-scopes.md section mapping out of the script
and into <!-- track: ... --> markers in the doc itself. Internal-only services
are now derived from @internal tags in code rather than a maintained list.

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
…only

Replace the marker-based prefix->section map with a pure presence check: a
public @track method must be documented somewhere in oauth-scopes.md, matched
by method name against rows already in the doc. No table, no doc annotations —
only data that exists for its own reasons. Section placement stays review's job.

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
Comment thread scripts/pr-checks/check-jsdoc-sync.mjs Outdated
@claude

claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

One new finding this run (the four existing open threads were skipped per dedupe policy):

check-jsdoc-sync.mjs:99 — findIndex returns -1 when modelDoc is a proper prefix of serviceDoc (all model lines match but the service has extra trailing lines). Both modelLines[-1] and serviceLines[-1] are undefined, so the diagnostic message reads 'first difference: model: end, service: end' with no hint of what actually differs. Fix: fall back to modelLines.length as the index when findIndex returns -1, which points at the first extra line of the service doc.

Comment on lines +88 to +94
const modelLines = modelDoc.split('\n');
const serviceLines = serviceDoc.split('\n');
const i = modelLines.findIndex((line, idx) => line !== serviceLines[idx]);
violations.push({
key,
message: `JSDoc differs between ${model.modelName} and ${entry.className} - first difference:\n model: ${JSON.stringify(modelLines[i] ?? '<end>')}\n service: ${JSON.stringify(serviceLines[i] ?? '<end>')}`,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findIndex returns -1 when modelDoc is a strict prefix of serviceDoc (all model lines match corresponding service lines but the service has extra trailing lines). In that case modelLines[-1] and serviceLines[-1] are both undefined, so the diagnostic prints model: '<end>', service: '<end>' — completely unhelpful.

Suggested change
const modelLines = modelDoc.split('\n');
const serviceLines = serviceDoc.split('\n');
const i = modelLines.findIndex((line, idx) => line !== serviceLines[idx]);
violations.push({
key,
message: `JSDoc differs between ${model.modelName} and ${entry.className} - first difference:\n model: ${JSON.stringify(modelLines[i] ?? '<end>')}\n service: ${JSON.stringify(serviceLines[i] ?? '<end>')}`,
});
const modelLines = modelDoc.split('\n');
const serviceLines = serviceDoc.split('\n');
const i = modelLines.findIndex((line, idx) => line !== serviceLines[idx]);
const diffIdx = i === -1 ? modelLines.length : i;
violations.push({
key,
message: `JSDoc differs between ${model.modelName} and ${entry.className} - first difference:\n model: ${JSON.stringify(modelLines[diffIdx] ?? '<end>')}\n service: ${JSON.stringify(serviceLines[diffIdx] ?? '<end>')}`,
});

When i === -1, diffIdx = modelLines.length points past the last model line, which lands on the first extra service line — the actual content that differs.

@claude

claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

One new finding this run (existing open threads on old file names were skipped — those files no longer exist in the PR, replaced by the TypeScript-AST-based rewrites):

check-jsdoc-consistency.mjs:88-94 — Same findIndex returns -1 bug that was flagged on the old check-jsdoc-sync.mjs. When modelDoc is a strict prefix of serviceDoc, all model lines match and findIndex returns -1, making modelLines[-1] and serviceLines[-1] both undefined. The diagnostic reads 'model: end, service: end' with no hint of what actually differs. Fix: fall back to modelLines.length as the index, which points at the first extra service line.

@claude

claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Unresolved thread from this review run:

check-jsdoc-consistency.mjsfindIndex returns -1 bug (thread reopened)

The prior thread on this file was resolved but the fix was not applied. The current code still reads:

const i = modelLines.findIndex((line, idx) => line !== serviceLines[idx]);
violations.push({
  key,
  message: `... model: ${JSON.stringify(modelLines[i] ?? '<end>')} service: ${JSON.stringify(serviceLines[i] ?? '<end>')}`,
});

When modelDoc is a strict prefix of serviceDoc (all model lines match but the service has extra trailing lines), findIndex returns -1. Both modelLines[-1] and serviceLines[-1] are undefined, so the diagnostic prints model: '<end>', service: '<end>' — no hint of what actually differs.

The fix is a one-liner:

const i = modelLines.findIndex((line, idx) => line !== serviceLines[idx]);
const diffIdx = i === -1 ? modelLines.length : i;
// then use diffIdx instead of i in the message

@claude

claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

One thread unresolved this run:

check-jsdoc-consistency.mjs:90 (PRRT_kwDOOpObr86PfyY2) — the findIndex returning -1 bug was flagged in the prior pass but the fix was not applied. When modelDoc is a strict prefix of serviceDoc (all model lines match but the service has extra trailing lines), findIndex returns -1, making both modelLines[-1] and serviceLines[-1] undefined. The diagnostic then prints model: '<end>', service: '<end>' with no hint of what actually differs.

Fix (same as the prior suggestion):

const i = modelLines.findIndex((line, idx) => line !== serviceLines[idx]);
const diffIdx = i === -1 ? modelLines.length : i;
violations.push({
  key,
  message: `JSDoc differs between ${model.modelName} and ${entry.className} - first difference:\n      model:   ${JSON.stringify(modelLines[diffIdx] ?? '<end>')}\n      service: ${JSON.stringify(serviceLines[diffIdx] ?? '<end>')}`,
});

All other previously raised threads were verified as fixed in this revision.

@sonarqubecloud

sonarqubecloud Bot commented Jul 9, 2026

Copy link
Copy Markdown

@claude

claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

✅ No issues found. Checked for bugs and CLAUDE.md compliance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant