If you want to take your use of AI for software development to the next level, you could do worse than superpowers, a set of interrelated AI skills that bring some process and rigor into play.
I’ve been somewhat reluctant to post about the wave of AI tooling that’s changing the way we develop software, primarily because anything I say is likely to become obsolete within months, possibly weeks - things are moving that fast. That said, I keep finding in conversation that we’re all trying different things, and sharing what we’re doing can help everyone adapt.
Superpowers is a set of skills you can add to your AI that turn software development into a collaborative process. It feels wierd to have a conversation with my AI agent about the feature that we’re building, but there’s no denying that it’s effective.
Perhaps the best way to introduce you to Superpowers is to show it in action.
On the Azure Service Operator project we make extensive use of go-vcr to record/replay HTTP interactions, allowing us to rapidly and reproducably test resource reconciliation. This works well, but as our number of supported resources increases, we’re running into problems with test duration.
Enter go-vcr-tidy an experimental tool I’m writing that can reduce the size of a go-vcr recording by compressing common interaction patterns into their essential steps. For example, an Azure Long Running Operation involves polling an operation URL repeatedly until the operation completes - most of the intermediate polls can be elided without changing the behaviour of the client at all.
I used Superpowers to add a support for tidying a new kind of interaction - here’s the conversation, lightly edited for readability.
As you read this, note how Copilot takes my initial prompt and starts by researching the code to better understand my intent. Then it comes back with a series of clarifying questions, providing a set of reasonable responses for each - but those don’t limit me, I can give any response I want.
Once Superpowers was complete, I reviewed the implementation and the tests, verified that it worked as needed, and merged the new feature.
/brainstorming Add a new generic detector/monitor pair to handle the case where a client polls a known URL (receiving 404s), waiting for a resource to be created.
Explored codebase · Read 19 files · Created 8 todos
- Read detector, monitor, and test files across
internal/generic/,internal/analyzer/,internal/interaction/, andinternal/fake/ - Analyzed existing
DetectDeletion/MonitorDeletionpatterns
I’ve explored the codebase. The existing DetectDeletion/MonitorDeletion pair establishes a clear pattern: a detector watches for a trigger interaction and spawns a monitor that accumulates intermediate interactions, excluding the middle ones when a terminal condition is met.
For the “poll for creation” case, the mirror pattern would be:
- Sequence: GET→404, GET→404, GET→404, … GET→2xx
- Goal: Exclude the middle 404 GETs, keeping only the first and last
Here’s my first question:
What should trigger the detector to start monitoring?
In the deletion case, a successful DELETE is a clear, unambiguous trigger. For creation polling, the trigger is less obvious since a single GET returning 404 could just be a normal “not found” rather than the start of a polling loop.
Options:
- (A) Trigger on any GET that returns 404 — simple, mirrors the deletion pattern, and lets the monitor sort out whether it’s actual polling (if only one 404 before a 2xx, nothing gets excluded anyway)
- (B) Require a preceding PUT/POST before triggering on GET 404 — more targeted but adds coupling and would miss cases where the creation happens outside the recorded sequence
- (C) Only trigger after seeing two consecutive GET 404s to the same URL — reduces false monitor spawning but adds complexity
I’d recommend (A) — it’s the simplest, consistent with the existing deletion pattern, and has no downside: if a spawned monitor only sees one 404 before a success (or abandons), nothing gets excluded and there’s no harm.
(A) It’s consistent with the way other monitors have been written.
Good, (A) it is — trigger on any GET returning 404, consistent with existing patterns.
Next question:
What should cause the monitor to abandon tracking (besides the happy path of GET→2xx)?
In the deletion monitor, it abandons when it sees a POST/PUT/DELETE to the monitored URL, or an unexpected status code (e.g. 500, 301). For the creation polling monitor, the analogous options for abandonment are:
- (A) Abandon on any non-GET method to the URL (POST, PUT, DELETE, PATCH), or a GET returning something other than 404 or 2xx (e.g. 500, 301) — mirrors the deletion monitor’s logic exactly
- (B) Same as (A), but also abandon on DELETE specifically with a different log message (since deleting a resource you’re waiting to be created is contradictory)
I’d recommend (A) — keep it simple. The deletion monitor doesn’t differentiate between different abandonment causes in its behavior (all produce Finished()), and we should follow suit. The debug log messages can mention the specific method/status that caused abandonment, as the deletion monitor already does.
Agreed. A.
Good. Next question:
When the monitor sees the terminal GET→2xx (resource created), how should it decide which interactions to exclude?
The deletion monitor keeps the first and last accumulated interactions and excludes the middle ones. For creation polling, the accumulated interactions are the 404 GETs. Options:
- (A) Keep first and last 404 GET, exclude all middle 404 GETs — mirrors the deletion monitor exactly. Minimum 3 accumulated 404s before anything gets excluded.
- (B) Keep only the first 404 GET, exclude all others — the last 404 before the 2xx success doesn’t add information since the success itself shows the transition. Minimum 2 accumulated 404s before anything gets excluded.
- (C) Keep only the last 404 GET, exclude all earlier ones — shows the state just before creation.
I’d recommend (A) — it’s consistent with the deletion monitor’s approach, and keeping both the first and last 404 preserves the visible polling window (you can see when polling started and when it was about to succeed).
A. The timestamps of the first and last 404 give context on timing.
Good reasoning on the timestamps. Last question:
Naming — what should the types be called?
Following the existing DetectDeletion/MonitorDeletion convention:
- (A)
DetectCreation/MonitorCreation— concise, mirrors the deletion pair - (B)
DetectCreationPolling/MonitorCreationPolling— more descriptive about what’s actually happening (polling for creation) - (C)
Detect404Polling/Monitor404Polling— describes the mechanism rather than the intent
I’d recommend (A) — it’s consistent with the existing naming convention (DetectDeletion/MonitorDeletion) and the intent (detecting resource creation) is clearer than the mechanism. The filenames would be detect_creation.go and monitor_creation.go.
The context here is when we’ve waiting for some other process to create the resource - so I’d suggest DetectDeferredCreation and MonitorDeferredCreation
Good call — “deferred” captures the intent precisely: the creation is happening elsewhere and we’re just waiting for it to appear. DetectDeferredCreation / MonitorDeferredCreation with files detect_deferred_creation.go and monitor_deferred_creation.go.
That covers all my clarifying questions. I have a clear picture now, so let me propose the approaches.
Approach 1 (Recommended): Direct mirror of the deletion pair
Two new types in generic, following the deletion pattern exactly:
DetectDeferredCreation— triggers on any GET returning 404, spawns aMonitorDeferredCreationfor that URLMonitorDeferredCreation— accumulates 404 GETs; on GET→2xx, excludes all but first and last 404; abandons on non-GET methods or unexpected status codes
Trade-offs: Simple, consistent, well-understood pattern. No new abstractions needed.
Approach 2: Parameterized generic polling detector/monitor
A single configurable pair (e.g. DetectPolling/MonitorPolling) that takes the trigger condition, accumulation condition, and terminal condition as parameters. The deletion and creation cases would both be instances of this.
Trade-offs: More abstract, reduces duplication between creation and deletion, but adds complexity that isn’t yet justified by the number of variants. Could be refactored to later if a third pattern emerges.
Approach 3: Shared base with embedded structs
Extract common logic (URL matching, interaction accumulation, exclusion calculation) into a base struct that both deletion and creation monitors embed.
Trade-offs: Reduces some code duplication but Go embedding can be awkward, and the actual shared logic is small (a few lines of URL comparison and slice operations).
I recommend Approach 1. The deletion pair is ~50 lines per file — the duplication is minimal and the code is straightforward. Premature abstraction would make both pairs harder to understand. If a third pattern emerges later, that’s the right time to refactor.
Does Approach 1 work for you?
yes, option 1
Here’s the design. I’ll present it section by section.
DetectDeferredCreation
File: internal/generic/detect_deferred_creation.go
A stateless detector that watches every interaction for a GET returning 404. When found, it spawns a MonitorDeferredCreation for that URL.
- Implements
analyzer.Interface - Never finishes (runs for the entire analysis lifetime, like
DetectDeletion) - Ignores all interactions that aren’t GET→404
- On GET→404: logs at Debug level, spawns
MonitorDeferredCreation(baseURL), and passes the triggering interaction so the monitor can include it in its accumulation
One difference from the deletion detector: the triggering interaction (the first 404 GET) is itself part of the sequence the monitor needs to track. The detector should pass it to the monitor’s constructor so the monitor starts with it already accumulated.
Does this section look right?
Yes.
MonitorDeferredCreation
File: internal/generic/monitor_deferred_creation.go
A stateful monitor that tracks a specific URL after a GET→404 is detected. It accumulates 404 GET responses and waits for either a successful GET (2xx) or an abandonment condition.
Constructor: NewMonitorDeferredCreation(baseURL *url.URL, firstInteraction interaction.Interface) — starts with the triggering 404 GET already in the accumulator.
State: baseURL *url.URL, interactions []interaction.Interface (seeded with the first 404).
Behavior on Analyze():
| Condition | Action |
|---|---|
| Different URL | Ignore (return empty result) |
| GET → 404 | Accumulate the interaction |
| GET → 2xx | Creation confirmed — finish with exclusions (see below) |
| POST, PUT, DELETE, PATCH to URL | Abandon — Finished() with no exclusions |
| GET → other status (500, 301, etc.) | Abandon — Finished() with no exclusions |
Exclusion logic (on GET→2xx):
- If fewer than 3 accumulated 404 GETs: finish with no exclusions (nothing worth removing)
- If 3+ accumulated: exclude
interactions[1 : len-1](keep first and last 404, remove all middle ones)
This mirrors MonitorDeletion.deletionConfirmed() exactly.
Does this section look right?
Minor change - no need to pass both baseURL and firstInteraction, as the base URL can be retrieved from that interaction.
Good catch. Constructor simplifies to NewMonitorDeferredCreation(firstInteraction interaction.Interface) — it extracts baseURL from firstInteraction.Request().BaseURL() internally.
Testing
Files: detect_deferred_creation_test.go and monitor_deferred_creation_test.go in generic
Tests follow the same patterns as the deletion pair, using the existing runAnalyzer helper from helpers_test.go and fakes from fake.
Detector tests:
- GET→404 spawns a
MonitorDeferredCreation - Various 4xx codes other than 404 do not spawn
- Non-GET methods returning 404 do not spawn
- Successful GETs (2xx) do not spawn
- Multiple 404 GETs to different URLs spawn independent monitors
- Detector never finishes
Monitor tests:
- Single 404 then 2xx → finishes, no exclusions (only 1 accumulated)
- Two 404s then 2xx → finishes, no exclusions (only 2 accumulated)
- Three 404s then 2xx → finishes, middle one excluded
- Many 404s then 2xx → all middle excluded
- Different URL → ignored
- POST/PUT/DELETE/PATCH to URL → abandons
- GET returning 500/301 → abandons
- Various 2xx status codes accepted as creation confirmation
- URL with query parameters matches base URL
Does this section look right?
Yes.
Wrote design spec · Ran automated spec review · Committed to git
- Created spec document
2026-03-15-deferred-creation-polling-design.md - Committed design spec to git
- Spawned spec review subagent — reviewed spec against codebase
- Review passed with advisory notes only (no blocking issues)
- Verified PATCH handling is consistent with existing
MonitorDeletionbehavior
That covers the full design. To summarize:
New generic detector/monitor pair for deferred creation polling:
DetectDeferredCreation— stateless detector, triggers on GET→404, spawns monitorMonitorDeferredCreation— stateful monitor, constructor takesfirstInteraction(derives baseURL from it), accumulates 404 GETs, finishes with exclusions on GET→2xx (keeps first and last 404, removes middle), abandons on non-GET methods or unexpected status codes- Tests mirror the deletion pair’s structure
- Four new files in
generic
Design approved. Spec written and committed. The reviewer approved it with advisory notes only (no blocking issues). Please review it and let me know if you want to make any changes before we start writing out the implementation plan.
Looks good. Proceed.
Created implementation plan · Ran automated plan review · Committed to git
- Read writing-plans skill for plan structure guidance
- Read existing source code to write exact code in the plan
- Created implementation plan
2026-03-15-deferred-creation-polling.md - Spawned plan review subagent — verified plan against spec and codebase
- Plan approved with no issues
- Committed plan to git
Plan complete and saved. Ready to execute?
yes
Test-driven implementation · 4 new files · 1 modified · All tests pass, lint clean
- Created
detect_deferred_creation_test.go— wrote detector tests first - Created
detect_deferred_creation.go+ stub monitor — ran tests, all pass - Created
monitor_deferred_creation_test.go— wrote monitor tests - Implemented full
monitor_deferred_creation.go— ran tests, all pass - Ran full test suite — all existing and new tests pass
- Ran linter — found 3 issues (test duplication warnings +
intrange) - Fixed lint issues: added
nolint:duplannotations, usedrangesyntax - Added
nolint:duplto existingdetect_deletion_test.gofor cross-file duplication - Final run: all tests pass, lint clean
- Committed to branch
feature/404-polling
Implementation complete. Here’s a summary:
New files created:
detect_deferred_creation.go— stateless detector, triggers on GET→404, spawns monitordetect_deferred_creation_test.go— 6 test functions covering spawn/no-spawn/never-finishesmonitor_deferred_creation.go— stateful monitor, accumulates 404s, excludes middle ones on GET→2xxmonitor_deferred_creation_test.go— 10 test functions covering exclusion thresholds, abandonment, URL matching
Modified:
detect_deletion_test.go— addednolint:duplto suppress cross-file duplication warning
All tests pass, lint is clean. The work is on branch feature/404-polling with 3 commits (spec, plan, implementation).
Comments
blog comments powered by Disqus