connect-opp-modify
Change a live Connect opportunity: verification flags, payment units, dates, budget, visit caps or the Learn pass mark, with a before-read and read-back. Use when asked to extend or reconfigure a live
SKILL.mdskills/connect-opp-modify/SKILL.md
GitHubModify a live Connect opportunity
Changes configuration on an opportunity that already exists, whether or not ACE built it. Each change reads the current value, writes it, and reads it back. Playwright-backed writes report the POST status, not the saved state, so only the read-back counts.
Platform facts: connect-api.md § Changing a live opportunity
and § Data model gotchas. This skill is the procedure.
Inputs
| Parameter | Used for | Resolver |
|---|---|---|
opportunity_id |
the opportunity UUID | explicit arg; default: run_state phases.connect-setup.products.connect.opportunity.id; else the program context doc's Scope |
program_org |
the org whose URL serves every opportunity operation: the program's org, not the holding org (connect-api.md § PM→NM org-URL matrix) |
explicit arg; default: run_state products.connect.pm_org_slug; else the org in the program's recorded URL |
program_id |
needed only for the Learn passing score | explicit arg; default: opp.yaml.connect.program.id; else the context doc |
changes |
the requested change(s): any of verification_flags, add_payment_units, end_date / name / short_description / description / active, total_budget, learn_passing_score |
explicit arg |
No run_state.yaml is needed.
Products
- A change record with each field's before, requested and read-back values:
- inside a run,
<N>-<phase>/connect-opp-modify_<YYYYMMDD-HHMM>.md; - on a program project, a dated line in the context doc's Decisions.
- inside a run,
What this skill cannot do
| Requested | Why not | Say instead |
|---|---|---|
| Change or delete a payment unit (amount, caps, deliver units) | No atom exists | Do it in the Connect UI, or a new opportunity on a fresh Deliver release |
| Change the holding org | target_organization_slug is create-time only; connect_update_opportunity has no org field (ace#2919) |
A new opportunity, which is a build, not a change |
| Delete the opportunity | No atom exists | Deactivate it (active: false) or delete it in the Connect UI |
| Bind a payment unit to a deliver unit another opportunity in the same holding org already holds | ace#573 | A fresh Deliver release |
Refuse these up front, with the reason, before any write.
Process
Confirm the approval. These are writes to a live partner object. The caller at level 0 must already have shown the before and after values and got approval (
partner-on-connect-program § Changing a live program). A subagent cannot ask the human; with no recorded approval, return the proposal and stop.Read the before state at
program_org:connect_get_opportunity;connect_list_payment_unitsandconnect_list_deliver_units;connect_get_verification_flags: the persistedform_field_rules, the per-deliver-unit duration floors and the submission window. It is read-only (ace#3161), so the before-read never goes throughconnect_set_verification_flags. An explicit--form-field-rulesoverrides it. Read it even whenchangeshas noverification_flags: a new payment unit on a deliver unit that already carries rules changes what those rules gate;- for a passing-score change,
connect_get_learn_passing_score(needsprogram_id).
A missing opportunity at that org means the wrong org. Re-resolve it; never try the other org blind.
Refuse what can't be done. Check
changesagainst § What this skill cannot do.Name the side effects in the proposal before writing:
- Learn passing score: shared by every opportunity in the holding org wired to the same
HQ Learn app (ace#1350). List those opportunities with
connect_list_opportunities. Changing the score changes the gate for all of them. Workers already past Learn are unaffected, because completion is one-way. - New payment unit: needs an unbound deliver unit. List the deliver units and check which
are already referenced by
connect_list_payment_units. - Budget: pass
total_budgettoconnect_create_payment_units, so the server enforces funds for at least one worker (ace#729). short_descriptionand slug: both are truncated at 50 characters without warning. Refuse anything longer.
- Learn passing score: shared by every opportunity in the holding org wired to the same
HQ Learn app (ace#1350). List those opportunities with
Write, one change at a time, each followed by its read-back. The payload rules for the first two live in one place,
connect-opp-setup§ Operations on an existing opportunity; follow them there rather than from memory:- Verification flags:
connect_set_verification_flags, perconnect-opp-setupStep 5 (JSONPathquestion_pathread from the released CCZ, the stored option value, the deliver unit'sserver_id, names of 25 characters or fewer, the refused dead flags). Its response carriesform_field_rules_savedand the persisted rules. A deliver-unit move or a duration floor that did not persist is a typed error, not a success. - Add payment units:
connect_create_payment_units, an atomic batch, perconnect-opp-setupStep 6 (whole-currency integers, never cents; a non-emptyrequired_deliver_unitsofserver_ids;total_budgetpassed; the create response, not the listing, is the read-back). - Dates, name, description, active:
connect_update_opportunity. Use it to deactivate only; activate withconnect_activate_opportunity, which carries the activation preconditions. - Learn passing score:
connect_set_learn_passing_score. Keep itsprevious_passing_scorein the record. To diagnose a read-back that disagrees, useconnect-opp-setupStep 4'spassing_scorecheck (classifyPassingScoreReadback).
- Verification flags:
Read back and compare. Run step 2's reads again and diff them against the requested values. Any mismatch is a failed change: report it. Retry only once, and only when the cause is understood.
Record. Write before, requested and read-back values to the record named in § Products.
MCP Tools Used
- ace-connect:
connect_get_opportunity,connect_list_opportunities,connect_list_deliver_units,connect_list_payment_units,connect_get_verification_flags,connect_set_verification_flags,connect_create_payment_units,connect_update_opportunity,connect_activate_opportunity,connect_get_learn_passing_score,connect_set_learn_passing_score
Existing objects
- Deliver units are shared within a holding org on the same released Deliver app (ace#573). A new payment unit needs an unbound deliver unit. Step 4 checks for one; with none, refuse.
- The Learn
passing_scorelives on the sharedCommCareApprow (ace#1350). Step 4 names every affected opportunity before any write. - The holding org is create-time only (ace#2919). Refused in step 3.
- There is no payment-unit update or delete atom. Refused in step 3.
Mode Behavior
- Auto: with approval recorded in the dispatch, writes and reads back each change; halts on the first mismatch.
- Review: presents the step 4 proposal (including every other opportunity a shared change touches) and waits.
Dry-Run Behavior
When --dry-run is active, run steps 2–4 and write the proposal. Make no writes.
Change Log
| Date | Change | Author |
|---|---|---|
| 2026-10-18 | Step 5 points at connect-opp-setup § Operations on an existing opportunity for the flag, payment-unit and passing-score mechanics, so they are written down once (#3148 batch 3) |
ACE |
| 2026-10-18 | Initial version: change a live opportunity, with explicit "cannot" rows and shared-state warnings (audit item 6) | ACE (build-vs-maintain audit) |