DEV Community

Cover image for The Legacy Obituaries: every Oracle feature that didn't survive the move to Azure gets a notice
Uptime Architect
Uptime Architect Subscriber

Posted on

The Legacy Obituaries: every Oracle feature that didn't survive the move to Azure gets a notice

Sanity Challenge Path Two Submission

This is a submission for the Sanity Challenge, Path Two: Vibe-Code Something Strange

Oracle Streams, born before 11.2, captured redo and continuously propagated database changes. It served as Oracle's replication engine with quiet persistence. Deprecated in 12.1 and desupported in 19c, Streams found Azure offered no direct reprieve… It is survived by Azure Database Migration Service, not at all; Azure Data Factory, only by workaround; Microsoft Fabric, partly; and Oracle Database@Azure, partly.

— The Legacy Obituaries

Read the paper: ora2az.vercel.app

What I Built

The Legacy Obituaries is a newspaper obituary column for Oracle Database features. The front page carries 28 notices, one for every feature that Oracle has deprecated or desupported, or that has no clean home in Azure; each of the 50 features in the graph has its own page:

  • born in the release that introduced it,
  • cause of departure: its deprecation and desupport releases, or the complication that keeps it out of Azure,
  • survived by: the Azure services that carry on its work, and how faithfully (unchanged, partly, only by workaround, or not at all),
  • contested accounts, when two sources disagree about how it died,
  • notices of correction: every source, with the date I read it.

It's strange on purpose, but it's also useful. If you're scoping an Oracle-to-Azure move, the front page is a fast checklist of what won't come with you, and every line links to the page that says so.

Every notice is assembled live from a structured Sanity dataset in which each claim carries a source. The "In life" summaries are written by me; the obituary paragraph is machine-drafted from the graph and human-certified. The same dataset powers my Path One agent: Keyword search found the facts but lost the sources.

Demo

Live: https://ora2az.vercel.app

Walking the front page, the Oracle Streams obituary, and the DBMS_JOB contested account

A contested account: did DBMS_JOB stop working in 19c?

Behind the paper there's Mortician's Desk, a small Sanity App SDK app in the Dashboard. An editor sees every draft notice live, and Certify edits and publishes it in one transaction. Only certified obituary prose reaches the public site; right now two notices are waiting in the queue.

Mortician's Desk in the Sanity Dashboard: 48 certified, 2 drafts waiting

The paper also carries The Coroner's Reports: every answer my Path One agent gave in its evaluation, with the queries it ran.

Code

GitHub logo pyaroslav / ora2az

Oracle → Azure migration knowledge graph on Sanity: an agent over Sanity Context, and The Legacy Obituaries (DEV Sanity Challenge 2026)

ora2az — an Oracle → Azure migration knowledge graph on Sanity

A structured, sourced graph of how Oracle Database features map to Azure, and two things built on it for the DEV Sanity Challenge:

What Try it
Path One A migration-advisor agent that answers only from the graph, through two Sanity Context MCP endpoints, with a four-way eval The Coroner's Reports: every eval answer, with the queries it ran. No install.
Path Two The Legacy Obituaries: an obituary for every Oracle feature that didn't survive the move to Azure ora2az.vercel.app

Sanity project udyjvgsk · dataset production (public; query it anonymously, e.g. all disputes). Studio at https://ora2az.sanity.studio needs a Sanity login.

The result in one table

18 held-out questions, graded blind (method and caveats):

Condition Verdict correct Cited every required publisher Grounded
Model alone 10/18 11/16 0/18
Keyword search (BM25) over the same documents 14/18
…

app/ is the Next.js site, desk/ the App SDK app, studio/ the schema, content/ the data, the drafting script and the tests. The session-by-session log is in docs/build-log.md.

My Build Process

Tool: Claude Code in the terminal. The model was Claude Fable 5.1 for most of the build and Claude Opus 5.5 at the end. One working session per step. The build log records each one: what I asked, what happened, what broke, how it was fixed.

My prompts were short; the agent did the planning and asked me the decisions. A few, verbatim:

"please analyze challenge at https://dev.to/devteam/join-the-sanity-challenge-2500-in-prizes-for-five-winners-514m and suggest next steps; make sure to do a thorough investigation and planning; ask questions if any"

That produced a plan and seven questions back to me: which path, which domain, account state, budget, which sources may be used, which brand, which Path Two concept. I picked Oracle → Azure because I've lived in that domain.

"suggest options that do not require payments - for example I have claude subscription and it sould be nice using it rather than buy a keys"

That decided the architecture: no API keys anywhere. The agent runs headless on the subscription, and the obituary prose is written by Sanity's Agent Actions on the free plan's AI credits.

"why do I need to certify? do I need to certify just one? can you do certification?"

Here's where the human gate got tested. More on that in step 4.

What went wrong, in order:

1. The schema came first, and it decided everything. I asked for a model where a keyword search could never fake the answer. That gave eight types: feature, Azure target, a mapping between them with a fidelity grade, caveats on each mapping scoped to Oracle versions, editions and Azure tiers, sources, and a dispute type that points at two caveats that disagree. The obituary is then just a GROQ join: desupportedIn gives the death, mapping gives the survivors, dispute gives the contested accounts.

 azureTarget ◀── mapping ──▶ oracleFeature ──sources[]──▶ source
                 fidelity    (dates, obituary, reviewStatus)
                    ▲
                    │
                 caveat ──evidence──▶ source
                 appliesTo: versions · editions · tiers
                  ▲    ▲
          claimA  │    │  claimB
                 dispute ──resolvedBy──▶ source

 glossary, pattern ──sources[]──▶ source    (the Knowledge Base)
Enter fullscreen mode Exit fullscreen mode

Every arrow is a reference. A notice is one GROQ query that walks them backwards from the feature, and a claim with no path to a source fails the seed validator and a dataset test before it can reach the site.

2. My first seed was invisible. The agent wrote ids like feature.dbms-job. All 445 documents were created, and every public query returned 0. A dot in a Sanity _id is a path prefix, like drafts., so the documents were hidden from the published view. Fix: store feature_dbms-job, keep the readable form in the YAML, recreate the dataset. Most instructive bug of the weekend.

3. The epitaph was pessimistic. The first version picked the worst mapping, so Data Pump read "survived by a workaround" even though it lives on unchanged in Oracle Database@Azure. An obituary is about who carries on, so the epitaph now speaks for the best survivor. I only caught it from a screenshot.

4. Obituary prose, written by Sanity's Agent Actions. A script calls client.agent.action.generate for each feature. The only material the model gets is that feature's own graph neighbourhood, passed as a GROQ instruction parameter: its mappings, caveats and disputes. It writes to the draft document; the site reads published documents only. Three things went wrong:
The first prompt forgot the survivors, the heart of an obituary (paragraph three is now mandatory and starts "It is survived by"); regenerating appended a second obituary instead of replacing it; and my "does a draft exist?" check ran in the published perspective, so it never saw drafts. All three are fixed, and a re-run now skips all 50.

Then the honest part. The domain is mine, and much of the material comes from my own blog, so I asked to certify all 50 at once. Before publishing, a script checked every draft for Oracle releases or ORA- codes that don't appear in that feature's own data. It flagged none, and all 50 were certified in one pass, not read line by line. A reviewer later pointed out that this made the gate look like a rubber stamp and left the desk with an empty queue. So three notices went back to draft. Two of them, XMLType and VECTOR, have since gone all the way through the workflow in step 6, and a front-page notice, the original exp utility (desupported in 26ai), joined the queue, so the gate now protects something a visitor can see.

5. The App SDK desk was scaffolded by hand, because I wasn't logged in yet. The docs left three questions open (is an index.html needed, may the organization id come from .env, how does process.env reach the browser), and the installed CLI source answered all three; the answers are in the build log. Certify batches editDocument and publishDocument in one useApplyDocumentActions call, so a notice is never half-certified.

6. Workflows: a notice has a lifecycle, not just a flag. A Sanity Workflows definition, notice-lifecycle, now sits over each queued obituary (workflows/):

drafted ──fact-check pass──▶ fact-checked ──certify (human)──▶ certified
   ▲   ◀──fact-check fail──┘       │                                │
   └────────── send back (reason) ─┘◀────── retract (reason) ───────┘
Enter fullscreen mode Exit fullscreen mode
  • Fact check. A script reads the draft obituary and fires pass or fail. It fails any Oracle release or ORA- code that isn't in that feature's own data. Right now two notices wait in fact-checked, including the exp utility from the front page, and XMLType and VECTOR have gone all the way to certified.
  • Certify. This is a human action. The desk's Certify button publishes the document and then fires the workflow's certify. Un-certify fires retract.
  • Freeze guard. While a notice sits in certified, a guard (!delta::changedAny((obituary))) refuses edits to the obituary. That's why certified deliberately keeps a retract exit: a stage with no way out ends the instance, and its guard with it.

What went wrong: the engine rejects drafts. ids as the subject (so the fact check reads the draft itself), an omitted optional action parameter crashed a field write (the bench caught it before deploy), and a leftover field would have re-routed a returning notice.

And the honest limit: this is early access (0.x), and per the docs guards are advisory. The Content Lake doesn't enforce them yet, and my App SDK desk doesn't read them. The workflow records the gate; it doesn't yet enforce it. The other 46 certified notices were certified before the workflow existed and have no instances.

Sanity Project Details

Agent Session

Two episodes from the build, as recorded by Claude Code. Curated excerpts; local paths anonymized, credentials and unrelated local files removed.

The invisible seed and the certify-all decision (steps 2 and 4 above):

Legacy Obituaries: the invisible seed and the certify-all decision claude-fable-5-1
You

registered in Sanity

Agent

Good. Let me check what's already in the env file and see which of the setup steps remain.

Agent
Agent

The script is ready. Let me check whether the CLI login has already happened so I can run it right away.

Agent
Agent

Not logged in yet, so I'm blocked on that one interactive step. Run it in the prompt:

! cd [REDACTED]/sanity-challenge/ora2az/studio && npx sanity login

It opens the browser for GitHub OAuth. As soon as it completes, tell me and I'll run the project-creation script, deploy the schema, seed the 445 documents, and deploy the Studio, then hand you the three remaining Manage clicks with exact links.

Agent

The CLI needs the provider named when it isn't running in a full terminal. Run it with the GitHub provider:

! cd [REDACTED]/sanity-challenge/ora2az/studio && npx sanity login --provider github --no-open

The --no-open flag makes it print the login URL instead of trying to launch a browser from this session. Open that URL, approve in GitHub, and the CLI will store the credential. Then tell me and I'll run the project setup.

Agent

Login succeeded. Running the project setup now: create the project, make the dataset public, mint the seed token, and write the env files.

Agent
Agent
Agent

The organization "Uptime Architect" now exists on your personal account. Running the full chain: project creation, schema deploy, seed of 445 documents, public-query check, then Studio deploy.

Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent

Sanity is live. Your project id is udyjvgsk, the organization is "Uptime Architect" (o8wfejrgc), the dataset is public with all 445 documents queryable, the Studio is at https://ora2az.sanity.studio, and the obituary site renders every route from live data.

One defect worth knowing about, now fixed and logged: Content Lake treats a dot in a document id as a path prefix, so the first seed wrote all 445 documents invisibly. Ids are now stored as type_slug, and I recreated the dataset to purge the hidden copies.

Three clicks only an org admin can do in the browser. I could not find API equivalents.

  1. Enable Context. Open https://www.sanity.io/manage/organization/o8wfejrgc, go to Labs, turn on Context, and opt into Knowledge Bases. Note whether Workflows appears there too.
  2. Org token. Same organization page, API → Tokens, create a token with the Context Viewer role. Paste it as SANITY_ORG_TOKEN= in ~/.config/ora2az/env.
  3. MCP endpoint. Open the Dashboard at https://www.sanity.io/@o8wfejrgc, open the Context app, create a new MCP endpoint named exactly ora2az-groq on project ora2az, dataset production, published perspective.

Tell me when those are done and I'll run the first live agent query through the endpoint, then build the Knowledge Base.

One decision for you, not urgent: the posts, the cover images and one source document point at a public GitHub repo pyaroslav/ora2az. Say the word and I'll create it and push the eleven commits, or tell me to hold.

You

give me link that I need to open to read/certify

Switched to claude-opus-5-5
Agent

Open the desk here:

https://www.sanity.io/@o8wfejrgc/application/mnuftqiwykngiwbua6tj9xrr

The desk shows each draft's status and a Certify button, but not the obituary text itself. To read a draft before certifying, open that feature in the Studio: https://ora2az.sanity.studio. Go to Oracle feature and pick one, and the obituary field shows the draft text. Then return to the desk and click Certify, which publishes it. The obituary then appears on https://ora2az.vercel.app within about a minute.

You

why do I need to certify? do I need to certify just one? can you do certification?

Agent

Why certify? The 50 obituaries exist only as drafts. The public site reads published documents only, so no obituary prose shows there yet. Everything else on each page already shows, because it comes straight from the published graph: dates, survivors, disputes and sources. Certifying publishes one draft.

The gate is there on purpose. The text is AI-written, even though it was limited to each feature's own data. A human reading it before it goes public is also a point in the Path Two story.

How many? The challenge doesn't require any. For the demo and the post, a handful is enough. I'd suggest 5 to 10 features you know well, such as Oracle Streams, DBMS_JOB, the non-CDB architecture and traditional auditing. Uncertified pages still work, just without the prose paragraph.

Can I do it? Yes. I can publish drafts directly through the Sanity API, with the same effect as the Certify button: set the status to certified and publish. Two things to weigh:
- Anything I publish goes public without your read-through. I did spot-check 3 of the 50, and they were accurate.
- The Path Two post currently says an editor certifies each notice. If I publish all of them, I'll reword that line so it stays true.

Which do you want?
- (a) I certify a named handful. Tell me which, or I'll pick 8.
- (b) I certify all 50 and adjust the post wording.
- (c) You certify in the desk yourself, which keeps the human-review story exactly as written.

You

I know all well as this is my blog, shall we certify all?

Agent

Yes, let's certify all 50. It's your material, so you're the right reviewer. Before publishing, I'll run a quick automated check on every draft: any Oracle release or ORA- code in the prose must also appear in that feature's own data. That catches the most likely kind of AI slip before it goes public.

Agent
Agent
Agent
Agent
Agent
Agent

DBMS_JOB is live with its obituary and certified mark. The others are still inside their 60-second cache window, so I'll wait for all of them.

Agent
Agent

All 50 obituaries are certified and live. All 50 pages on https://ora2az.vercel.app now show the obituary and the "certified by the mortician" mark.

Before publishing, a script checked every draft for Oracle releases or ORA- error codes that weren't in that feature's own data. It flagged none. Each certification then set the status, published the text, and removed the draft in one step. Sanity reports 50 certified.

I updated the Path Two draft so it stays accurate. It now describes the automated check and says you certified all 50 in one pass because you know the material first-hand. The desk's Certify button remains the path for anything new.

Still yours to do:
- Take a screenshot of the desk's "Certified" tab for the post: https://www.sanity.io/@o8wfejrgc/application/mnuftqiwykngiwbua6tj9xrr
- Resolve the remaining <CONFIRM/EDIT> markers in both drafts: your opening lines, whether to name the coding agent, and the agent session section.
- Publish Path One on Friday, Oct 2, and Path Two on Saturday, Oct 3.

Building the notice-lifecycle workflow (step 6), by a helper agent working from a written brief:

Open the workflow-building session (linked rather than embedded: its package names read as @-mentions to DEV).


Sources are public only: Oracle documentation, Microsoft Learn, community documentation, and my own public blog and labs. — Yaro

Top comments (2)

Collapse
 
jashanpreet_kaur_917e774f profile image
JASHANPREET KAUR •

The obituary format is such a good fit for deprecated features, it makes a dry migration list actually readable. I liked that each notice says which Azure service "carries on" its work instead of just declaring it dead.

The "invisible seed" bug made me laugh because I hit the exact same thing. A dot in my document IDs made them disappear from the public dataset, and it took me a while to realise that's how drafts. works.

Curious: did the Workflows guards ever stop you from doing something you actually needed to do, or did they feel helpful the whole time?

Collapse
 
uptimearchitect profile image
Uptime Architect •

Thank you! "Survived by" was the whole idea: a migration checklist reads differently when it names who carries on, not just what died.

And the dot in _id seems to be a rite of passage. 445 documents "created", zero visible. Glad I'm not the only one.

Honest answer on guards: they never stopped me, because in the current early access they can't yet. Guards are advisory. The Content Lake doesn't enforce them, and my App SDK desk doesn't read them, so the freeze on a certified obituary is recorded rather than enforced. Where they did shape things was the design. A stage with no way out ends the instance, and its guard with it, so certified keeps a retract exit just to keep the freeze alive. What actually pushed back was the engine itself: it won't take a drafts. id as the subject, so the fact check reads the draft separately. If I take it further, the desk will check the guard before it enables editing.