decisions-render
Internal /ace:run step — Render a per-run decisions.yaml into a prose Google Doc at one stable URL per run.
SKILL.mdskills/decisions-render/SKILL.md
GitHubDecisions Render
Read decisions.yaml from a run folder, render it as a prose Google Doc, and
write the result to decisions.gdoc at one stable URL.
Inputs
Pipeline-only: renders a run's decisions.yaml, which exists only in a run.
| Source | Artifact | Used for |
|---|---|---|
| Per-run state | ACE/<opp-name>/runs/<run-id>/decisions.yaml |
the structured log to render |
Products
ACE/<opp-name>/runs/<run-id>/decisions.gdoc— prose Google Doc rendering at one stable URL. Find-or-update semantics; existing content is cleared and replaced on every invocation. Each row renders anAI-default:line and, when the row is overridden, anOverride:line immediately below it. The status line is plain text (Status: appliedorStatus: overridden).
Terminology
Every string this skill puts in front of a reader follows
skills/_terminology.md: Connect, never CommCare Connect, and
US spelling, always — program, enrollment, enroll, organization, behavior, center; never
programme, enrolment, organisation (owner, 2026-10-20: "everything should be US spelling",
ace#3232). Identifiers (case properties, slugs, ids, config keys) keep their spelling.
Process
Resolve the run folder file ID for
ACE/<opp-name>/runs/<run-id>/.Use
drive_list_folderfrom the opp folder to find the run folder.
1.5. Enrich the log first — decisions_enrich (REQUIRED, schema v6). The
decisions log is the run's review artifact (the build memo is retired), and
the parts of it with a right answer are computed, not left to the producers:
mcp__plugin_ace_ace-decisions__decisions_enrich
{ runFolderId: "<run-folder file ID from step 1>" }
It reads decisions.yaml + run_state.yaml from the folder and stamps
rule scope/enforcement, audience: internal on harness rows, folds
cross-skill duplicates, and marks review_ask: recommended-confirmation on
every PROPOSED program parameter the build configured, every
machine-translated language, every enforcement gap, every OPEN row and
every open residual a person must decide (docs/decisions-contract.md § What earns a review_ask). Idempotent; writes only on change. Carry its
reviewAsks list into the pause summary's Decisions Log: line ("N to
confirm before launch").
Plain-language gate. report.plainLanguageGate.verdict: fail is a
FAIL for this step, not a warning: list every findings[] entry as
<id>.<field>: <finding> grouped by skill (the producer that owes the
rewrite — skills/_decisions-review-fields.md), and carry the count into
the pause summary. It does not halt the render (the Doc is still the
reviewer's way in), but the same check blocks release
(assessDecisionsPlainLanguage), so a failing run cannot reach an outside
reviewer. Contract: docs/decisions-contract.md § Plain-language gate.
(missingPlain / jargon remain as flat views of the same findings.)
Render via the
render_decisions_logatom (the canonical, single-call path). Pass the run-folder file ID; the atom readsdecisions.yamlfrom it, renders the prose log vialib/decisions-renderer.ts, and find-or-updatesdecisions.gdocin the same folder — read + render + clear + batchUpdate all happen server-side, so you never relay the generated Docs API JSON yourself:mcp__plugin_ace_ace-gdrive__render_decisions_log { runFolderFileId: "<run-folder file ID from step 1>" }Returns
{ gdocId, reused, requestCount, webViewLink }. Each row renders anAI-default:line, anOverride:line when the row is overridden, and a plainStatus: applied | overriddenline (see § Products for the exact shape). The schema is validated server-side (lib/decisions-schema.ts § parseDecisionsYaml); a malformed row throws with its dot-path.- Do NOT hand-render the rows through
drive_create_doc_from_markdownor hand-relayrenderDecisionsLogoutput throughdocs_batch_update— that was the ~65KB-per-phase manual relay this atom replaces (jjackson/ace#574). scripts/decisions-render.ts(runDecisionsRender) is the library the atom wraps; itsimport.meta.url === ...CLI branch is still intentionally unwired (it needs a live Drive client). Don't shell out to the script.
- Do NOT hand-render the rows through
Confirm the gdoc URL from the atom's
webViewLinkfield. The orchestrator captures this URL for the pause summary'sDecisions Log:line.
Failure modes
- decisions.yaml is missing: the script throws with the run folder ID; the orchestrator's Phase Write-Back Verifier should have already created an empty decisions.yaml before this skill runs. If it didn't, the skill halts and surfaces the missing-file error to the operator.
- Schema-invalid YAML: the script throws with the dot-path of the offending field. The originating skill (whichever phase wrote the bad row) gets a hard fail; orchestrator surfaces it in the pause summary's BLOCKER list.
- Docs API rate limit: rare — the renderer makes one batch update per phase. Retry once after 30s; halt with actionable error if it fails again.
MCP Tools Used
- Google Drive:
drive_list_folder(step 1, resolve run folder),render_decisions_log(step 2, the single-call render) - ace-decisions:
decisions_enrich(step 1.5, the deterministic v6 review fields)
Mode Behavior
- Auto: Run, no human pause. Stdout includes the gdoc URL for downstream skills.
- Review: Same as Auto — the renderer is deterministic, no human review of the rendering itself.
Change Log
| Date | Change | Author |
|---|---|---|
| 2026-05-08 | Initial skill — pairs with lib/decisions-renderer.ts and scripts/decisions-render.ts. Renders decisions.yaml as a prose Google Doc; idempotent; runs at end of every phase. |
ACE team (decisions-log PR #2) |
| 2026-05-31 | Canonical path is now the render_decisions_log MCP atom (wraps runDecisionsRender server-side) — one call with the run-folder file ID instead of hand-relaying ~65KB of docs_batch_update JSON per phase (jjackson/ace#574). |
ACE team |
| 2026-09-06 | Stop routing concerns to a gate brief that does not exist (dimagi-internal/ace#1884). 0.13.116 removed the per-skill gate-brief file class and the ace#1880 sweep removed the remaining *.md PATHS, but prose directives naming the gate brief as a DESTINATION survived in 15 files — a concern "surfaced in the gate brief" is surfaced nowhere. Repointed at the verdict YAML's auto_surfaced block, which is what the orchestrator actually renders the pause summary from. Gated by the new destination check in test/skills/gate-brief-removal-complete.test.ts. |
ACE team |
| 2026-10-03 | Step 1.5: decisions_enrich before the render (schema v6). The decisions log replaced the build memo as the review artifact; the enrichment computes rule scope/enforcement, harness audience, cross-skill dedupe and every derived review_ask, and the Doc now opens with "To confirm before launch". Contract: docs/decisions-contract.md. |
ACE team |