What this educational system demonstrates
This Blueprint describes a reusable pattern for evidence-grounded bilingual content operations. Scheduled jobs discover demand, compare existing pages, gather verifiable sources, draft both locales, enforce independent policy gates, publish automatically only when every signal passes, and keep measuring each page. The records and identifiers are fictional examples, and the design is not a description of Ting’s private systems.
Included
- Demand discovery with existing-content deduplication
- Evidence records linked to every factual clause
- Paired English and Arabic revisions
- Automatic publication, verification, monitoring and lifecycle actions
Not included
- Ting’s production architecture or provider choices
- Private prompts, scoring rules or internal thresholds
- Real customer, analytics or credential data
- A guarantee of rankings, traffic or revenue
Resumable architecture and state machine
A small state machine defines legal transitions, while a scheduler advances one bounded step per invocation. Durable storage holds leases, evidence, decisions and retries so interrupted work resumes safely. This is one educational pattern; teams should adapt the states and limits to their own risk, volume and platform.
View Mermaid source
flowchart LR
T["Scheduled Trigger"] --> A["Discovery & Eligibility"]
A --> B["Evidence Research"]
B --> C["Bilingual Brief & Drafts"]
C --> D["Claim, Quality & SEO Gates"]
D --> E["Publish & Verify"]
E --> F["Monitor & Lifecycle"]
F -- "refresh / merge / noindex" --> BView Mermaid source
stateDiagram-v2
[*] --> DISCOVERED
DISCOVERED --> ELIGIBILITY_CHECK
ELIGIBILITY_CHECK --> CLUSTERING
CLUSTERING --> RESEARCHING
RESEARCHING --> EVIDENCE_READY
EVIDENCE_READY --> BRIEF_GENERATING
BRIEF_GENERATING --> DRAFTING
DRAFTING --> CLAIM_VALIDATION
CLAIM_VALIDATION --> QUALITY_VALIDATION
QUALITY_VALIDATION --> SEO_VALIDATION
SEO_VALIDATION --> READY_TO_PUBLISH
READY_TO_PUBLISH --> PUBLISHING
PUBLISHING --> PUBLISHED
PUBLISHED --> MONITORING
CLAIM_VALIDATION --> REPAIRING: unsupported claim
SEO_VALIDATION --> REPAIRING: gate failed
REPAIRING --> DRAFTING: bounded retries
MONITORING --> REFRESH_REQUIRED: decay detected
REFRESH_REQUIRED --> RESEARCHING: refresh cycle
DRAFTING --> FAILED_RETRYABLE: provider error
FAILED_RETRYABLE --> DRAFTING: backoff resumeNamed reference stack
The example uses GitHub for version control, Postgres for workflow and evidence state, OpenRouter as a server-side model gateway, and a Web Hoster / Cloud Infrastructure for the application and schedules. These are educational reference choices, not claims about Ting’s production stack.
GitHub
Reference version control and CI for code, policy fixtures and deployment history.
Web Hoster / Cloud Infrastructure
Application runtime, scheduled triggers, secret injection, health checks and rollback.
Postgres
Illustrative durable store for topics, evidence, immutable revisions, decisions and lifecycle signals.
OpenRouter
An educational server-side model gateway choice with schema-constrained output, timeouts and fallback policy.
Scheduled Jobs + Application Functions
The reference runs discovery and worker schedules at configurable cadences; each tick performs one bounded step and reserves time to persist safely.
Reference repository, schedules and setup
The example keeps web routes and the content worker in one repository so contracts and tests evolve together. Discovery and worker schedules are illustrative: choose a cadence and runtime budget that match your own demand, provider limits and recovery objectives.
reference-seo-system/
app/api/cron/content/
discovery/route.js # scheduled opportunity discovery
worker/route.js # advance one due workflow step
app/blog/[slug]/page.js # render published articles
src/seo/
orchestrator.js # lease a workflow and run one bounded step
state-machine.js # legal transitions for the reference flow
repository.js # leases, budgets and circuit breakers
discovery.js # demand discovery, scoring and deduplication
research.js # evidence retrieval and verification
structured-output.js # schema-constrained model calls
policy.js # automatic publication and lifecycle gates
monitoring.js # outcome checks and lifecycle signals
search-console.js # indexing and performance measurements
*.test.js # regression suites beside the modules
hosting-config.example # runtime schedules and resource limits# Educational reference dependencies. Choose versions that match
# your application and review their official documentation.
npm install next react react-dom pg
# pg -> reference Postgres repository
# Hosting -> deploy to a Web Hoster / Cloud Infrastructure# .env.example — placeholder values only; never commit real secrets
DATABASE_URL=postgres://user:password@host:5432/database
MODEL_GATEWAY_API_KEY=replace_with_server_side_secret
CONTENT_CRON_SECRET=replace_with_random_bearer_token
CONTENT_DAILY_NEW_PAGE_LIMIT=replace_with_integer
CONTENT_MAX_MODEL_CALLS_PER_WORKFLOW=replace_with_integer
CONTENT_POLICY_VERSION=replace_with_version_identifierTopics, workflows, evidence and results
Reference tables persist each topic, source, validation result, transition and lifecycle signal. Nothing depends on a chat transcript. Use immutable revision records, idempotency keys and an audit trail so an automatic action can be explained, retried or rolled back.
-- Illustrative reference schema; adapt names to your system.
create table content_topics (
id uuid primary key,
query text not null,
locale text check (locale in ('en','ar')),
intent text,
canonical_topic text,
priority_score numeric
);
create table content_workflows (
id uuid primary key,
topic_id uuid references content_topics(id),
current_state text not null,
intended_action text,
retry_count int default 0,
failure_category text,
idempotency_key text unique,
locked_at timestamptz,
next_review_at timestamptz
);create table content_evidence_sources (
id uuid primary key,
workflow_id uuid references content_workflows(id),
url text not null,
publisher text,
retrieved_at timestamptz,
excerpt text,
verification_status text -- verified | retired
);
create table content_validation_results (
workflow_id uuid,
stage text, -- CLAIM | QUALITY | SEO | PUBLICATION
decision text, -- pass | repair | reject
details jsonb
);
-- Every factual clause must map to retrieved evidence.
-- Unsupported clauses route to REPAIRING, never to publication.// src/seo/state-machine.js — educational reference example
export const WORKFLOW_STATES = Object.freeze([
"DISCOVERED", "ELIGIBILITY_CHECK", "CLUSTERING",
"EXISTING_CONTENT_CHECK", "RESEARCHING", "EVIDENCE_READY",
"BRIEF_GENERATING", "BRIEF_READY", "DRAFTING", "DRAFTED",
"CLAIM_VALIDATION", "QUALITY_VALIDATION", "SEO_VALIDATION",
"REPAIRING", "READY_TO_PUBLISH", "PUBLISHING", "PUBLISHED",
"MONITORING", "REFRESH_REQUIRED", "MERGE_REQUIRED",
"REDIRECT_REQUIRED", "NOINDEX_REQUIRED", "REJECTED",
"FAILED_RETRYABLE", "FAILED_FINAL"
]);
assertTransition("DRAFTED", "CLAIM_VALIDATION"); // allowed
assertTransition("DRAFTED", "PUBLISHED"); // throws// A scheduler on your Web Hoster / Cloud Infrastructure invokes
// this worker. One lease, one bounded step, then release.
export async function runContentWorker() {
const workflow = await claimNextDueWorkflow();
if (!workflow) return { ok: true, idle: true };
try {
await advanceOneStep(workflow);
} catch (error) {
await recordFailure(workflow, error); // backoff + circuit breaker
}
return { ok: true, workflowId: workflow.id };
}Clustering and existing-content checks
Before drafting, compare locale, search intent, canonical topic, query overlap and content similarity against every eligible page. The deterministic outcome is create, refresh, merge or reject. A new URL is allowed only when it serves a distinct intent that an existing page cannot satisfy.
createNo strong page covers the same locale and intent.
refreshOne relevant page exists but coverage is partial or stale.
mergeSeveral pages compete for the same intent.
rejectExisting content is strong or the opportunity is ineligible.
// Compare locale, intent, canonical cluster and similarity
// before drafting. This function is deterministic and testable.
export function decideIntendedAction({ topic, livePages }) {
const sameCluster = livePages.filter((page) =>
page.locale === topic.locale &&
page.canonicalTopic === topic.canonicalTopic
);
if (sameCluster.some((p) => p.coverage === "strong")) return "REJECT_TOPIC";
if (sameCluster.some((p) => p.coverage === "partial")) return "REFRESH_EXISTING";
if (sameCluster.length > 1) return "MERGE_INTO_EXISTING";
return "CREATE_NEW";
}Research and exact-claim grounding
Store retrieved sources before writing. The writer may use only supported excerpts, and a separate verifier maps every factual clause back to exact evidence. Missing, stale or contradictory support sends the revision to repair or rejection; model labels cannot bypass the ledger.
// Re-extract every factual clause and verify the exact text
// against stored evidence instead of relying on model memory.
export async function validateClaims(workflowId, draft) {
const evidence = await getVerifiedEvidence(workflowId);
return extractClaims(draft).map((claim) => ({
...claim,
status: evidence.some((row) =>
claim.evidenceIds.includes(row.id) &&
supportsExactClause(row.excerpt, claim.text)
) ? "supported" : "unsupported"
}));
}- Allow official and primary sources according to policy.
- Persist source title, retrieval time and excerpt.
- Distinguish an unavailable source from an unsupported claim.
- Never allow the model to invent a URL or evidence ID.
Bilingual brief and drafting
One evidence-backed brief produces native English and Arabic revisions in the same translation group. Arabic is written naturally for Saudi readers while preserving the same supported facts, intent boundaries, internal-link purpose, canonical relationship and hreflang pairing.
Shared brief
Intent, audience, evidence, boundaries and required links.
Two native drafts
Each locale is written for its readers under the same claim boundaries.
Locale pairing
Each version carries correct canonical and hreflang relationships.
Drift review
Compare claims, numbers and promises across both locales.
Signal-gated validation and publication
Deterministic checks and role-separated model reviews evaluate evidence coverage, quality, duplication, metadata, links, structured data and locale parity. Publication proceeds automatically only when every required signal passes. A disagreement blocks, repairs or rejects the revision; no manual queue is part of the publishing path.
{
"workflow_id": "wf_reference_topic_en",
"current_state": "SEO_VALIDATION",
"intended_action": "CREATE_NEW",
"locales": ["en", "ar"],
"gates": {
"claims": "pass",
"quality": "pass",
"seo": "pending",
"publication_policy": "pending"
},
"retry_count": 0,
"failure_category": null,
"publishable": false
}Automatic monitoring, refresh, merge and noindex
Fresh Search Console and indexation measurements drive recurring lifecycle checks. Decay, overlap or loss of independent value can queue a refresh, merge, redirect or noindex action automatically, but only after minimum sample, confidence, destination-health and rollback gates pass. The system never defaults to the older URL.
keep
Content remains useful, accurate and distinct.
refresh
Evidence, coverage or performance needs an update.
merge
Multiple pages compete and should be consolidated.
noindex
The page no longer provides independent value.
Scheduled endpoints and failure behavior
Protect scheduled routes with a server-side secret and return structured results. Classify retryable failures, use bounded backoff and circuit breakers, reserve time for persistence, and cap daily work. A timeout or provider outage must stop safely without publishing a partial revision or consuming an unrelated retry budget.
// app/api/cron/content/worker/route.js — simplified reference
export async function GET(request) {
const token = request.headers.get("authorization");
if (token !== "Bearer " + process.env.CONTENT_CRON_SECRET) {
return Response.json({ error: "unauthorized" }, { status: 401 });
}
const result = await runContentWorker();
return Response.json(result);
// A revision is published automatically only after every policy signal
// passes and the public URL is verified. Otherwise it repairs or stops.
}Tests beside the reference modules
Test legal transitions, evidence coverage, demand filtering, bilingual parity, publication rollback and lifecycle thresholds. Evaluation fixtures should include unsupported claims, prompt injection, DNS changes, stale measurements, duplicate intent, partial bilingual writes and failed public verification.
// Illustrative regression cases for the reference implementation.
const cases = [
["illegal state transition", "throws"],
["unsupported factual clause", "REPAIRING"],
["duplicate intent detected", "MERGE_REQUIRED"],
["provider fails repeatedly", "circuit_breaker_open"],
["all publication signals pass", "PUBLISHED"],
["public URL verification fails", "automatic_rollback"],
["overlap exceeds merge threshold", "automatic_merge_queued"],
["lifecycle evidence is incomplete", "action_blocked"]
];
test.each(cases)("%s -> %s", async (scenario, expected) => {
expect(await runFixture(scenario)).toEqual(expected);
});Create, refresh, merge or reject matches the expected fixture.
Share of factual clauses linked to valid evidence.
No changed numbers, promises or meaning between versions.
Zero publications before all policy gates and public verification pass.
Web hosting, persistence and rollback
Run the application on a Web Hoster / Cloud Infrastructure with injected secrets, health checks, rate limits and monitored schedules. Keep durable state outside process memory, deploy immutable revisions, retain the last healthy version, and rehearse automatic rollback before enabling unattended publishing.
Durable state
Persist jobs, transitions, evidence and policy decisions outside process memory.
Bounded retries
Use idempotency keys, backoff and a dead-letter queue instead of open retries.
Observability
Track stage latency, cost, gate failures and job age.
Rollback
Keep the prior version, document rollback and reverify the public URL.
Operational ownership
Assign policy, publishing and incident owners without making routine publication wait on a manual queue.
Security and intentional exclusions
Treat source pages as untrusted input, pin outbound evidence requests to validated HTTPS destinations, keep model and database credentials server-side, redact logs, and separate retrieval, publishing and lifecycle permissions. This Blueprint intentionally excludes Ting’s prompts, private integrations, production thresholds and security implementation details.
Least privilege
Separate source-reading permissions from publishing and lifecycle actions.
Untrusted input
Sanitize HTML and source instructions before model use.
Server secrets
Never expose keys or traces to the browser.
Request boundaries
Limit job rate, size and duration.
Safe logs
Redact secrets, personal data and private content.
Guardrailed autonomy
Do not refresh, merge or noindex until signal thresholds and rollback checks pass.
