Articles / Viewpoints and methods
6 minFor system builders

Building an AI Content Workflow Platform, Part 2: Turning Model Integration into a System Specification

A real project breakdown of how a software PM turned model integration into contracts for data lineage, Job lifecycle, readiness, human decisions and private Connector boundaries.

Aaron HuangSystems, product and AI practice

The specification most often missing from an AI product is not the prompt. It is the data and responsibility around the model call. If the source version, work state, failure reason or human confirmation is undefined, “AI integration” is still a technical action rather than an acceptance-ready product capability.

Part 1 reduced the Content Workflow Platform MVP to one workflow that could be accepted. This article continues from that decision. When one step is handed to AI, the PM needs four additional contracts before the model becomes part of the system rather than a disconnected endpoint.

Layer 1: A decision contract defines what AI may decide

The platform did not begin with one shared Generate button. AI was split into two jobs:

source_to_plan
→ produce three candidate directions
→ the user selects one direction
→ draft_deliverable
→ produce candidate content for that direction

This added a step compared with generating a complete article in one call, but it preserved the product decision that mattered: the model could propose options, but it could not decide which direction was worth continuing.

Layer 2: A data contract lets every result return to its source

If each call simply sends the text currently visible in the editor, it becomes difficult to answer basic questions later: which source revision was used, which guidance version was applied, which Job produced the result and whether an old result can still be explained after the source changes.

The project therefore separated the data into a traceable chain:

SourceRecord
→ immutable Raw Snapshot / Raw Artifact
→ versioned Context Manifest
→ AI Job + Result receipt
→ Candidate Artifact
→ human-edited Deliverable
→ Manual Publication Record

Raw Artifact preserves the original content and its hash. Context Manifest records the version of the material allowed into the model context. The Job receipt records execution state and failure reason. Candidate Artifact preserves the model's original candidate. Only after the user edits and saves it does the content become an authored Deliverable.

This lineage makes each result traceable to its source and prevents a model output from being stored as if it were the same thing as a human decision.

Model output and human-approved content cannot be the same record

If a model response goes straight into an editor and is saved as the same record, the system cannot distinguish model output from content that a person has reviewed and accepted responsibility for.

The project therefore keeps the original Candidate. A user may bring it into the editing area, but selection, changes and saving are what form the authored Deliverable. Copying text to the clipboard does not publish it. The platform records manual publication separately.

That distinction produces three direct benefits:

  • a failed retry does not overwrite the last successful candidate;
  • a reload can reconstruct the candidate source and the current edited content; and
  • a successful model call cannot be mistaken for approved or published content.

Layer 3: An execution contract handles interruption, stuck states and reloads

The first end-to-end browser acceptance did not show that the model could never respond. It showed that an AI Job passes through more states during real use than a simple request-and-response diagram suggests.

Background refreshes could reset the stage a user was viewing. If a Job was not saved as running before the call, closing the browser could leave an unexplained queued state. Without a browser timeout, the interface could remain locked. A successful result also had to return to the correct platform editor after reload.

The corrected rules were:

  • save running before calling the model;
  • turn a queued or running Job that has been interrupted too long into an explicit failure;
  • give the browser request a bounded wait instead of locking the interface indefinitely;
  • save the result with its target platform and hydrate it into the correct field after reload; and
  • preserve the failure reason and retry entry point without silently clearing the last successful result.

Those states are part of the AI feature specification. “Integrate the model API” does not describe any of them.

Current readiness and the last successful Job answer different questions

Later UX acceptance found another problem. When the service was not ready, the interface could still show the receipt from a previous successful Job. Both messages were true, but at the same level they made it unclear whether the system was unavailable now or had succeeded before.

The interface separated them:

  • Current readiness answers whether a new Job can be created now.
  • Last Job receipt answers what happened during the previous Job.

When no Job is running, the interface should not show “Stop AI Job.” When the service is not ready, the action should return a concrete reason instead of leaving an unexplained disabled button.

This principle applies beyond AI. Any feature that depends on an external service should separate current availability from historical results.

Layer 4: The system boundary should not be owned by a private model service

The completed platform uses a private model service, but the product core does not depend on that provider. Source, Plan, Deliverable, Asset, Review and Today belong to the generic core. The model endpoint, private connection and credentials stay inside a local Connector boundary.

That separation handles practical risks:

  • server-only keys do not enter the browser or public code;
  • core data and historical results remain readable when the Connector is unavailable;
  • a paid fallback or automatic retry does not hide a connection problem; and
  • replacing the model service does not require rewriting the product data model.

The completed version remains loopback-only, with no account system, public service or automatic publishing. These are not forgotten features. They are the operating boundary deliberately kept for this version.

Connecting the two parts: define the work before defining AI's participation

Part 1 handled the problem, scope and acceptance boundary: what to build. Part 2 handled data, execution, responsibility and system boundary: how AI may participate. Together they form a complete software PM path for an AI product project.

When a requirement says “integrate AI,” I would use these six questions:

  1. Which source and Context version did the model read?
  2. Which states can the Job enter, and what happens on interruption, timeout or reload?
  3. How does the result connect back to the source, Job, target platform and user choice?
  4. Is the model output a Candidate or a human-confirmed Deliverable?
  5. When the model service is unavailable, how does the interface explain it, and can old data still be used?
  6. Which credentials, costs and external side effects must be isolated or prohibited?

Without Part 1, these questions have no product workflow to attach to. Without Part 2, the acceptance conditions from Part 1 cannot reach real AI behavior. The two parts turn AI from an endpoint that returns text into a product capability that can be operated, tested and recovered after failure.

Previous: Building an AI Content Workflow Platform, Part 1: Turning an Ambiguous Idea into a Verifiable MVP