sweep-labs
Find orphaned connect-labs workflows, pipelines, synthetic data, and solicitations and clean them up. Needs a live-set from sweep-live-set.
SKILL.mdskills/sweep-labs/SKILL.md
GitHubsweep-labs
Find connect-labs artifacts (workflows, pipelines, synthetic opportunities, solicitations, funds, reviews, responses) that no current opp references. Workflows, pipelines, synthetic opps, and solicitations have first-class delete/disable atoms in the labs MCP — deletable in the execute pass, after the orchestrator's per-system human-confirmation gate (see agents/sweep.md § Human-confirmation gate). The remaining LabsRecord-backed types (funds + standalone reviews/responses) are report-only by design until per-type atoms exist upstream. Reviews and responses cascade-delete with their parent solicitation, so they generally don't need standalone cleanup.
Inputs
- Live-set file path from
sweep-live-set. LABS_MCP_TOKENand labs base URL (loaded viaconnect-labsMCP).- Labs admin base URL:
https://labs.connect.dimagi.com. mode—recommend(default) |execute. Inrecommendthe skill is report-only: diff/score/render + return the recommended-action list; no mutations (no delete/disable). Inexecuteit mutates onlyapprovedIds. The human-confirmation gate between the two is the orchestrator's job — seeagents/sweep.md § Human-confirmation gate.approvedIds(executemode only) — the exact workflow/pipeline/synthetic/solicitation/update-link/quote ids the human approved in chat. Mutate nothing outside this set. Aforce: truedelete of a solicitation with seeded responses is approved per solicitation, by name, never by a blanket approval.programIds(optional explicit argument) — labs program ids to audit for supply-chain records. Default: everyprogram_idon a solicitation ACE's orgs own (Step 2), plus everyphases.execution-management.products.supply_chain.program_idthe live-set's runs carry.
Products
ACE/_sweep/<timestamp>/labs-orphans.md— human-readable triage report.ACE/_sweep/<timestamp>/labs-orphans.yaml— machine-readableOrphanReport.- For approved orphan workflows:
workflow_deletecalls. - For approved orphan pipelines:
pipeline_deletecalls. - For approved orphan synthetic opps:
synthetic_disablecalls. - For approved orphan solicitations:
delete_solicitationcalls (cascade-deletes reviews + responses; gated on cascade emptiness — connect-labs PR #197). - For approved supply-chain items:
supply_chain_update_link_revokeandsupply_chain_quote_voidcalls. - An irreversible-records section in
labs-orphans.md: the supply-chain records labs keeps no delete for, listed for audit (§ "Optional labs track" below).
Process
- Read the live-set via
drive_read_file. - List labs inventory using existing atoms:
workflow_listpipeline_listlist_solicitations(each entry includesprogram_id,statusandis_public). It returns every call ACE's organisations own, unlisted (is_public: false) ones included, plus every public call. Noprogram_idis needed to see an unlisted call you own — that was a stale claim, refuted against the live schema in #3166. Passorganization_idper ACE org (pm_org,nm_org,llo_org) to scope the listing to ACE's own calls.list_fundslist_reviewslist_responses
- Diff against the live-set's labs buckets:
- workflows →
liveSet.identifiers.labsWorkflowIds - pipelines →
liveSet.identifiers.labsPipelineIds - synthetic opps →
liveSet.identifiers.labsSyntheticIds - solicitations/funds/reviews/responses →
liveSet.identifiers.labsRecordIds
- workflows →
- Score each orphan via
scoreLabsItem(item, liveSet)fromlib/sweep-fingerprint.ts. Pass each item'snameAND itsdescription(workflows, registries, cohorts) /notes(synthetic opps): a Phase 7 object carries its sweep handle(synthetic, ace <opp>/<run-id>)in whichever field no frame renders — a rendered object (programme report, opp report, synthetic opportunity) has it indescription/notes, never its name (demo-data-setup§ C7 "Sweep handles", ace#2733).sweepHandleFieldchecks all three and the score names the field and the run it came from. The scorer defensively downgrades tolowwhen an item references a Connect opportunity that's still inliveSet.identifiers.connectOpportunityIds— that's a sign the caller mis-flagged the item. - Build the
OrphanReportwithsystem: 'labs'. Partition into:- Actionable (deleted in the execute pass, after human approval): workflows, pipelines, synthetic opps, orphan solicitations. Solicitation deletion is gated on
responses + reviews == 0(cascade emptiness), not on lifecycle status — every ACE dogfood solicitation passes that gate cleanly because no real LLO ever engaged. See connect-labs PR #197. - Informational only: funds, standalone reviews/responses (reviews+responses that were already cascade-deleted with a parent solicitation don't appear here). Funds may need their own per-type atom in a future labs MCP release; reviews/responses generally cascade with their parent solicitation.
- Supply-chain items (optional labs track): active update links, and quotes that are neither awarded nor voided, in a program that is orphaned or whose run has closed — see § Optional labs track.
- Actionable (deleted in the execute pass, after human approval): workflows, pipelines, synthetic opps, orphan solicitations. Solicitation deletion is gated on
- Render + write
labs-orphans.mdand.yamlto the sweep folder, including the irreversible-records section. - Recommend — stop here in
mode: recommend. Return the structured recommended-action list (orphan workflows/pipelines/synthetic to delete-or-disable; orphan solicitations to delete with their cascade preview — each with id, confidence) plus the informational-only items (funds, standalone reviews/responses) and the report Drive link, to the orchestrator. Perform no mutations. Do not try to prompt the human from this skill — a dispatched subagent can't reach them; the orchestrator runs the confirmation gate (seeagents/sweep.md § Human-confirmation gate).
Execute phase (mode: execute only)
Runs only when the orchestrator re-dispatches with mode: execute + approvedIds (the ids the human approved in chat). Mutate only those ids:
Orphan workflows →
workflow_delete({ workflow_id })Orphan pipelines →
pipeline_delete({ pipeline_id })Orphan synthetic opps →
synthetic_disable({ synthetic_opp_id })Orphan solicitations →
delete_solicitation({ solicitation_id })(program_idis "accepted for compatibility; not needed" in the live schema). The atom cascade-deletes the solicitation's reviews and responses in one call and returns the count of records deleted at each level — surface that in the result so the human sees the cascade impact. Passforce: trueonly for the rare legitimate destroy-with-engagement-data case (test fixtures that intentionally include responses) — and only if the human explicitly approved that override.Approved update links →
supply_chain_update_link_revoke({ program_id, link_id, source: { ref: "ace:sweep:<timestamp>:update-link:<link_id>" } }). It stops working at once and cannot be re-enabled; what was recorded through it stays.Approved quotes →
supply_chain_quote_void({ program_id, quote_id, reason: "ACE sweep <timestamp>: simulated run <run-id> closed", source: { ref: "ace:sweep:<timestamp>:quote:<quote_id>" } }). The quote stays readable and drops out of comparisons.
Funds, standalone reviews/responses and every irreversible supply-chain record are never mutated (report-only). Return the per-item result.
Optional labs track (--with labs_e2e runs)
A run with the optional steps on (spec docs/superpowers/specs/2026-10-18-optional-labs-e2e-steps.md) leaves three kinds of labs objects behind, each with a different cleanup:
- Private solicitations with seeded responses.
solicitation-seed-responsesfiles fictional respondents (names end[Synthetic], the run's roster lists them). Because the call then HAS responses,delete_solicitationrefuses it withoutforce: true. Recommend it as a per-solicitationforcedelete, with the cascade preview, and say the responses are ACE-seeded fixtures. The human approves the override for that solicitation by name. A solicitation with any response NOT on the run's seeded roster is real engagement data: report it, never recommendforce. - Removable supply-chain items. For each program in
programIds:supply_chain_update_link_list({ program_id, include_inactive: false })→ recommend revoking every active link of an orphaned or closed run;supply_chain_quote_list({ program_id })→ recommend voiding every quote that is neither awarded nor already voided, on a tender no live run still has open. These are the only supply-chain removals labs offers. - Irreversible records — report, never act. Labs keeps no delete for tenders, quotes, awards, contracts, shipments, consignments, receipts, invoices, payments, stock counts or distributions (spec § F6), and a declared programme runner can only be changed by that runner's admins or support, never removed. For each program, list counts from the matching
supply_chain_*_listreads andsupply_chain_programme_runner_get, each with the run that wrote it. The isolation for these is the program itself: they are scoped to ACE's own program, named "simulated", and stay there for audit.
Known ACE-made items as of 2026-10-18, so the first sweep after them reads them right rather than flagging them as strays:
- Private call 1000003 on program 308 (owned by
connect_orgs.pm_org), closed, with seeded responses 1000046–1000049: the PR4 live probe (#3176). Deletable: recommendforce: truewith the cascade preview. - Program 308's runner declaration (
connect_orgs.pm_org's labs org, 352): the live check of connect-labs #2605. Irreversible from ACE; report it. Nothing else was written to program 308's supply chain.
Failure modes
- Live-set path doesn't resolve: abort with "Run
sweep-live-setfirst." - Labs MCP returns 401:
LABS_MCP_TOKENis expired; recommend/ace:labs-token-mintto rotate, then retry. workflow_deletefails because the workflow has running tasks: report the item as "in-use — needs manual review"; don't retry, don't abort the batch.delete_solicitationrefused (FAILED_PRECONDITIONwith response/review counts): the solicitation has real engagement data — a real LLO filed a response or a review was created. Surface the counts in the chat output; do NOT passforce: trueautomatically. The operator decides whether to override.
Why funds + standalone reviews/responses remain report-only
The labs MCP exposes per-type delete for solicitations because solicitations are the lifecycle unit for the audit-data ecosystem (reviews and responses are children that cascade-delete with their parent). The other LabsRecord types intentionally don't have per-type delete atoms because:
- Funds may have allocations + downstream allocation refs from responses. A future
delete_fundatom would need similar lifecycle guards (and the labs team hasn't surfaced demand for one yet — funds tend to be reused across solicitations rather than created per-opp). - Standalone reviews/responses (not cascade-deleted with a parent solicitation) are uncommon — if they exist as true orphans, they were probably created by a buggy producer and should be investigated rather than auto-deleted. Surface them for visibility.
If the labs team adds delete_fund upstream, this skill's coverage matrix entry flips automatically — the proxy is a pure forwarder so no ACE-side wiring is needed beyond updating Step 5/6/9 and agents/sweep.md.
Related skills
sweep-live-setproduces the live-set this skill diffs against.