API review: duplicate surface and simplification proposals - #295
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
@copilot review samples in the repository, fix compilation issues, adapt them to the new APIs, and assess the changes. |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Audited all 58 TS samples and 331 markdown samples (a9dd129). No compilation issues: Running the full sample suite did surface nine genuinely broken samples, now fixed:
Remaining suite failures (192) are all the ≤30-line budget in Added §6 "Sample audit" to |
|
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅ |
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /codebase-design and /improve-codebase-architecture — approving with minor suggestions.
📋 Key Themes & Highlights
Positive Highlights
- ✅ Dead code removed cleanly.
inputShape/outputShapehad zero repository references; the deletion is surgical and correctly leaves no sample migration. - ✅ Claude compatibility rigorously checked. The compatibility checklist (§5) is thorough and shows each proposal is safe to proceed with.
- ✅ Sequencing is well-reasoned. Additive consolidation before deletion keeps every intermediate commit green — exactly the right way to handle a 110-callsite migration.
- ✅ Nine samples repaired correctly. The
p.env()pattern for removing root-agentinputis consistent and idiomatic. - ✅ AGENTS.md updated to remove the stale shape-descriptor note — keeps the project documentation honest.
Suggestions (non-blocking)
- Intentional parity duplicates should also be documented in
references/claude-workflow-conversion.md(not only in the new review doc) — see inline comment on line 75. - Sample 99 (
99-bash-each.md) now primarily demonstrates delegation, notp.bashEach— consider a comment or rename to avoid confusion. - Sample 182 uses a hardcoded path that won't exist in most repos —
p.env("TEMPLATE_PATH", "docs/commit-template.md")would be more consistent with the other fixes. - Type signature sketch for
p.input/p.outputwould de-risk the next additive-consolidation PR before 110 call sites are migrated. references/linting.mdupdate for the proposedprefer-s-intrule could be done now to keep the lint reference current even before enforcement.
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 76.1 AIC · ⌖ 4.81 AIC · ⊞ 6.3K
Comment /matt to run again
| three operations; the extra names exist purely to vary *where the operand comes | ||
| from* (literal, single vs. many, input field, output field): | ||
|
|
||
| | Operation | Literal | Many | From input field | Optional/fallback | |
| three operations; the extra names exist purely to vary *where the operand comes | ||
| from* (literal, single vs. many, input field, output field): | ||
|
|
||
| | Operation | Literal | Many | From input field | Optional/fallback | |
There was a problem hiding this comment.
[/codebase-design] Section 2 recommends documenting intentional parity duplicates in references/claude-workflow-conversion.md, but this PR only notes the recommendation in the new review doc — the actual reference update is missing.
💡 Suggested addition to skills/rig/references/claude-workflow-conversion.md
Adding a short "Intentional parity duplicates" section to that file now locks in the decision and prevents the next reviewer from re-examining the same four pairs:
## Intentional parity duplicates
These pairs look redundant but must not be removed:
| Pair | Reason |
|------|--------|
| `context.{parallel,pipeline,until,phase,log}` + module-level | Claude sandbox globals |
| `call.text`/`call.json` + `agent()` | inline-agent 1:1 image |
| `CallOptions.model`/`maxTurns` overrides | per-call override semantics |
| `budget.total/spent()/remaining()` | direct Claude primitive parity || model: "small", | ||
| agents: { endpointProbe }, | ||
| instructions: p`Delegate to endpointProbe with endpoints ["https://example.com", "https://example.org"], then return its result unchanged.`, | ||
| output: ProbeResult, |
There was a problem hiding this comment.
[/codebase-design] Sample 99 is supposed to demonstrate p.bashEach, but the root healthProbe agent no longer calls it — it delegates to endpointProbe with hardcoded URLs. The sample still keeps p.bashEach in the child agent, but the root-level comment ("supply the endpoint list and delegate") now makes the sample illustrate delegation rather than its stated bash-each pattern.
💡 Consider
Either retitle to 99-delegation.md (since the primary demonstration is now delegation) or add a comment noting that endpointProbe carries the actual p.bashEach usage while the root agent satisfies the "no-input root" constraint. Without this clarification, readers browsing by filename will be confused by the root agent doing nothing but delegation.
| tools: [parseGitLogLine], | ||
| input: s.object({ templatePath: s.path, outputPath: s.path }), | ||
| instructions: p`Read the template at the input templatePath using ${p.readInput("templatePath")}. Gather recent commit metadata: ${p.bash("git log --format='%H|%an|%ae|%ai|%s' -10 2>/dev/null || echo ''")} and current branch: ${p.bash("git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown'")}. Use parseGitLogLine to parse each log line. Replace {{commit}}, {{author}}, {{branch}}, {{date}}, {{message}} placeholders in the template with actual values. Write the rendered content to the path from input.outputPath using ${p.writeInput("outputPath", "renderedContent")}. Return which placeholders were replaced.`, | ||
| instructions: p`Read the template using ${p.read("docs/commit-template.md")}. Gather recent commit metadata: ${p.bash("git log --format='%H|%an|%ae|%ai|%s' -10 2>/dev/null || echo ''")} and current branch: ${p.bash("git rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown'")}. Use parseGitLogLine to parse each log line. Replace {{commit}}, {{author}}, {{branch}}, {{date}}, {{message}} placeholders in the template with actual values. Write the rendered content using ${p.writeOutput("renderedContent", "docs/commit-rendered.md")}. Return which placeholders were replaced.`, |
There was a problem hiding this comment.
[/codebase-design] Sample 182 was fixed by removing the input field, but the new hardcoded path docs/commit-template.md is unlikely to exist in most repos where someone runs this sample. The original design (reading path from input) was correct for a template renderer; the fix trades a launcher constraint for a silent runtime failure.
💡 Alternative fix
Use p.env("TEMPLATE_PATH", "docs/commit-template.md") as the source, consistent with how 172-service-health-probe.md was fixed in this same PR (p.env("HEALTH_CHECK_URLS", ...)). This keeps the sample runnable without a matching repo layout and is consistent with the pattern established by the other sample fixes here.
instructions: p`Read the template using ${p.read(p.env("TEMPLATE_PATH", "docs/commit-template.md"))}...`|
|
||
| **Proposal:** drop `p.json` and document that objects interpolate as | ||
| pretty-printed JSON. 10 references to migrate. | ||
|
|
There was a problem hiding this comment.
[/improve-codebase-architecture] Section 3.3 proposes p.input(field) as a first-class reference value to replace stringly-typed p.inputField(field) — good direction. But the doc doesn't address type safety: p.inputField returns string, so p.read(p.inputField("path")) at least gives string to p.read. If p.input(field) returns an opaque InputRef object, every p.* signature that accepts it will need an overload. Consider sketching the minimal type signature in this doc to de-risk the "additive consolidation" next PR.
💡 Suggested sketch
// Minimal type contract to validate before implementation
type InputRef = { __kind: "input"; field: string };
type OutputRef = { __kind: "output"; field: string };
type PathLike = string | string[] | InputRef;
type ContentLike = string | OutputRef;
function read(source: PathLike, opts?: { optional?: boolean; fallback?: string }): PromptIntent;
function write(target: PathLike, content: ContentLike): PromptIntent;
function bash(cmd: string, opts?: { each?: InputRef }): PromptIntent;Writing this now catches whether p.read(p.input("files")) needs the array case to allow InputRef (yes it does) before 110 call sites are migrated.
| - `p.input(field)` — deferred reference to an input field (replaces | ||
| `p.inputField`, and becomes a real value rather than a magic string). | ||
| - `p.output(field)` — deferred reference to an output field. | ||
| - `p.read(source, options?)` where `source` is a path, an array of paths, or a |
There was a problem hiding this comment.
[/improve-codebase-architecture] s.integer removal (§3.2) is proposed but not acted on in this PR — that's the correct sequencing. However, the proposal says to add a lint rule prefer-s-int, while skills/rig/references/linting.md already documents the linting reference. It's worth confirming whether the lint reference should be updated now (even without the enforcement PR) so the rule exists as a documented decision. Skipping that update means the next PR will need to both add the rule and update the reference, making the commit less atomic.
Reviews the public
rigAPI surface after the addition of Claude background/dynamic workflow support, looking for duplicate APIs and proposing simplifications. Claude compatibility is treated as a hard constraint, so every finding is classified as either intentional parity duplication (keep) or accidental duplication (removable), with a per-proposal compatibility verdict. Samples are deliberately left untouched.docs/rig-api-review.md(new)s.*helpers, 17p.*helpers, 9PromptBuildermethods, the workflow layer, four engine entry points.phase/log/parallel/pipeline/until,call.text/call.jsonalongside declared agents, per-callmodel/maxTurnsoverrides,budget. Removing any of these breaks mechanical porting of.claude/workflows/*.workflow.js.inputShape/outputShape;s.integer(336s.intuses vs. 11); the 11-intentp.*matrix;PromptBuilderpass-throughs incl. the undocumentedfile()alias forp.write; the no-opp.json; thetimeout()addon (duplicatesCallOptions.timeout);AgentFn.use()(duplicatesAgentSpec.addons).s.*constraint presets, four engine-selection mechanisms, publicdebug().The largest finding is the
p.*intent matrix: eleven intents encode three operations, varying only in where the operand comes from. Promoting deferred references to first-class values collapses them:PromptIntent.modeis unchanged, so this is a front-door consolidation with no runtime-contract change. Claude impact is nil — dynamic workflows build prompts as plain strings.Code changes
skills/rig/rig.ts— removed theAgentFn.inputShape/outputShapealiases. They duplicateinputSchema/outputSchema(andspec.input/spec.output) and have zero references repo-wide, making this the only proposal with no sample impact.AGENTS.md— dropped the stale "Shape descriptors … promoted viaSchemaLike" note; that API no longer exists.