Skip to content

[rig-tasks] Add 10 rig samples — 2026-08-11 - #404

Merged
pelikhan merged 1 commit into
mainfrom
rig-tasks/2026-08-11-b2c63f8c5818c15e
Aug 11, 2026
Merged

[rig-tasks] Add 10 rig samples — 2026-08-11#404
pelikhan merged 1 commit into
mainfrom
rig-tasks/2026-08-11-b2c63f8c5818c15e

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Summary

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

# File Description Typecheck
1 401-git-file-at-revision.md Extract file content at a git revision with commit metadata pass
2 402-json-schema-structure-validator.md Validate JSON data against a schema checking required fields and types pass
3 403-markdown-frontmatter-extractor.md Parse YAML frontmatter from all markdown files in the workspace pass
4 404-git-diff-word-frequency.md Count added/deleted words in the current git word-diff pass
5 405-ts-async-function-finder.md Find all async function signatures in TypeScript source files pass
6 406-npm-dep-depth-analyzer.md Classify npm dependencies by depth (direct / transitive) pass
7 407-http-access-log-stats.md Parse HTTP access log and report status counts and top paths pass
8 408-ts-spread-usage-counter.md Count object/array spread patterns across TypeScript source files pass
9 409-git-hook-file-scanner.md Analyze .git/hooks files for shebang, executability, and hook type pass
10 410-merge-strategy-selector.md Workflow: recommend a merge strategy from diff and conflict analysis pass

Typecheck failures

None — all 10 tasks passed typecheck. Task 10 required one fix: the initial workflow({ agents: {...} }) pattern is not valid in the current rig API. Fixed by closing over agents as variables and using sequential call() invocations with type casts instead of parallel([]) (which loses heterogeneous return types).

Tasks run

  • (reused) Git file at revision extractor
  • (reused) JSON schema structure validator
  • (reused) Markdown frontmatter extractor
  • (reused) Git diff word frequency counter
  • (reused) TypeScript async function finder
  • (reused) NPM dependency depth analyzer
  • (new) HTTP access log stats
  • (new) TypeScript spread usage counter
  • (new) Git hook file scanner
  • (new) Merge strategy selector workflow

Generated by Daily Rig Task Generator · sonnet46 129.6 AIC · ⌖ 10.2 AIC · ⊞ 6.8K ·

Samples cover: git-file-at-revision, json-schema-structure-validator,
markdown-frontmatter-extractor, git-diff-word-frequency,
ts-async-function-finder, npm-dep-depth-analyzer, http-access-log-stats,
ts-spread-usage-counter, git-hook-file-scanner, merge-strategy-selector.

All 10/10 typecheck passed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pelikhan
pelikhan marked this pull request as ready for review August 11, 2026 15:30
@pelikhan
pelikhan merged commit 425e116 into main Aug 11, 2026
1 check passed
@github-actions

github-actions Bot commented Aug 11, 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 /codebase-design — requesting changes on correctness and security issues in the tool handlers.

📋 Key Themes & Highlights

Key Findings

  • Shell injection (401): revision and filePath are interpolated unsanitised into execSync strings — use spawnSync with an argv array instead (two call sites).
  • maxDepth off-by-one (406): The depth tracking update happens before recursion, so maxDepth is always one less than the true value.
  • Per-line tool calls (407): Calling parseLogLine once per log line will exceed maxTurns on any real log file. The tool should accept the full log content.
  • undefined vs absent (402): Early-return paths set schemaTitle: undefined, which serialises inconsistently — use null or omit the key.
  • Regex correctness (403, 405, 408): Multiple regex patterns have edge-case bugs (frontmatter delimiter anchoring, async method coverage, nested object spread counting).
  • Single-commit edge case (410): HEAD~1 reference fails on repos with one commit.

Positive Highlights

  • ✅ Good variety of patterns across the 10 samples (tools, prompt intents, workflow, steering/repair addons)
  • ✅ Consistent use of s.path, s.int, s.enum over bare s.string where appropriate
  • ✅ Sample 410 correctly avoids the invalid workflow({ agents }) pattern and uses sequential call() invocations

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

parameters: s.object({ revision: s.string, filePath: s.path }),
handler: async ({ revision, filePath }: { revision: string; filePath: string }) => {
const { execSync } = await import("node:child_process");
const fileContent = execSync(`git show ${revision}:${filePath} 2>/dev/null || echo ""`, { encoding: "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.

[/codebase-design] Shell injection risk: revision and filePath are interpolated directly into execSync command strings without sanitisation — a caller-supplied revision like $(rm -rf .) would execute arbitrary commands.

💡 Suggested fix

Use spawnSync with an explicit argv array to avoid shell interpolation:

import { spawnSync } from "node:child_process";
const result = spawnSync("git", ["show", `${revision}:${filePath}`], { encoding: "utf8" });
const fileContent = result.stdout ?? "";

This is the correct pattern whenever tool parameters flow into shell commands.

fileContent,
commitHash: spaceIdx > -1 ? logLine.slice(0, spaceIdx) : logLine,
commitMessage: spaceIdx > -1 ? logLine.slice(spaceIdx + 1) : "",
linesCount: fileContent.split("\n").length,

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.

[/codebase-design] The same shell injection concern applies to git logrevision and filePath are still interpolated unquoted. Consistently use spawnSync for both calls, as suggested on line 11.

addons: [repair()],
});

export default jsonSchemaStructureValidator;

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.

[/codebase-design] schemaTitle: undefined in early-return paths conflicts with the output schema s.optional(s.string) which expects the field to be absent (or null), not undefined. Return null or omit the key to match the schema contract — some JSON serialisers will silently drop undefined, others may fail validation.

💡 Example
return { valid: false, errors: ["Invalid JSON in schema file"], checkedFields: 0, schemaTitle: null };

Or change the output schema to s.optional(s.string) accepting null explicitly, if supported.

tags = tagsMatch[1].split(/[\n,]/).map((t: string) => t.replace(/^\s*-\s*/, "").trim()).filter(Boolean);
}
return {
hasFrontmatter: true,

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.

[/codebase-design] The frontmatter regex /^--- ? ([\s\S]*?) ? ---/ doesn't require the closing --- to be at the start of a line (^), so it could match a --- in the middle of a line. Add the m flag and anchor the closing delimiter:

const match = content.match(/^---
?
([\s\S]*?)
?
^---/m);

Otherwise a document with --- foo --- in its body could produce a false frontmatter match.

});

// Agent role: Parse an HTTP access log file and return status count statistics.
const httpAccessLogStats = agent({

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.

[/codebase-design] The agent is asked to call parseLogLine once per log line, which could mean thousands of tool calls for a real access log. This will exceed maxTurns (default 10) and produce incomplete results without any guidance.

💡 Suggested fix

Either:

  1. Have the tool accept the full log content and loop internally (preferred — fewer turns, no token overhead per line), or
  2. Set maxTurns to a sensible bound and document the expected log size limit.

const depthClass: "direct" | "transitive-shallow" | "transitive-deep" =
depth === 1 ? "direct" : depth === 2 ? "transitive-shallow" : "transitive-deep";
if (!packages[name]) {
packages[name] = { depth, depthClass };

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.

[/codebase-design] maxDepth is updated with if (depth > maxDepth) maxDepth = depth before recursing, so it always lags one level behind. Move the update after the recursive call, or simply Math.max at each level:

walk(child, depth + 1);
if (depth > maxDepth) maxDepth = depth;

As written, maxDepth will always equal one less than the true maximum depth.

if (name) matches.push(name);
}
return { functions: matches };
},

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.

[/codebase-design] The regex /const\s+(\w+)\s*=\s*async\s*(?:\([^)]*\)|[^=]+)\s*=>/g is brittle for multiline arrow functions and will silently miss async methods (async methodName()) in classes. Since this is a sample, the limitation should at minimum be documented in a comment so readers don't copy it expecting complete coverage.

totalFiles: s.int,
dominantArea: s.enum("src", "test", "config", "docs", "mixed"),
}),
});

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.

[/codebase-design] branchDiffAgent uses git diff --stat HEAD~1..HEAD which will fail on a repository with a single commit (no HEAD~1). The || git diff --stat HEAD fallback still won't produce stats since HEAD with no parent means an empty diff. Consider git diff --stat $(git rev-parse --verify HEAD~1 2>/dev/null || git hash-object -t tree /dev/null) HEAD or document this limitation.

},
});

// Agent role: Count TypeScript object spread and array spread patterns across source files.

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.

[/codebase-design] The object-spread regex /\{[^}]*\.\.\./g counts characters between { and ... but [^}]* is greedy and stops at the first }, so spread patterns inside nested objects (e.g. { a: { ...x }, b: 1 }) will match on the outer { and the wrong .... Consider a simpler /\.\.\.[a-zA-Z_$]/g count as a more robust proxy for spread occurrences in the file, noting the inherent approximation.

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