DEV Community

Legacy Obituaries: building the notice-lifecycle workflow

Claude Code 82 messages September 28, 2026
by uptimearchitect
Legacy Obituaries: building the notice-lifecycle workflow claude-opus-5-5
You

<teammate-message teammate_id="team-lead" summary="Build and deploy notice-lifecycle workflow">
Goal: add a real Sanity Workflows (early access, @sanity/workflow-engine + @sanity/workflow-cli 0.35.x) definition to the public repo ora2az, deploy it to the live Sanity project, and prove it runs. This is for a DEV.to challenge entry ("Legacy Obituaries"); judges give bonus credit for using Workflows.

Repo (local git clone, pushes to public GitHub pyaroslav/ora2az): [REDACTED]/sanity-challenge/ora2az
- Sanity project udyjvgsk, dataset production (public), org o8wfejrgc. The Sanity CLI is logged in on this machine (npx sanity login credential in ~/.config/sanity/config.json), which the workflows CLI can use; env values are in ~/.config/ora2az/env (SANITY_PROJECT_ID, SANITY_DATASET, SANITY_WRITE_TOKEN editor token). Never print token values.
- Schema: studio/schemaTypes/oracleFeature.ts has fields obituary (Portable Text) and reviewStatus ('draft' | 'certified'). Published features with certified obituaries: 47. Three features are currently in the review queue as drafts (drafts.feature_xmltype, drafts.feature_vector-datatype, drafts.feature_flashback-query) with reviewStatus 'draft' and an obituary; their published versions have no obituary.
- Existing human gate: the App SDK desk (desk/src/CertifyButton.tsx) certifies by editDocument(set reviewStatus certified)+publishDocument.
- There is a fact check we already ran by script: an obituary may not mention an Oracle release (e.g. 12.2, 19c, 26ai) or ORA-xxxxx code that is not present in that feature's own data (summary, releases, its mappings/caveats/disputes).

Read the docs FIRST (fetch pages; use https://www.sanity.io/docs/llms/workflows.txt and the pages it links): https://www.sanity.io/docs/workflows , /docs/workflows/getting-started , /docs/workflows/studio-plugin , /docs/workflows/sanity-functions , /docs/workflows/cli-reference , /docs/workflows/cookbook , /docs/workflows/cookbook-editorial-review , /docs/workflows/cookbook-ai-content-pipeline. Also read the installed package types in node_modules (@sanity/workflow-engine/define etc.) — a scratch install exists at /tmp/claude-1000/wf. Follow the real API; do not guess.

Build:
1. workflows/ folder in the repo with its own package.json (deps @sanity/workflow-engine, @sanity/workflow-cli pinned to the versions in /tmp/claude-1000/wf), sanity.workflow.ts, and definitions/notice-lifecycle.ts: a workflow over an oracleFeature document with stages roughly: drafted → fact-checked → certified (terminal), with a retract path back to drafted, and a guard so the obituary field cannot change while the instance is in certified if guards are supported. Model the fact check as an activity/action (automated where the engine allows, otherwise an action fired by a script) and certification as a human action. Keep it small and correct over ambitious.
2. workflows/scripts/fact-check.mjs: reads the instance's document (draft), runs the release/ORA-code check described above via GROQ, and fires the corresponding action (pass → fact-checked, fail → back to drafted with a note) using the CLI or the engine client API, whichever the docs show.
3. Deploy to deployment production bound to udyjvgsk.production (npx sanity-workflows deploy). Start instances for the 3 queued drafts, run the fact check on them so they reach fact-checked, and leave them there for a human to certify (do NOT certify or publish them). Use sanity-workflows inspect/list commands to capture the resulting state.
4. If the docs show a simple way to make certification in the existing App SDK desk fire the workflow's certify action (or to show the workflow stage in the desk), describe it in the README but only implement it if it is small and you can type-check it (npx tsc --noEmit in desk/); do NOT redeploy the desk.
5. workflows/README.md: what it does, stages diagram in text, how to deploy, how to run the fact check, current state (paste CLI output of the 3 instances), and honest limitations (early access 0.x, what is enforced vs not).

Rules: no brand/company names other than Sanity/Oracle/Azure; do not mention any AI vendor or model names in committed files; commit with git -c user.name=pyaroslav -c user.email=<personal-email> commit -m "workflows: …" (no co-author trailers) and git push. Do not modify app/, content/data/, or the published documents' obituary/reviewStatus beyond what starting a workflow instance does. If Workflows turns out to be unavailable for this org/plan (feature gated, 403, etc.), stop, do not fake it, and report the exact error text and which doc page states the requirement.

Report back: what was deployed, the instance states (CLI output), files added, any doc ambiguities you resolved from package source, and any errors.
</teammate-message>

Agent

I'll read the Sanity Workflows docs and the installed package types first, then build, deploy, and run the workflow.

Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent

Docs read; now writing the definition and config.

Agent
Agent
Agent
Agent
Agent
Agent
Agent

Validation passes. Before deploying, I'll exercise every path in memory using the engine's test bench.

Agent
Agent
Agent
Agent
Agent

The bench caught a real bug: optional params can't feed a field.set when omitted. I'll make the pass note required and drop the certify note.

Agent
Agent

Tests pass on every path, including the guard. Now the fact-check script; first a look at the three queued drafts.

Agent
Agent

Deploying the definition to udyjvgsk.production now.

Agent
Agent

Deployed as v1. Starting instances for the three features (published ids, as the docs require).

Agent
Agent
Agent

Instances are live in drafted. Writing the fact-check script now.

Agent
Agent

Dry run passes all three. I'll normalize token display and sanity-check the rule against the 47 certified obituaries to catch false positives.

Agent
Agent

The rule matches all 47 certified obituaries with no false positives. Running the fact check for real.

Agent
Agent

All three reached fact-checked. Capturing CLI state and verifying content documents were untouched and instance docs aren't public.

Agent
Agent

Now step 4: checking the App SDK doc and the desk's certify button for a small integration.

Agent
Agent
Agent
Agent
Agent
Agent

A small desk hook is feasible with just @sanity/workflow-engine (no UI packages). I'll try it and keep it only if the desk type-checks cleanly.

Agent
Agent
Agent

Desk type-checks. Checking the lockfile churn and that the desk still builds.

Agent
Agent
Agent
Agent

Desk builds. I'll let the desk agent know I touched its files, then write the README.

Agent
Agent
Agent
Agent

Writing the README.

Agent
Agent

Some workflow files show as modified, so someone already committed an earlier version of them. Checking.

Agent
Agent

An earlier commit by another agent swept in my first drafts of four workflow files. My commit completes them. Checking for disallowed names, then committing only my files.

Agent
Agent

Pushed. Last check: confirming the deployed definition matches the committed code.

Agent
Agent
Agent
Agent

The notice-lifecycle workflow is live on Sanity project udyjvgsk, dataset production. All three queued drafts have instances, passed the fact check, and are waiting in fact-checked for a human to certify. Nothing was certified or published. The work is pushed to GitHub as commit 88a3f8c. Workflows was available on this org with no gating or permission errors.

What was deployed. The workflow runs drafted, then fact-checked, then certified. A retract action returns a certified notice to drafted. A guard freezes the obituary text while a notice sits in certified. That stage is deliberately not terminal. A terminal stage would complete the instance and remove the freeze. A second deploy in dry-run mode reports no changes, so the live definition matches the committed code.

Instance states from the workflows CLI:

Instance Feature Stage
production.wf-instance.2e9f8b706af0 feature_xmltype fact-checked
production.wf-instance.1739bb2d4543 feature_vector-datatype fact-checked
production.wf-instance.3c0dea974deb feature_flashback-query fact-checked
  • Fact check. It passed all three. Each obituary mentions one release, and each release is in that feature's own data. I also ran the same rule against the 47 certified obituaries in report-only mode, and all 47 passed.
  • Content untouched. A public query confirms the three published features still have review status "draft" and no obituary.
  • Workflow data is private. The workflow's own records are not publicly readable. A public count of them returns zero.
  • Tests. In-memory tests cover every path, including the guard, and all pass.

Desk integration. The desk's Certify button now fires the workflow's certify action after it publishes. Un-certify fires retract. It adds one package, the desk type-checks, and a test build succeeds. The desk was not redeployed, so the live desk does not do this yet. I told the desk agent about the edit.

Doc gaps I resolved from the package source and tests:
- The workflow's subject must be the published document id, so the fact check reads the draft itself.
- An optional action parameter left out crashes the action. The tests caught this before deploy, so the fact-check note is now required.
- The workflows CLI needs TypeScript 6 or later.
- The documented definition diff command crashed, so I used a dry-run deploy for the drift check.

Limitations, all stated in the README:
- Advisory only. The docs say every engine check and guard is advisory during early access.
- The desk ignores the freeze. It does not read guards, so it can still change a frozen obituary.
- Publishing is not blocked. An obituary can still be published without passing the fact check. The workflow records the gate but does not enforce it.
- Order matters. Publish first, then fire certify, because entering certified switches on the freeze.
- Older obituaries are not tracked. The 47 already-certified obituaries have no workflow instances.
- The definition was shared with Sanity. Definition sharing was left at the CLI default, which is on, so deploying shared the workflow definition with Sanity.

Another agent's commit. It swept in my first drafts of four workflow files while I was still working. My commit completes them.

Files are in [REDACTED]/sanity-challenge/ora2az/:
- workflows/definitions/notice-lifecycle.ts
- workflows/sanity.workflow.ts
- workflows/scripts/fact-check.mjs
- workflows/test/notice-lifecycle.test.ts
- workflows/README.md
- workflows/package.json
- desk/src/workflow.ts
- desk/src/CertifyButton.tsx

You

<teammate-message teammate_id="team-lead" summary="Rebase before pushing; repo neutrality rule">
Heads-up before you commit: I force-pushed main a moment ago (history rewritten to 3e63b9c). Before your first commit run git fetch origin && git reset --keep origin/main if your local main is behind (you have not committed yet, so this only moves the pointer), then commit and push normally — never force-push. Also, repo rule: no committed file, path or commit message may contain the words "claude" or "anthropic" (case-insensitive), including in file names like CLAUDE.md; run git grep -Iil -E 'claude|anthropic' -- ':!**/package-lock.json' before each commit and fix any hit.
</teammate-message>

Agent

My commit was already pushed before this message arrived, so I'll check where it sits against the rewritten main.

Agent
Agent
Agent

My workflows commit, 88a3f8c, was pushed before the team lead's heads-up arrived, and it already sits on top of the rewritten main. Nothing needed resetting or fixing.

  • History: The push was a normal fast-forward from f0cbc60, not a force-push. The rewritten base, 3e63b9c, is an ancestor of my commit. Local main and the remote main now point at the same commit.
  • Banned words: The team lead's check for "claude" or "anthropic" finds no files on the remote main. No commit message there contains either word.

I've told the team lead all of this and have no further commits pending.