Skip to content

[rig-tasks] Add 10 rig samples — 2026-08-16 - #434

Merged
pelikhan merged 1 commit into
mainfrom
rig-tasks/2026-08-16-7b75611fbaae6b4c
Aug 16, 2026
Merged

[rig-tasks] Add 10 rig samples — 2026-08-16#434
pelikhan merged 1 commit into
mainfrom
rig-tasks/2026-08-16-7b75611fbaae6b4c

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Summary

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

# File Description Typecheck
1 421-html-anchor-extractor.md Extract and classify anchor links from HTML files pass
2 422-ts-optional-chaining-counter.md Count ?. and ?? operators across TypeScript files pass
3 423-git-file-size-tracker.md Track file byte-size changes between HEAD~1 and HEAD pass
4 424-json-pretty-printer.md Pretty-print a JSON file and report structural statistics pass
5 425-ts-interface-method-counter.md Count method signatures in TypeScript interfaces pass
6 426-git-tag-annotation-extractor.md Classify git tags as annotated/lightweight/signed pass
7 427-ts-wildcard-reexport-detector.md Detect export * from wildcard re-export patterns pass
8 428-markdown-link-classifier.md Classify all links in markdown files pass
9 429-package-json-field-auditor.md Audit package.json for standard field presence pass
10 430-parallel-git-stats-workflow.md Parallel workflow: commit stats + file stats via Promise.all pass

Typecheck failures

No failures this run. All 10/10 samples passed typecheck.

Task 10 required two fixes during authoring:

  1. call must come from body: async ({ call }) => {} parameter, not import { call } from "rig".
  2. WorkflowMeta requires both name and description fields.

Tasks run

  • (reused) HTML anchor link extractor
  • (reused) TypeScript optional chaining counter
  • (reused) Git file size change tracker
  • (reused) JSON pretty-printer stats reporter
  • (reused) TypeScript interface method counter
  • (reused) Git tag annotation extractor
  • (new) TypeScript wildcard re-export detector
  • (new) Markdown link classifier
  • (new) package.json field presence auditor
  • (new) Parallel git stats workflow

Generated by Daily Rig Task Generator · sonnet46 148.7 AIC · ⌖ 9.36 AIC · ⊞ 6.8K ·

- 421: html-anchor-extractor
- 422: ts-optional-chaining-counter
- 423: git-file-size-tracker
- 424: json-pretty-printer
- 425: ts-interface-method-counter
- 426: git-tag-annotation-extractor
- 427: ts-wildcard-reexport-detector
- 428: markdown-link-classifier
- 429: package-json-field-auditor
- 430: parallel-git-stats-workflow

All 10/10 typecheck pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review August 16, 2026 13:27
@pelikhan
pelikhan merged commit 3efccab into main Aug 16, 2026
2 checks passed
@github-actions

github-actions Bot commented Aug 16, 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 bugs found in tool implementations.

📋 Key Themes & Highlights

Key Themes

  • Correctness bug (426): Tagger date regex never matches — git stores timestamps as Unix epoch, not ISO dates. date always returns "".
  • Schema mismatch (430): call.json output schema uses s.record(s.int) but the sub-agents return { authors: Record<string,number>, totalCommits: number } — the schema needs to mirror the actual objects.
  • Shell injection (423, 426): LLM-controlled filePath/tagName interpolated directly into execSync strings. Use spawnSync with an args array instead.
  • Regex fragility (425): Interface body regex [^}]* silently drops methods from interfaces with nested generic types.

Positive Highlights

  • ✅ Solid variety: HTML, TypeScript, git, JSON, markdown, and workflow patterns
  • ✅ Sample 430 cleanly demonstrates the Promise.all parallel call() pattern — good canonical reference
  • ✅ Consistent addon usage (repair() / steering()) across all samples
  • ✅ All 10 samples passed typecheck

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

const body = execSync(`git cat-file tag "refs/tags/${tagName}" 2>/dev/null || echo ""`, { encoding: "utf-8" });
if (/BEGIN PGP/.test(body)) return { type: "signed" as const, subject: "", date: "" };
const subjectMatch = body.match(/^subject (.+)$/m);
const dateMatch = body.match(/^tagger .+ (\d{4}-\d{2}-\d{2})/m);

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 tagger date regex will never match — git stores tagger timestamps as Unix epoch (1697000000 +0000), not YYYY-MM-DD. dateMatch always returns null, so date is always "" for every annotated tag.

💡 Fix

Parse the epoch integer and convert it:

const dateMatch = body.match(/^tagger .+ (\d{10,})/m);
const date = dateMatch ? new Date(parseInt(dateMatch[1], 10) * 1000).toISOString().slice(0, 10) : "";

topExtension: ${topExtension ?? ""}
overallHealth: ${health}`,
s.object({
authorStats: s.record(s.int),

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] Schema mismatch in call.json output: s.record(s.int) on line 68 expects a flat Record<string, number> but authorStats is { authors: Record<string, number>, totalCommits: number }. The LLM is being asked to write a value it has structured data for, but the schema tells it to discard the structure.

💡 Fix

Use schemas that match the actual agent outputs:

authorStats: s.object({ authors: s.record(s.int), totalCommits: s.int }),
fileStats:   s.object({ extensions: s.record(s.int), totalFiles: s.int }),

description: "Get the byte size of a file at a specific git revision using git cat-file.",
parameters: s.object({ revision: s.string, filePath: s.string }),
handler({ revision, filePath }: { revision: string; filePath: string }) {
try {

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] Shell injection risk: revision and filePath are interpolated directly into a shell command with execSync. If the agent passes paths containing spaces, quotes, or ;, the command will misbehave or execute unintended commands.

💡 Fix

Use spawnSync to pass arguments as an array, bypassing the shell entirely:

import { spawnSync } from "node:child_process";

const result = spawnSync("git", ["cat-file", "-s", `${revision}:${filePath}`], { encoding: "utf-8" });
const size = parseInt(result.stdout?.trim() ?? "0", 10);
return { size: isNaN(size) ? 0 : size };

parameters: s.object({ tagName: s.string }),
handler({ tagName }: { tagName: string }) {
try {
const objType = execSync(`git cat-file -t "refs/tags/${tagName}" 2>/dev/null || echo lightweight`, { encoding: "utf-8" }).trim();

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] Same shell injection pattern as 423: tagName is interpolated into execSync shell commands. A tag named foo```; rm -rf .git would be passed directly to the shell.

💡 Fix

Use spawnSync for both calls:

import { spawnSync } from "node:child_process";

const typeResult = spawnSync("git", ["cat-file", "-t", `refs/tags/${tagName}`], { encoding: "utf-8" });
const objType = typeResult.status === 0 ? typeResult.stdout.trim() : "lightweight";

while ((m = ifaceRe.exec(content)) !== null) {
const name = m[1];
const body = m[2];
const methods = (body.match(/\w+\??\s*\([^)]*\)/g) ?? []);

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 regex /interface\s+(\w+)[^\{]*\{([^}]*)\}/gs won't match interfaces whose bodies contain nested braces (e.g. { key: Record<string, { a: string }> }). The greedy [^}]* stops at the first }, producing an empty or partial body.

💡 Fix

For a sample, acknowledging the limitation in a comment is fine. If correctness matters, consider a brace-counting approach:

// Simple depth-aware body extraction
function extractInterfaceBody(src: string, start: number): string {
  let depth = 0, i = start;
  while (i < src.length) {
    if (src[i] === '{') { depth++; }
    else if (src[i] === '}') { if (--depth === 0) return src.slice(start + 1, i); }
    i++;
  }
  return "";
}

Or note the limitation with a comment so readers understand the scope.

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