Skip to content

[rig-tasks] Add 10 rig samples — 2026-07-27 - #227

Merged
pelikhan merged 1 commit into
mainfrom
rig-tasks/2026-07-27-a5b5969a86c30cbc
Jul 27, 2026
Merged

[rig-tasks] Add 10 rig samples — 2026-07-27#227
pelikhan merged 1 commit into
mainfrom
rig-tasks/2026-07-27-a5b5969a86c30cbc

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Summary

Added 10 new rig sample files to skills/rig/samples/.

# File Description Typecheck
1 230-git-rename-tracker-v3.md Git rename tracker using p.bash git log --diff-filter=R, s.array, repair() pass
2 231-yaml-workflow-linter-v2.md YAML workflow linter using p.glob, async defineTool, s.record, s.enum pass
3 232-two-phase-complexity-review-v3.md Two-phase complexity review with nano extractor + reviewer subagents pass
4 233-barrel-file-generator-v3.md Barrel file generator using p.glob, async defineTool, p.writeOutput pass
5 234-git-hook-inventory-v3.md Git hook inventory using p.bash, defineTool classifyHook, s.record pass
6 235-pr-review-checklist-v3.md PR review checklist using p.bash git diff, s.enum categories/priorities pass
7 236-vitest-coverage-parser.md Vitest coverage parser using p.readOptional, async defineTool, s.record pass
8 237-git-log-stats-aggregator.md Git log stats using p.bash pipe-delimited log, synchronous defineTool pass
9 238-ts-import-depth-analyzer.md TS import depth analyzer using p.glob, async defineTool, s.record pass
10 239-env-file-completeness-checker.md Env completeness checker using p.readOptional ×2, defineTool parseEnvKeys pass

Typecheck failures

No typecheck failures in final committed versions. Task 10 had an initial noImplicitAny failure on .map(line => callbacks in a defineTool handler — fixed by adding explicit : string type annotations.

Tasks run

  • (reused) Git file rename tracker (gitrnam7)
  • (reused) YAML file lint checker (yamlint8)
  • (reused) Two-phase code complexity reviewer (twophcx9)
  • (reused) TypeScript barrel file generator (brlfile1)
  • (reused) Git hook inventory mapper (ghkvinv2)
  • (reused) PR review checklist generator (prrchk3)
  • (new) Vitest coverage parser
  • (new) Git log stats aggregator
  • (new) TypeScript import depth analyzer
  • (new) Env file completeness checker

Generated by Daily Rig Task Generator · sonnet46 86.4 AIC · ⌖ 9.44 AIC · ⊞ 6.7K ·

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review July 27, 2026 21:13
@pelikhan
pelikhan merged commit 4b348f6 into main Jul 27, 2026
1 check passed
@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /grill-with-docs — requesting changes on correctness issues in defineTool handlers that readers will copy into production agents.

📋 Key Themes & Highlights

Issues found (5 inline comments)

  • Dead code (234): hookPath.endsWith(".sample") is always false — the .sample guard intent is silently lost
  • Glob scope (238): p.glob("**/*.ts") pulls in node_modules; the instruction says to exclude them but the list is already resolved before the model sees it
  • Redundant parameter (236): parseCoverageSummary takes a filePath parameter but the agent always passes the hard-coded string "coverage/coverage-summary.json", making the parameter misleading
  • Date NaN (237): totalCommits increments even when the date is unparseable, causing a mismatch with perDayOfWeek totals
  • Shell word-splitting (232): wc -l $(find ...) splits on spaces in file paths; readers copying this pattern may hit errors in real repos

Positive Highlights

  • ✅ Consistent use of s.optional, s.enum, and s.record throughout
  • repair() addon applied on agents that output structured data where parse failures are likely
  • ✅ Good use of p.readOptional for graceful file-absent handling in 236 and 239
  • ✅ Two-phase subagent orchestration in 232 is a clean illustration of the pattern

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 61.3 AIC · ⌖ 4.83 AIC · ⊞ 6.3K
Comment /matt to run again

try {
await access(hookPath, constants.F_OK);
const content = await readFile(hookPath, "utf8");
const isSample = content.includes("sample") || hookPath.endsWith(".sample");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/grill-with-docs] Dead branch: hookPath.endsWith(".sample") is always falsehookPath is built as .git/hooks/${hookName} and hookName is never a .sample-suffixed string.

💡 Fix

Remove the dead branch or adjust the logic to also list .sample files:

// Option A: drop the dead condition
const isSample = content.includes("sample");

// Option B: if you want to catch .git/hooks/pre-commit.sample files,
// pass them as hookName values and the check works naturally

As written the intent (skip .sample files) is silently lost.

description: "Parse a vitest coverage-summary.json file to extract per-file coverage metrics.",
parameters: { filePath: s.path },
handler: async ({ filePath }) => {
const raw = await readFile(filePath, "utf8");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/grill-with-docs] The tool reads the file but the agent passes the path via the prompt instruction (line 41) as the hard-coded string "coverage/coverage-summary.json" — the filePath parameter is effectively unused for path selection. If the coverage file is at a different location this pattern silently breaks.

💡 Fix

Have the agent pass the detected path to the tool, or remove the parameter and hard-code the path inside the tool:

// Option A: remove filePath parameter, embed the path
handler: async () => {
  const raw = await readFile("coverage/coverage-summary.json", "utf8");
  ...
}

// Option B (better): let the agent derive the path from p.readOptional and pass it
parameters: { filePath: s.path },
// and instruction says: call parseCoverageSummary with the file path shown above

model: "small",
instructions: p`Analyze TypeScript import depth across all source files.

Source files to analyze: ${p.glob("**/*.ts")}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/grill-with-docs] The p.glob("**/*.ts") prompt intent includes node_modules and generated files — the instruction comment says "excluding node_modules" but the glob has no exclusion, so the agent will be directed to analyze potentially thousands of files at runtime.

💡 Fix

Use a more targeted glob, consistent with how sample 232 tackles the same problem:

Source files to analyze: ${p.glob("src/**/*.ts")}

Or document that the agent is expected to filter in the instruction text, which is fragile since the file list itself is already resolved before the model sees it.

instructions: p`List TypeScript source files and their line counts.

Files found: ${p.glob("**/*.ts")}
Line counts: ${p.bash("wc -l $(find . -name '*.ts' -not -path '*/node_modules/*' -not -path '*/.git/*' | head -20) 2>/dev/null | tail -21")}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/grill-with-docs] The wc -l command uses shell word-splitting on the $(find ...) subshell — file paths with spaces will be split into multiple arguments causing wc to error on them. This is a shell injection risk in samples (readers may copy this pattern into production tools).

💡 Fix

Use xargs or a while read loop to handle paths safely, or replace with find ... -exec wc -l:

find . -name "*.ts" -not -path "*/node_modules/*" -not -path "*/.git/*" | head -20 | xargs wc -l 2>/dev/null | tail -21

const author = parts[1].trim();
const dateStr = parts[3].trim();
perAuthor[author] = (perAuthor[author] ?? 0) + 1;
const day = days[new Date(dateStr).getDay()];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/grill-with-docs] new Date(dateStr).getDay() returns NaN when dateStr is empty or malformed, so days[NaN] is undefined — the if (day) guard silently drops those commits from perDayOfWeek but still increments totalCommits, causing a mismatch.

💡 Fix

Validate dateStr before parsing, or guard on the date being valid:

const date = new Date(dateStr);
if (!isNaN(date.getTime())) {
  const day = days[date.getDay()];
  if (day) perDayOfWeek[day] = (perDayOfWeek[day] ?? 0) + 1;
}
totalCommits++;

The current guard on if (day) only prevents the undefined key insertion but does not prevent the totalCommits inflation.

description: "Parse an env file string and return the list of key names.",
parameters: { content: s.string },
handler: ({ content }) => {
return content

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/grill-with-docs] parseEnvKeys receives the file content as a string, but when p.readOptional returns nothing (file absent), the agent is instructed to pass that content to the tool — the content will be an empty string or the literal token (not available), which will result in ["(not", "available)"] being parsed as keys unless the agent handles it.

💡 Fix

Guard in the tool handler or document the expected contract:

handler: ({ content }) => {
  if (!content || content.startsWith("(not")) return [];
  return content.split("
")...
}

Otherwise readers copying this pattern may be surprised by phantom keys appearing in exampleKeys or presentKeys when files are missing.

parameters: { filePath: s.path },
handler: async ({ filePath }) => {
const content = await readFile(filePath, "utf8");
const exportMatches = content.match(/^export\s+(?:default\s+)?(?:const|function|class|type|interface|enum)\s+(\w+)/gm) ?? [];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/grill-with-docs] The match(/^export\s+.../gm) regex captures the full export ... line, then a second .match(/(\w+)\s*$/) extracts the last word. For export default function foo this correctly returns foo, but for export const myVar = the trailing = is not in the pattern so the last word captured is correctly myVar — but export type { Foo } (re-export braces syntax) and export * from patterns are silently missed.

💡 Suggestion

This is a sample so perfect correctness is not required, but it would improve the sample quality (and reader trust) to note the limitation in a comment:

// Note: only detects direct declaration exports; re-exports (`export { Foo }`, `export * from`)
// are not captured by this regex.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant