From 143e65fd57c4193eda71ac535291cd56b56fc56a Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 15:54:31 +0000 Subject: [PATCH] feat(use-cases): readiness tier on every scenario card, build-checked Each /use-cases/ scenario now states how far it is from running, from a closed set: today (works on the platform today), integration (needs a connection to a system you run), rule (needs the business rule written down first). - Data: one `readiness` per scenario in en and zh-Hans, the same tier in both. Tiers come from evidence: none of the ten linked posts or templates shows its scenario running on the shipped platform (the posts are prescriptive; the templates ship their AI as bring-your-own-LLM stubs), so no card is `today`: six are `integration`, four are `rule`. - Type: `SCENARIO_READINESS` closed list; `readiness` required. - UI: labels and a legend lead-in for en and zh-Hans (zh-Hant derived, other locales fall back to English). - Render: a plain chip under each card title with a token-coloured dot, and a one-line legend under the metrics. - Build: a missing or unknown value fails astro build, in the same loop that checks each scenario's post, template and guide. The home page's scenario cards come from MarketingHome, not this component, and are left untagged. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01FeA1nwBz1ohH65dvffUGKr --- content/pages/en/use-cases.ts | 13 +++++ content/pages/zh-Hans/use-cases.ts | 12 ++++ src/components/MarketingEvidencePage.astro | 66 +++++++++++++++++++++- src/content-pages/types.ts | 16 ++++++ src/content-pages/ui.ts | 22 ++++++++ 5 files changed, 128 insertions(+), 1 deletion(-) diff --git a/content/pages/en/use-cases.ts b/content/pages/en/use-cases.ts index c40fd42..572bb6a 100644 --- a/content/pages/en/use-cases.ts +++ b/content/pages/en/use-cases.ts @@ -3,6 +3,9 @@ import type { MarketingPage } from '../../../src/content-pages/types'; // One card per existing scenario post, grouped by business team (ruling on // #359, 2026-11-04). Each card summarizes its post and claims nothing the post // does not say; the post, template and guide links are checked at build time. +// `readiness` (#370) is taken from evidence, not optimism: `today` only where +// the linked template or post shows the scenario running on the shipped +// platform; in doubt, the more conservative tier. zh-Hans carries the same tiers. const page = { slug: 'use-cases', navLabel: 'Use cases', @@ -44,6 +47,7 @@ const page = { body: 'Reps fill in CRM fields after the selling is done, while the real context sits in meetings, emails, notes and follow-up promises.', scenario: { post: 'ai-sales-assistant', + readiness: 'integration', guide: 'crm-case-management-ai', withAi: 'Reps update by voice or text. AI summarizes meetings, picks out next steps, surfaces deal risk, suggests stage changes and preps the next account meeting.', approves: 'The rep confirms each suggested CRM change, and customer-facing commitments need confirmation. Managers set the risk rules and approval boundaries.', @@ -62,6 +66,7 @@ const page = { body: 'A long email or a frustrated chat becomes a record that waits for someone to read, classify, search, reply and escalate.', scenario: { post: 'ai-ticket-hub', + readiness: 'integration', template: 'helpdesk', withAi: 'AI classifies each issue, detects urgency and sentiment, matches knowledge articles, drafts replies with citations and ranks cases by SLA.', approves: 'Agents confirm drafts, routing and case updates. Refund, compensation and contract-promise replies can be set to wait for a manager’s approval; escalations are created only after permission checks.', @@ -80,6 +85,7 @@ const page = { body: 'OCR fills in the fields, but finance still judges by hand whether a claim is in policy, in budget, project-related and not a duplicate.', scenario: { post: 'ai-expense-audit', + readiness: 'integration', withAi: 'AI extracts receipt data, checks policy, budget, project and duplicate invoices, ranks the claims to review first and cites the policy line behind each finding.', approves: 'AI recommends; payment approval follows a clear authority chain, high-risk claims route to finance review, and reviewer corrections are recorded.', }, @@ -89,6 +95,7 @@ const page = { body: 'Supplier risk is spread across systems: expiring certificates, slipping delivery, unusual pricing, contract gaps and quality returns.', scenario: { post: 'ai-procurement-risk', + readiness: 'integration', template: 'procurement', withAi: 'Before an order is placed, AI checks qualifications and delivery, compares the quote with history, surfaces quality and contract issues and suggests alternatives.', approves: 'AI does not make the buying decision: procurement approves with the risk explanation in front of it, and review outcomes feed back into supplier governance.', @@ -107,6 +114,7 @@ const page = { body: 'Employees need a VPN, a laptop, leave or a policy answer, and the portal makes them find the right HR, IT, admin or finance form first.', scenario: { post: 'ai-employee-service-center', + readiness: 'rule', template: 'hr', withAi: 'AI splits one message into the right service requests, pre-fills the employee’s context, answers policy questions from the knowledge base and routes fulfilment tasks.', approves: 'Requests are created only through a governed service catalog; access, devices and reimbursements stay behind permissions and approvals, tracked in the same conversation.', @@ -125,6 +133,7 @@ const page = { body: 'The contract register is managed but the review is not: risk stays in attachments and comments, and approvers see too little context.', scenario: { post: 'ai-contract-risk', + readiness: 'rule', template: 'contracts', withAi: 'AI extracts parties, amounts, terms and non-standard clauses, compares them with the standard template and turns deviations into risk records.', approves: 'Legal confirms or edits every finding and owns the final opinion. High-risk findings go to approval, and signed obligations become follow-up tasks.', @@ -135,6 +144,7 @@ const page = { body: 'Compliance teams align policy text with evidence scattered across IAM, contracts, procurement, logs, workflows and spreadsheets — by hand.', scenario: { post: 'ai-compliance-control', + readiness: 'integration', template: 'compliance', withAi: 'AI parses policies into controls, matches evidence, explains why a gap is high risk and suggests remediation tasks.', approves: 'Responsible owners confirm high-risk findings and evidence requirements; remediation and its confirmation stay in the audit history.', @@ -153,6 +163,7 @@ const page = { body: 'Risk hides in meeting notes, task updates, weekly reports, change requests and resource conversations until a milestone slips.', scenario: { post: 'ai-project-risk-assistant', + readiness: 'rule', template: 'project', withAi: 'AI links notes to tasks and milestones, detects blockers, dependency and resource conflicts, creates risk records with suggested actions and answers health questions.', approves: 'AI detects and explains; commitments stay human decisions. Managers turn accepted risks into action plans; a rule can hold scope changes until their impact is assessed.', @@ -171,6 +182,7 @@ const page = { body: 'AI may speed up one draft, but ideas, sources, review comments, the publishing calendar and retrospectives stay scattered.', scenario: { post: 'ai-content-workbench', + readiness: 'integration', template: 'content', withAi: 'AI clusters source material into topics, writes briefs with audience and evidence, highlights claims that lack support and summarizes performance after publishing.', approves: 'Drafts route to brand, product, legal or customer-success review before publishing, and review comments and approvals are structured records.', @@ -181,6 +193,7 @@ const page = { body: 'An assistant answers the question, then the user still opens the business system to create tasks, start approvals, update records and leave an audit trail.', scenario: { post: 'ai-agent-workbench', + readiness: 'rule', withAi: 'The agent turns a goal into a visible plan and calls governed tools: it queries records, creates tasks, starts approvals and generates reports.', approves: 'It checks the user’s access before querying data, asks before creating tasks, gates high-risk actions with approval and records each tool call and result.', }, diff --git a/content/pages/zh-Hans/use-cases.ts b/content/pages/zh-Hans/use-cases.ts index 9d3704c..ab8753a 100644 --- a/content/pages/zh-Hans/use-cases.ts +++ b/content/pages/zh-Hans/use-cases.ts @@ -2,6 +2,8 @@ import type { MarketingPage } from '../../../src/content-pages/types'; // 每张卡对应一篇已有的场景文章,按业务团队分组(#359 裁决,2026-11-04)。 // 卡片只概括文章已写的内容;文章、模板与专题链接在构建时校验。 +// `readiness`(#370)按证据定档:只有链接的模板或文章演示了在已发布平台上运行, +// 才标 `today`;拿不准时取更保守的一档。与英文版逐卡同档。 const page = { slug: 'use-cases', navLabel: '使用场景', @@ -43,6 +45,7 @@ const page = { body: '销售在事情办完之后才去填 CRM 字段,真正的上下文留在会议、邮件、笔记和跟进承诺里。', scenario: { post: 'ai-sales-assistant', + readiness: 'integration', guide: 'crm-case-management-ai', withAi: '销售用语音或文字更新进展。AI 整理会议纪要、识别下一步动作、提示商机风险、建议阶段变更,并为下一次客户会议做准备。', approves: '每条 CRM 变更建议由销售本人确认,面向客户的承诺需要确认。风险规则和审批边界由主管设定。', @@ -61,6 +64,7 @@ const page = { body: '一封长邮件或一段不满的对话变成一条记录,然后等人去读、分类、查资料、回复和升级。', scenario: { post: 'ai-ticket-hub', + readiness: 'integration', template: 'helpdesk', withAi: 'AI 识别问题类型、紧急程度和客户情绪,匹配知识库,起草带引用的回复,并按 SLA 给工单排序。', approves: '回复草稿、分派和工单更新由客服确认。退款、补偿和合同承诺类回复可设为须主管审批后才能发出;升级任务只在权限校验通过后创建。', @@ -79,6 +83,7 @@ const page = { body: 'OCR 能把字段填上,但报销是否合规、是否在预算内、是否与项目相关、有没有重复,财务仍要人工判断。', scenario: { post: 'ai-expense-audit', + readiness: 'integration', withAi: 'AI 提取票据信息,核对政策、预算、项目和重复发票,排出今天优先要审的报销单,并给出每条发现依据的政策条款。', approves: 'AI 只给建议;付款审批走清晰的授权链,高风险报销转财务复核,复核人的修正会被记录。', }, @@ -88,6 +93,7 @@ const page = { body: '供应商风险分散在多个系统里:资质快到期、交付变慢、报价异常、合同缺口、质量退货。', scenario: { post: 'ai-procurement-risk', + readiness: 'integration', template: 'procurement', withAi: '下单之前,AI 核对资质和交付表现,把报价与历史对比,列出质量和合同问题,并建议替代方案。', approves: 'AI 不替你做采购决定:采购在看到风险说明之后再审批,复核结果回流到供应商管理。', @@ -106,6 +112,7 @@ const page = { body: '员工要开 VPN、领电脑、请假或问一条政策,门户却要他们先在人事、IT、行政、财务里找到对的表单。', scenario: { post: 'ai-employee-service-center', + readiness: 'rule', template: 'hr', withAi: 'AI 把一句话拆成对应的服务请求,预填员工信息,用知识库回答政策问题,并把履约任务分派给对的团队。', approves: '请求只能经由受治理的服务目录创建;访问权限、设备和报销都在权限与审批之后,进度在同一段对话里跟踪。', @@ -124,6 +131,7 @@ const page = { body: '合同台账有人管,审查却没有:风险留在附件和批注里,审批人看到的上下文太少。', scenario: { post: 'ai-contract-risk', + readiness: 'rule', template: 'contracts', withAi: 'AI 提取签约方、金额、期限和非标准条款,与标准模板对比,把偏离变成风险记录。', approves: '每条发现由法务确认或修改,最终意见归法务。高风险发现进入审批,已签署的义务变成跟进任务。', @@ -134,6 +142,7 @@ const page = { body: '合规团队要手工把制度条文和散落在 IAM、合同、采购、日志、流程系统和表格里的证据对上。', scenario: { post: 'ai-compliance-control', + readiness: 'integration', template: 'compliance', withAi: 'AI 把制度拆成控制项,匹配证据,解释为什么某个缺口是高风险,并建议整改任务。', approves: '高风险发现和证据要求由责任人确认;整改及其确认都留在审计历史里。', @@ -152,6 +161,7 @@ const page = { body: '风险藏在会议纪要、任务更新、周报、变更请求和资源沟通里,直到里程碑滑期才被看见。', scenario: { post: 'ai-project-risk-assistant', + readiness: 'rule', template: 'project', withAi: 'AI 把纪要关联到任务和里程碑,识别阻塞、依赖和资源冲突,创建带建议动作的风险记录,并回答项目健康度问题。', approves: 'AI 负责发现和解释;承诺仍由人决定。经理把接受的风险转成行动计划;可以设规则让范围变更先做影响评估。', @@ -170,6 +180,7 @@ const page = { body: 'AI 也许能让一篇草稿写得更快,但选题、素材、评审意见、发布排期和复盘仍然散落各处。', scenario: { post: 'ai-content-workbench', + readiness: 'integration', template: 'content', withAi: 'AI 把素材聚成选题,写出带受众和论据的简报,标出缺少支撑的说法,并在发布后总结表现。', approves: '草稿发布前流转到品牌、产品、法务或客户成功评审;评审意见和审批都是结构化记录。', @@ -180,6 +191,7 @@ const page = { body: '助手回答了问题,用户却还得打开业务系统去建任务、发起审批、更新记录、留下审计痕迹。', scenario: { post: 'ai-agent-workbench', + readiness: 'rule', withAi: 'Agent 把目标变成一份看得见的执行计划,再调用受治理的工具:查询记录、创建任务、发起审批、生成报告。', approves: '查询数据前先校验用户权限,创建任务前先请求确认,高风险动作经审批,每次工具调用及其结果都被记录。', }, diff --git a/src/components/MarketingEvidencePage.astro b/src/components/MarketingEvidencePage.astro index 64e3023..03448b2 100644 --- a/src/components/MarketingEvidencePage.astro +++ b/src/components/MarketingEvidencePage.astro @@ -4,7 +4,7 @@ import heroImage from '../assets/objectos-home-hero.png'; import { getMarketingPage, getMarketingPages, marketingPagePath } from '../content-pages/registry'; import { clusterBySlug, clusterPath } from '../lib/clusters'; import { clusterCopy } from '../lib/cluster-i18n'; -import type { MarketingPage } from '../content-pages/types'; +import { SCENARIO_READINESS, type MarketingPage } from '../content-pages/types'; import { marketingPageUi } from '../content-pages/ui'; import { cardSpans } from '../lib/card-rows'; import { phraseHtml } from '../../scripts/lib/cjk-phrases.mjs'; @@ -67,8 +67,16 @@ for (const section of page.sections) { if (scenario.guide && !clusterBySlug(scenario.guide)) { throw new Error(`Scenario card ${where}: no guide (cluster) "${scenario.guide}"`); } + // Every card states how far it is from running (#370): exactly one of the + // closed set, so a scenario cannot ship without a stated tier. + if (!(SCENARIO_READINESS as readonly string[]).includes(scenario.readiness)) { + throw new Error( + `Scenario card ${where}: readiness "${scenario.readiness ?? ''}" is not one of ${SCENARIO_READINESS.join(' | ')}` + ); + } } } +const hasScenarios = page.sections.some((section) => section.items.some((item) => item.scenario)); const guideLink = (slug: string) => { const cluster = clusterBySlug(slug)!; return { href: clusterPath(locale, slug), label: clusterCopy(cluster, locale).shortTitle }; @@ -138,6 +146,15 @@ const ph = (text: string): string => phraseHtml(text, locale); ))} + {hasScenarios && ( +

+ {ui.scenario.readinessLegend} + {SCENARIO_READINESS.map((tier) => ( + {ui.scenario.readiness[tier]} + ))} +

+ )} +

{page.artifact.eyebrow}

@@ -166,6 +183,9 @@ const ph = (text: string): string => phraseHtml(text, locale); {section.items.map((item, index) => item.scenario ? (

{item.title}

+

+ {ui.scenario.readiness[item.scenario.readiness]} +

{ui.scenario.today}
@@ -613,6 +633,47 @@ const ph = (text: string): string => phraseHtml(text, locale); flex-direction: column; min-height: 0; } + /* Readiness (#370): a plain chip with a status dot, on each scenario card + and in the legend under the metrics. The label carries the meaning; the + dot only helps the eye match a card to the legend: green and amber are + status colours, the rule tier a hollow ring (indigo stays interaction). */ + .metrics:has(+ .readiness-legend) { + margin-bottom: 1.25rem; + } + .readiness-legend { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.5rem 0.75rem; + margin: 0 0 5rem; + color: var(--ink-soft); + font-size: var(--fs-14); + line-height: var(--lh-ui); + } + .readiness-chip { + white-space: normal; + } + .readiness-chip::before { + content: ''; + flex: none; + width: 0.5rem; + height: 0.5rem; + border-radius: var(--r-pill); + background: var(--muted); + } + .readiness-today::before { + background: var(--green); + } + .readiness-integration::before { + background: var(--amber); + } + .readiness-rule::before { + background: transparent; + box-shadow: inset 0 0 0 2px var(--muted); + } + .scenario .scenario-readiness { + margin: 0 0 0.9rem; + } .scenario dl { display: grid; gap: 0.7rem; @@ -876,6 +937,9 @@ const ph = (text: string): string => phraseHtml(text, locale); .metrics { margin-bottom: 3rem; } + .readiness-legend { + margin-bottom: 3rem; + } .metrics div { min-height: auto; } diff --git a/src/content-pages/types.ts b/src/content-pages/types.ts index 7852c51..5f24a5f 100644 --- a/src/content-pages/types.ts +++ b/src/content-pages/types.ts @@ -8,6 +8,20 @@ export interface MarketingPageAction { href: string; } +/** + * How far a /use-cases/ scenario is from running (#370), a closed set: + * - `today`: it works on the shipped platform, shown by its linked template + * or post; + * - `integration`: it needs a connection to a system the reader runs (e-mail, + * chat, OCR, ERP, quality, IAM, analytics…); + * - `rule`: the business rule it applies has to be written down first. + * The tier comes from evidence, never optimism: in doubt, the more + * conservative one. `MarketingEvidencePage.astro` fails `astro build` on a + * scenario whose value is missing or not in this list. + */ +export const SCENARIO_READINESS = ['today', 'integration', 'rule'] as const; +export type ScenarioReadiness = (typeof SCENARIO_READINESS)[number]; + /** * A scenario card on /use-cases/: the item's `body` is the "today" line, and * these two lines finish the shape "today → with AI → what a person approves, @@ -23,6 +37,8 @@ export interface MarketingPageScenario { template?: string; /** Cluster slug of a pillar guide that goes deeper, where one exists. */ guide?: string; + /** How far the scenario is from running; one of `SCENARIO_READINESS`. */ + readiness: ScenarioReadiness; withAi: string; approves: string; } diff --git a/src/content-pages/ui.ts b/src/content-pages/ui.ts index 71ab203..afe21c0 100644 --- a/src/content-pages/ui.ts +++ b/src/content-pages/ui.ts @@ -1,4 +1,5 @@ import type { Locale } from '../lib/i18n'; +import type { ScenarioReadiness } from './types'; import { s2t } from '../lib/zhconvert'; interface MarketingPageUi { @@ -23,6 +24,9 @@ interface MarketingPageUi { readPost: string; template: string; guide: string; + /** The readiness tag on each card and the legend's lead-in (#370). */ + readinessLegend: string; + readiness: Record; }; } @@ -59,6 +63,12 @@ const EN_UI: MarketingPageUi = { readPost: 'Read the scenario', template: 'Template', guide: 'Guide', + readinessLegend: 'What each scenario needs before it runs:', + readiness: { + today: 'Works on the platform today', + integration: 'Needs a connection to a system you run', + rule: 'Needs the business rule written down first', + }, }, }; @@ -95,6 +105,12 @@ const ZH_HANS_UI: MarketingPageUi = { readPost: '阅读完整场景', template: '模板', guide: '专题', + readinessLegend: '每个场景跑起来之前需要什么:', + readiness: { + today: '平台即可', + integration: '需要接现有系统', + rule: '需要先写清制度', + }, }, }; @@ -120,6 +136,12 @@ const toHant = (s: MarketingPageUi): MarketingPageUi => ({ readPost: s2t(s.scenario.readPost), template: s2t(s.scenario.template), guide: s2t(s.scenario.guide), + readinessLegend: s2t(s.scenario.readinessLegend), + readiness: { + today: s2t(s.scenario.readiness.today), + integration: s2t(s.scenario.readiness.integration), + rule: s2t(s.scenario.readiness.rule), + }, }, });