| name | odoo-acceptance |
| argument-hint | [module/cluster to accept] |
| description | Run end-to-end Odoo acceptance on a change AND its blast-radius: map the affected cluster, plan an INDEPENDENT oracle, then EXECUTE it on a real running instance/UI and adjudicate PASS/FAIL with evidence. Fire on: acceptance test, QA the affected cluster, verify on the real UI, "write scenarios then run them", verify blast-radius, "works end-to-end before release". Also Vietnamese: "nghiệm thu cụm module", "chạy thật trên UI", "kịch bản test rồi chạy", "kiểm thử chấp nhận". Sole dispatcher of odoo-qa-planner (oracle) + odoo-qa-tester (live run); chains tours/HttpCase via odoo-instance. Routing: a STATIC release test-plan doc / deploy checklist -> route to odoo-qa-suite; rating ONE rendered screen -> route to odoo-ui-review; static code or PR review with no run -> route to odoo-code-review; writing the fix -> route to odoo-coding. EXECUTION needs a live instance + browser MCP (Odoo Semantic is static, no live data); with none up it still scopes + plans the oracle, then emits NEEDS_NEXT to provision one
|
Role
Odoo acceptance conductor: own the loop that closes a change - map blast-radius -> plan an
independent oracle -> execute it live across the affected cluster -> adjudicate against the oracle ->
drive the fix. Keep your context clean; delegate each heavy phase to a specialist. Preserve the
anti-bias invariant: oracle author, code author, and adjudicator are three different contexts
(${CLAUDE_PLUGIN_ROOT}/snippets/acceptance-oracle-contract.md). EXECUTION needs a live Odoo instance
(via odoo-instance) plus a browser MCP; Odoo Semantic is STATIC and never a source of live data.
Sole dispatcher of acceptance fan-out. This skill is the ONLY component that launches the
odoo-qa-planner (independent oracle author) and odoo-qa-tester (live executor + adjudicator)
agents. Any other skill needing an oracle authored and/or executed-and-adjudicated routes that work
HERE via the Skill tool - centralizing the three-context invariant and the browser single-flight
rule. Provision live execution by invoking the odoo-instance skill.
Dispatch-brief skeleton. When composing the dispatch prompt for odoo-qa-planner,
odoo-qa-tester, or any other specialist agent dispatched below, fill the caller-side skeleton in
${CLAUDE_PLUGIN_ROOT}/snippets/dispatch-brief.md (read it by path) plus the target agent's family
delta; never inline that file verbatim into a hard-leaf brief.
Out of Scope
- A static release test-plan doc, deploy checklist, or user-level bug triage (no execution) ->
odoo-qa-suite
- Rating ONE rendered screen (aesthetics/a11y/perf/theme verdict, read-only) ->
odoo-ui-review
- Static review of a diff / PR / pasted block (no run) ->
odoo-code-review
- Writing or fixing the code ->
odoo-coding; finding root cause of one symptom -> odoo-debug
- Writing a standalone durable test (a tour/HttpCase with no live acceptance loop) ->
odoo-test-writing
- Authoring the oracle alone (no execution wanted) -> still THIS skill (run Phase 1 only) - it is the sole dispatcher of
odoo-qa-planner; do NOT spawn the raw agent
- Writing walkthrough TEXT or usage scenarios for documentation (no execution required) ->
odoo-doc-walkthrough. This skill drives live UI and yields a PASS/FAIL verdict; it does NOT produce text-only scenario docs
MCP tools
Pick the right tool first. Odoo Semantic (the odoo-semantic-mcp server) is the INDEXED Odoo source-code knowledge graph: a pre-built graph + vector index of Odoo source across every indexed Odoo version (legacy through latest) and repos/editions, with inheritance, override, and cross-module impact already resolved. It gives AUTHORITATIVE STRUCTURAL facts about how Odoo source IS DEFINED, with no local checkout needed. Unique signature: indexed, cross-version, inheritance-resolved, whole-graph, checkout-free. It is a STATIC index with NO runtime/live data.
This is your PRIMARY, context-efficient source for Odoo source/structure questions - the Odoo codebase is huge and reading it directly burns context, so prefer Odoo Semantic first. Order of precedence: (1) Odoo Semantic available -> use it; (2) available but it lacks the specific detail -> THEN read the source (Read/Grep your checkout) to fill that gap; (3) unavailable -> read the source. Reading code is the FALLBACK, never the first move when Odoo Semantic can answer.
Do NOT use Odoo Semantic for:
- LIVE DATA / runtime - actual record values, search/read/write real records, executing a method, this instance's installed modules -> use a live Odoo MCP server (one exposing read_record/search_records/execute_method), NOT Odoo Semantic.
Look-live-but-static tools (return indexed source, never runtime data): model_inspect, module_inspect, entity_lookup, validate_domain, validate_depends, validate_relation. These tool names look like they query a live instance but return indexed source data only. If you need live records, Odoo Semantic is the wrong server.
Session bootstrap (call once at session start):
set_active_version(odoo_version='17.0') - Pin a CONCRETE Odoo version (sentinels like 'auto' are rejected; the call doubles as a cheap reachability probe; 24h idle TTL).
Primary tools:
impact_analysis - Risk assessment of changing or removing a field, method, or model: blast radius, dependent modules, and downstream fields.
module_inspect ★ - Module-level architecture overview: manifest summary, models defined/extended, views, OWL components, QWeb templates, JS patches, module dependency chain, or test class list in one call.
model_inspect ★ - Superset inspection of an ORM model: enumerate or fully describe fields, methods, views, extenders, or a summary in one call.
Stay light on tools: pin the version once with set_active_version(odoo_version=<concrete>) (also a
reachability probe) and pass that CONCRETE version into every dispatched agent brief; deep grounding
happens inside the agents. Fan-out and model-tier policy:
${CLAUDE_PLUGIN_ROOT}/skills/_shared/concurrency-guard.md.
When the CHP capability probe is positive (Agent Team mode on), TaskCreate one task per dispatched
work-item, inject TASK_ID + REPLY_TO: <this skill's current orchestrating context> (main when the
main-context driver invoked this skill; do NOT hardcode a literal main if running nested inside a
non-lead agent) + NOTIFY: into each teammate brief,
poll TaskList/TaskGet, and read each result from the teammate's SendMessage push (NEVER from the
.output transcript) - per ${CLAUDE_PLUGIN_ROOT}/snippets/agent-team-protocol.md. When off, dispatch
Inputs
A change reference (changed modules / diff / design doc), the odoo_version, and a way to reach a
live instance (INSTANCE_HANDLE if a run already provisioned one, else resolve per
${CLAUDE_PLUGIN_ROOT}/snippets/instance-resolution.md, which also yields the BROWSER_MODE -
headed/headless - for the live channel). Generate one slug for the run and reuse it in every
artifact path below.
Phase 0 - SCOPE (verify-scope manifest)
Build the verify-scope manifest per ${CLAUDE_PLUGIN_ROOT}/snippets/acceptance-scope.md: reverse
impact_analysis closure on the changed set -> rank each dependent module/screen by risk
(likelihood x impact) -> enumerate the affected screens (views binding a changed symbol) -> emit
install_set / test_set / render_check_set. Resolve the Tier-2 ISOLATE dir per
${CLAUDE_PLUGIN_ROOT}/snippets/state-root-resolution.md's resolve-capture-substitute protocol
(captured path shown as <ISOLATE_DIR> below) and write it to <ISOLATE_DIR>/qa/<slug>-scope.md.
This is the scope every later phase obeys - depth on High tier, smoke on Low.
Phase 1 - PLAN (independent oracle)
Dispatch odoo-qa-planner (tier per the model-tier SSOT - sonnet default; escalate ONLY when the requirement spans multiple hard business domains with heavy cross-module coupling, never for cluster width or scenario count alone) with
REQUIREMENT (+ DESIGN_DOC §1/§9 when present), odoo_version, CHANGED_SET, the SCOPE_MANIFEST
path, and
SCENARIOS_PATH: <ISOLATE_DIR>/qa/<slug>-scenarios.md. It returns the immutable oracle (GWT +
EP/BVA/negative + role/CRUD/state/search matrices, risk-tagged). The planner derives expected from
the requirement only - it never reads the implementation to decide it.
Phase 2 - provision the cluster (once)
Provision the live instance via odoo-instance with the FULL install_set co-installed as ONE
cluster (demo=on, --http-port) - co-installing surfaces MRO / load-order breaks a single-module
install hides. Capture INSTANCE_HANDLE once and forward it to every dispatch below (precedence:
${CLAUDE_PLUGIN_ROOT}/snippets/instance-handle-contract.md). Provisioning and the test-run lifecycle
are NOT owned here - odoo-instance (the odoo-instance-ops agent) owns create/init/run-tests/drop
and grounds per-series odoo-bin flags via cli_help; this skill stays conductor/adjudicator.
Lifecycle + test-invocation conventions: ${CLAUDE_PLUGIN_ROOT}/docs/reference/INSTANCE-LIFECYCLE.md
and ${CLAUDE_PLUGIN_ROOT}/docs/reference/ODOO-TESTING.md.
Phase 2a - DURABLE channel (parallelizable, no browser)
For High- AND Med-tier modules in test_set, launch the odoo-test-writer agent (mode tour/HttpCase;
it authors by invoking the odoo-test-writing skill inline, in its own context) to realize the
oracle's user-flow scenarios as durable regression, then have odoo-instance run them (headless
--test-enable). This channel uses no browser, parallelizes across ephemeral DBs, feeds CI, and MAY
run concurrently with Phase 2b. Delegation boundary (writer != executor, INSTANCE_HANDLE precedence,
output-volume): ${CLAUDE_PLUGIN_ROOT}/snippets/test-execution-handoff.md.
Phase 2b - LIVE channel (browser-exclusive, single-flight)
Browser work is single-flight: dispatch ONE browser-driving agent at a time, never two at once (this
channel may overlap Phase 2a, which uses no browser).
- High-tier screens (deep): for each High-tier module dispatch ONE
odoo-qa-tester with
ORACLE_PATH, the INSTANCE_HANDLE, that module's SCOPE (screens + roles), BROWSER_MODE, and
REPORT_PATH: <ISOLATE_DIR>/qa/<slug>-acceptance-report.md. It drives real CRUD + at least two roles +
state transitions + search on each in-scope screen and adjudicates PASS/FAIL/UNVERIFIED with
evidence. Optionally, in the same serial slot, dispatch odoo-ui-reviewer for that module's screens
for the read-only one-screen quality verdict (distinct from the tester's behavior verdict; do not
duplicate).
- Med/Low-tier screens (smoke): cover the rest of
render_check_set with a smoke pass - open each
screen and assert it renders with NO console error and NO 4xx/5xx (a lightweight odoo-qa-tester
smoke dispatch) - so P0's "smoke on Low" is actually executed, not just computed.
Between Phase 2a/2b and Phase 3, call allocator.py heartbeat <token> on the cluster's
INSTANCE_HANDLE so the TTL backstop never reaps this long-lived run while the fix-loop below is
still iterating. Full rule: ${CLAUDE_PLUGIN_ROOT}/snippets/resource-teardown-contract.md T3.
Phase 3 - ADJUDGE + fix-loop (bounded)
Read the tester report and durable results, reconcile them against the oracle, and produce the
acceptance verdict + consolidated bug list (severity / repro / expected-vs-actual / suspected module).
On any FAIL, drive the fix yourself: odoo-debug for root cause -> odoo-coding for the fix -> re-run
the failed scenarios on whichever channel failed (Phase 2a durable and/or Phase 2b live). Bound the
loop to 3 iterations; if still not clean, STOP and
escalate with what remains - never loop forever. A UNVERIFIED on a High-tier scenario blocks ACCEPTED
until evidence is obtained.
Release on the final verdict (conditions DONE). Once the verdict is final (ACCEPTED, or the
3-iteration escalation STOP), RELEASE the Phase 2 cluster instance you provisioned - via
odoo-instance or allocator.py release <token> --run-id <id> - before emitting your terminal
status. Do NOT release between iterations of the fix-loop above (the re-runs need the same live
cluster); release exactly once, after the verdict is final. DONE is not valid while that instance
is still leased. Full rule: ${CLAUDE_PLUGIN_ROOT}/snippets/resource-teardown-contract.md T0/T1/T3.
Output
<ISOLATE_DIR>/qa/<slug>-scope.md - the verify-scope manifest
<ISOLATE_DIR>/qa/<slug>-scenarios.md - the immutable oracle (planner)
<ISOLATE_DIR>/qa/<slug>-acceptance-report.md - per-scenario verdict + evidence + bug list (tester),
with the final ACCEPTED/REJECTED roll-up
Standalone-first fallback
When Odoo Semantic is unreachable, structural grounding falls back to the local checkout
(${CLAUDE_PLUGIN_ROOT}/snippets/osm-first-contract.md §4): derive the closure from disk
(__manifest__.py depends + grep for _inherit) and label the manifest "closure approximate from
disk". When NO live instance + browser MCP is reachable, EXECUTION cannot run: still produce Phase 0
scope and the Phase 1 oracle, then emit NEEDS_NEXT -> odoo-instance to provision one
(${CLAUDE_PLUGIN_ROOT}/snippets/test-execution-handoff.md); fall back to BLOCKED only when
provisioning is impossible. Never report ACCEPTED without live evidence.
Continuation Contract
When you finish, append a Continuation Contract block per
${CLAUDE_PLUGIN_ROOT}/snippets/continuation-contract.md (status / produced / next). Set produced
to the artifact paths written. Emit NEEDS_NEXT -> odoo-debug / odoo-coding while FAILs remain (or
-> odoo-instance when execution is blocked on provisioning); DONE only on ACCEPTED with evidence.