极点宏观|Financial Cloud Cloud · 构建文章
Kiro:实施 Lab — 从零构建具类型的 Factory Risk Portal
仅供教育工程用途。本内容是软件架构演练,不属于工艺放行建议。
Lab 总览
在这个 lab 中,开发人员会使用 Kiro 从空文件夹构建 TypeScript React single-page application。此 app 使用决定性的本机 fixtures、具类型领域逻辑、实时模拟更新、搜索、排序与 SVG charts,将工厂机台风险视觉化。整个 lab 都使用 Kiro 作为单一 AI 工程服务:steering、specs、chat、hooks、code generation、refactoring 与 documentation。
前提条件
● 已安装 Kiro,并开启到空的 workspace。
● 建议使用 Node.js 20+。
● 可使用 npm。
● 熟悉 React 与 TypeScript。
步骤 1 — 建立 Vite TypeScript 项目
在 terminal 执行:
npm create vite@latest factory-risk-portal -- --template react-ts
cd factory-risk-portal
npm install
npm run dev
预期结果:默认 React + TypeScript application 会在本机 browser 中执行。
Kiro prompt 示例
Inspect this new React TypeScript workspace. Summarize the current structure and propose the minimal files we should add for a typed factory machinery risk portal. Do not write implementation code yet. Focus on architecture and type boundaries.
系统设计理由
● 从已知的构建系统开始。 Vite with React TypeScript 提供小而可预测的 workshop baseline。这让开发人员能把课程时间花在 Kiro workflows 与工程设计,而不是 bundler configuration。稳定的 project scaffold 也让 hooks 更容易,因为 npm run build、tsc 与 local dev commands 都有可预测的名称。
● 将检查与实施分离。 第一次 Kiro 互动要求的是 structure proposal,而不是 code。这很重要,因为当助理先读取 workspace 并形成计划时,agentic coding 质量会更好。对工厂工程软件而言,从空文件夹急着跳到 UI,往往会把领域假设埋进 JSX,这正是造成 typed React false-start 的原因。
● 建立可重复的课堂 baseline。 每个人都从相同 project template 开始。这让 troubleshooting 更容易,并确保教学中的 Kiro 行为与 specs、steering、implementation tasks 相关,而不是被各自本机 framework 差异影响。这也呼应现场工作:先建立稳定控制 baseline,再调整工艺参数。
步骤 2 — 新增 Kiro steering files
建立 .kiro/steering/product.md:
# Product overview
Build a local-only factory machinery risk portal for professional engineers. The portal helps review machinery drift, sensor-health symptoms, and risk recommendations. The application is advisory-only and must not imply autonomous equipment control, machine state changes, or bypassing human approval.
建立 .kiro/steering/tech.md:
# Technology stack
- React with TypeScript.
- Strict TypeScript; no `any`.
- Vite build system.
- CSS modules are not required; use plain CSS with clear class names.
- Inline SVG is allowed for sparklines and bar charts.
- No charting dependencies unless explicitly approved.
- No backend calls in the lab.
- Use local deterministic fixture data.
建立 .kiro/steering/structure.md:
# Project structure
- `src/types.ts` contains shared domain types.
- `src/data/fixtures.ts` contains deterministic local data.
- `src/domain/risk.ts` contains pure risk and formatting functions.
- `src/components/` contains presentational React components.
- `src/App.tsx` owns top-level state and tab switching.
- Event handlers and props must be typed.
- Action labels, tab names, and sort keys must be union types.
Kiro prompt 示例
Read the steering files and confirm the constraints you will follow. Then identify the first three implementation tasks for the factory risk portal. Do not create files yet.
系统设计理由
● Steering 将部落知识转换为持久场景。 现场团队常有存在于资深工程师脑中的标准:绝不暗示自主控制、不要使用未具类型 state、保持 risk logic 可审查,并避免 demo 中的网络假设。Steering files 让这些标准在每次互动中都可供 Kiro 使用,减少重复指示的需求。
● 类型政策放在 code generation 之前。 TypeScript failures 在 component tree 已存在后修正,成本远高于事前预防。通过预先要求 actions、tabs 与 sort keys 使用 union types,Kiro 较不容易建立过度宽松的 string props 或不安全 indexing logic。这是防止 React 项目 drift 到 untyped code 的主要控制。
● 结构文件建立可维护性压力。 如果 Kiro 知道 domain logic 属于 risk.ts、fixtures 属于 fixtures.ts、UI 属于 components,它就较不容易产生单体式 App.tsx。这对专业开发人员很重要,因为 maintainability 是系统属性,而不是格式偏好。
步骤 3 — 产生 Kiro spec
要求 Kiro 建立包含 requirements、design 与 tasks 的 spec。
Kiro prompt 示例
Create a Kiro spec for a TypeScript React factory machinery risk portal.
The app must include:
- typed machinery fixtures
- top KPI strip
- tabs for Overview, Live Risk Board, Health Matrix, Dynamic Matching, Triage, and Runbook
- search by machine, layer, or symptom
- sorting by risk, blind-window age, matching gap, slope, fleet sigma, or residual
- expandable evidence panels
- SVG sparklines and a larger SVG trajectory chart
- simulated 5-second live updates
- advisory-only wording
Use strict TypeScript and include acceptance criteria that can be tested.
预期结果:Kiro 会建立或提出包含 requirements section、design section 与 task list 的 spec。
系统设计理由
● Spec 是工程契约。 专业开发人员不应让 AI 助理单靠 UI labels 推断控制行为。Spec 说明哪些 behavior 可用、哪些仅限本机、哪些必须维持 advisory,以及哪些 acceptance criteria 能证明正确性。这可降低歧义并提供 review artifact。
● Acceptance criteria 控制范围。 如果没有 acceptance criteria,Kiro 可能过度构建或构建不足。例如,「make a live dashboard」可能变成 backend architecture、WebSocket client 或 static table。Acceptance criteria 会把系统限缩到 deterministic fixtures、明确 search、明确 sort keys、accessible controls 与 simulated updates。
● Spec 保留可追溯性。 工厂机台应用程序常需要 software、equipment、process 与 safety owners 审查。Spec-driven workflow 会建立 artifacts,说明功能为何存在以及允许做什么。这比包含零散决策的 chat transcript 更可靠。
步骤 4 — 建立 domain types
建立 src/types.ts:
export type Recommendation =
| 'RELEASE'
| 'WATCH'
| 'RUN SPC'
| 'GOLDEN WAFER'
| 'ROUTE LIMIT'
| 'HOLD REVIEW'
| 'APC GUARD';
export type RiskTone = 'pass' | 'warn' | 'danger';
export type SortKey = 'risk' | 'blindHours' | 'matchingGapNm' | 'slope' | 'fleetSigma' | 'residual3SigmaNm';
export type TabKey =
| 'OVERVIEW'
| 'LIVE RISK BOARD'
| 'HEALTH MATRIX'
| 'DYNAMIC MATCHING'
| 'TRIAGE'
| 'RUNBOOK';
export type MachineRecord = {
id: string;
layer: string;
symptom: string;
risk: number;
blindHours: number;
matchingGapNm: number;
slope: number;
fleetSigma: number;
residual3SigmaNm: number;
recommendation: Recommendation;
deltaMeanSeries: number[];
};
export type HealthLink = {
name: string;
sensor: string;
metrologyImpact: string;
yieldRisk: string;
advisoryRule: string;
};
商业逻辑说明
Domain types 定义 risk portal 的词汇。MachineRecord 代表一个机台或量测工具状态。Recommendation 是封闭的 review actions 集合,让 UI 不会意外呈现未支持的命令。SortKey 保护排序不受任意字符串影响。RiskTone 让 UI 显示颜色加上文字状态。HealthLink 将 sensor symptoms 对应到工程审查逻辑。
代码逻辑说明
每个 type 都从中央文件 export,让 components 与 domain functions 共享相同契约。Recommendations、tabs 与 sorting 刻意使用 union types。这让 TypeScript 能在 build time 检测无效 labels、不安全 sort keys 与拼错的 tabs。
预期结果
Kiro 与 TypeScript compiler 现在应理解核心 domain vocabulary。后续代码可 import 这些 types,而不是发明隐含 object shapes。
系统设计理由
● 封闭集合防止不安全语言 drift。 在工厂场景中,label 可能被解读为操作。自由格式 action string 可能意外变成「STOP TOOL」或「AUTO ROUTE」。Union type 会将应用程序限制在已知、已审查且刻意措辞的 advisory recommendations。
● 具类型 sort keys 移除 runtime guesswork。 Sorting UI 常从 generic strings 与 dynamic object indexing 开始,这很脆弱。SortKey union 在 controls、data fields 与 sort logic 之间建立契约。如果字段改变,TypeScript 会在 app 抵达用户前标出每个受影响区域。
● Domain-first coding 引导 Kiro。 当 Kiro 看见 data contracts 后,就能产生更好的 components。这避免了常见 false-start:AI 助理产生吸引人的 JSX 与隐含形状,然后难以在已写好的 state 与 props 周围补回 type declarations。
步骤 5 — 新增决定性 fixtures
建立 src/data/fixtures.ts:
import type { HealthLink, MachineRecord } from '../types';
export const initialMachines: MachineRecord[] = [
{
id: 'CDSEM-01',
layer: 'Gate ADI',
symptom: 'Stable master, production anchor',
risk: 18,
blindHours: 1.2,
matchingGapNm: 0.12,
slope: 1.0,
fleetSigma: 0.4,
residual3SigmaNm: 0.08,
recommendation: 'RELEASE',
deltaMeanSeries: [0.02, 0.01, 0.03, 0.01, 0.02, 0, 0.01, 0.02, 0.01, 0.02]
},
{
id: 'CDSEM-03',
layer: 'Fin dense CD',
symptom: 'Deflector DAC wobble, slope mismatch',
risk: 91,
blindHours: 7.4,
matchingGapNm: 0.23,
slope: 1.031,
fleetSigma: 3.2,
residual3SigmaNm: 0.16,
recommendation: 'HOLD REVIEW',
deltaMeanSeries: [0.02, 0.03, 0.06, 0.05, 0.08, 0.12, 0.16, 0.2, 0.22, 0.24]
}
];
export const healthLinks: HealthLink[] = [
{
name: 'Deflector DAC',
sensor: 'Deflector linearity / DAC stability',
metrologyImpact: 'Mandel Slope moves away from 1',
yieldRisk: 'Dense/isolated feature bias and process window narrowing',
advisoryRule: 'If slope <0.98 or >1.02, request engineering review before critical-layer routing.'
}
];
商业逻辑说明
Fixtures 代表真实感足够但安全的学习数据集。一笔 record 稳定,另一笔 record 风险高。这让开发人员不用连接工厂系统,就能立即验证 pass/warn/danger 行为、排序、chart geometry 与 recommendation display。
代码逻辑说明
Arrays 明确指定为 MachineRecord[] 与 HealthLink[]。TypeScript 现在会验证每个 field name、numeric metric 与 recommendation label。如果开发人员写成 HOLD 而不是 HOLD REVIEW,compiler 会抓到。
预期结果
App 具备可 render、sort、search、simulate 与 test 的决定性数据。
系统设计理由
● Fixtures 比实时机台数据更安全。 工作坊重点是使用 Kiro 进行软件工程,而不是运营整合。决定性的本机数据可避免凭证、网络失败、敏感生产值与意外控制暗示。它也让每位参与者看到相同预期结果。
● 代表性极端值支持验证。 同时包含低风险稳定机台与高风险 drift case,有助于验证 color thresholds、recommendation wording、expanded detail panels 与 chart scaling。只有正常值的数据集会把 risk-path defects 隐藏到更后面。
● 具类型 fixtures 作为 contract tests。 Fixture file 不只是 mock data;它是 domain model 可用性的 compile-time check。如果 model 过度复杂或缺少字段,Kiro 与 TypeScript 会在编写 fixtures 时立即显示不匹配。
步骤 6 — 新增纯风险逻辑
建立 src/domain/risk.ts:
import type { MachineRecord, RiskTone, SortKey } from '../types';
export function getRiskTone(risk: number): RiskTone {
if (risk >= 80) return 'danger';
if (risk >= 55) return 'warn';
return 'pass';
}
export function getStatusLabel(machine: MachineRecord): string {
if (machine.risk >= 80) return 'HOLD CANDIDATE';
if (machine.risk >= 55) return 'WATCH / REVIEW';
return 'NORMAL RELEASE';
}
export function filterMachines(machines: MachineRecord[], query: string): MachineRecord[] {
const q = query.trim().toLowerCase();
if (!q) return machines;
return machines.filter(machine =>
`${machine.id} ${machine.layer} ${machine.symptom}`.toLowerCase().includes(q)
);
}
export function sortMachines(machines: MachineRecord[], sortKey: SortKey): MachineRecord[] {
return [...machines].sort((a, b) => Math.abs(b[sortKey]) - Math.abs(a[sortKey]));
}
商业逻辑说明
Risk thresholds 集中管理。Green/pass 低于 55,yellow/watch 为 55-79,red/danger 为 80+。Search 支持 machine ID、process layer 或 symptom。Sorting 会依工程师选择的 metric,将最严重的值排在最前。
代码逻辑说明
这些 functions 是 pure:相同 inputs 永远产生相同 outputs。sortMachines 在排序前复制 array,以避免 mutation React state。SortKey 确保 dynamic indexing 只使用有效 numeric fields。
预期结果
Kiro 现在可以在可测试 business logic 之上构建 UI components。开发人员稍后可新增 unit tests,而不需要 render 整个 application。
系统设计理由
● Pure functions 让 AI-generated code 可审查。 当 business logic 直接混在 JSX 内,reviewers 必须在脑中分离 rendering、state、thresholds 与 formatting。Pure functions 会隔离重要决策:risk thresholds、filtering、sorting 与 status language。
● Immutability 保护 React state。 原地排序 arrays 是 dashboards 常见 bug。排序前复制可避免微妙 UI 问题,并让 live update behavior 更容易推理。只要 Kiro 转换 state,就应被引导保留 immutability。
● 集中 thresholds 支持治理。 Risk thresholds 是工程政策。将它们放在一个 domain file 中,可让未来 review 与 change control 更容易。如果 process owner 改变 warning threshold,实施会有一个明确位置,且较少隐藏 UI dependencies。
步骤 7 — 构建 SVG sparkline component
建立 src/components/Sparkline.tsx:
type SparklineProps = {
data: number[];
width?: number;
height?: number;
color?: string;
};
export function Sparkline({ data, width = 130, height = 38, color = '#35d5ff' }: SparklineProps) {
const min = Math.min(...data, 0);
const max = Math.max(...data, 0.24);
const points = data.map((value, index) => {
const x = (index / Math.max(1, data.length - 1)) * width;
const y = height - ((value - min) / (max - min || 1)) * (height - 6) - 3;
return `${x.toFixed(1)},${y.toFixed(1)}`;
}).join(' ');
return (
<svg className="spark" viewBox={`0 0 ${width} ${height}`} role="img" aria-label="DeltaMean sparkline">
<polyline points={points} fill="none" stroke={color} strokeWidth="2" />
<line x1="0" y1={height / 2} x2={width} y2={height / 2} stroke="#49657c" strokeDasharray="4 4" />
</svg>
);
}
商业逻辑说明
Sparkline 不需加入第三方 chart package,就能提供近期 drift 的快速视觉场景。工程师可直接在 risk table 中辨识稳定、上升或噪声行为。
代码逻辑说明
Component 会将 numeric values 对应到 SVG coordinates。它会在 minimum 与 maximum 之间 normalize values,建立 polyline string,并绘制中心参考线。Props 明确具类型,optional dimensions 也有 defaults。
预期结果
每个 machine row 都可显示具 accessible image metadata 的 compact trend line。
系统设计理由
● Inline SVG 保持 dependency surface 小。 对工作坊而言,charting library 会增加 API 学习负担与版本风险。SVG 是浏览器原生能力,对 React 而言类型支持足够,且足以处理 sparklines、trajectory charts 与 sigma bars。
● Chart component 隔离 coordinate math。 Coordinate transformation 不是 UI 装饰;它是逻辑。将它放在具类型 props 的 component 中,可让 table 更简洁,也让 rendering decision 可在 compact 与 expanded views 间重用。
● Accessibility 保持明确。 Sparkline 使用 role="img" 与 aria-label。这可避免只用视觉传达状态。在工程工具中,即使无法使用颜色或视觉细节,用户仍应能通过文字与 labels 解读状态。
步骤 8 — 要求 Kiro 实施 app shell
Kiro prompt 示例
Implement the app shell using the existing types, fixtures, risk functions, and Sparkline component.
Requirements:
- top header with title and live local clock
- KPI strip
- tab navigation controlled by typed TabKey state
- Live Risk Board with search, sort buttons, and expandable details
- simulated live updates every 5 seconds
- advisory-only footer
Keep App.tsx readable. If it becomes too large, propose component extraction before writing more code.
预期结果:Kiro 会建立可运作的 top-level app,具备 typed state 并渲染 core board。
系统设计理由
● Kiro 同时收到 constraints 与 assets。 到这一步,domain model、fixtures、pure functions 与 sparkline component 都已存在。Prompt 要求 Kiro 组合既有 pieces,而不是发明新东西。这会大幅改善 type consistency 并减少 duplicate logic。
● State ownership 是刻意设计的。 Top-level app 拥有 active tab、query、sort key、expanded row、live clock 与 machine records。这对小型 single-page lab 很合适。如果 app 成长,Kiro 应萃取 state 或 components,而不是把所有东西埋进深层 children。
● Simulated updates 安全地模拟真实遥测。 现场软件常需要展示随时间变化的 behavior。决定性的本机 update loop 比连接设备更安全。它可验证 re-rendering、chart updates 与 risk changes,同时保留 advisory-only 边界。
步骤 9 — 新增 hooks 以维持类型纪律
建立 .kiro/hooks/typecheck-on-save.json:
{
"version": "v1",
"hooks": [
{
"name": "typecheck-on-save",
"description": "Run TypeScript build checks when TS or TSX files are saved.",
"trigger": "PostFileSave",
"matcher": "\\.(ts|tsx)$",
"action": {
"type": "command",
"command": "npm run build"
},
"timeout": 60,
"enabled": true
}
]
}
建立 .kiro/hooks/review-react-change.json:
{
"version": "v1",
"hooks": [
{
"name": "review-react-change",
"description": "Ask Kiro to review React changes for typing, state mutation, accessibility, and advisory-only wording.",
"trigger": "PostFileSave",
"matcher": "src/.*\\.(ts|tsx)$",
"action": {
"type": "agent",
"prompt": "Review the changed TypeScript React file. Check for any, implicit object shapes, unsafe state mutation, untyped props, inaccessible controls, color-only status, and wording that implies autonomous machinery control. Suggest minimal fixes."
},
"timeout": 60,
"enabled": true
}
]
}
商业逻辑说明
Hooks 像工程质量闸门。它们不控制机台,也不批准 production behavior。它们协助开发人员及早捕捉不安全的 implementation patterns:type drift、mutation、UI-only status,以及可能被误解为 operational command 的语言。
代码逻辑说明
第一个 hook 会在 TypeScript 或 TSX 文件存储后执行 shell command。第二个 hook 会在 TypeScript React source changes 后调用 Kiro 的 agent review。Matcher 会将自动化限制在相关文件。
预期结果
存储 TypeScript 文件会触发 checks 或 review automation,取决于本机环境中的 Kiro hook configuration。
系统设计理由
● Hooks 将标准转换为 workflow。 Steering 告诉 Kiro 有哪些标准;hooks 让这些标准在 development 期间运作。当开发人员快速迭代且不一定每次都手动要求 review 时,这很关键。
● Type checking 在变更点自动化。 TS 或 TSX 文件一存储,build 就能抓出 invalid labels、missing props 与 broken imports。这降低了直到 lab 结尾才发现 type errors 的机率。
● Agent review 捕捉语义问题。 TypeScript 无法检测 button label 是否暗示自主设备控制。Agent hook 可以审查 language、accessibility 与 engineering intent。这是 compiler checks 的补充,而不是替代。
步骤 10 — 最终强化 prompt
Kiro prompt 示例
Perform a final technical review of the project.
Check:
- strict typing and no `any`
- no mutation of React state arrays
- all controls keyboard accessible
- search and sorting use typed contracts
- risk status includes text, not only color
- app wording remains advisory-only
- README explains how to run the app and states that fixture data must be replaced with validated data before operational use
Return a prioritized fix list, then implement only the safe low-risk fixes.
系统设计理由
● Final review 将检测与行动分开。 要求 Kiro 先提供 prioritized list 再实施,可避免未审查的 sweeping changes。这在工程环境中很重要,因为大型 refactor 可能在 workshop 或 sprint 后期引入 regressions。
● Safety language 是技术质量的一部分。 在工厂应用程序中,措辞是系统的一部分。「Hold candidate」与「recommend route limit」不同于「hold tool」或「reroute lot」。Review 会确保软件仍在 advisory scope 内。
● Low-risk fixes 保护 workshop 完成度。 最后几分钟应稳定项目,而不是开启架构震荡。Kiro 有助于找出许多改善点,但专业开发人员必须决定哪些现在实施、哪些放入 backlog。
完成检查清单
● [ ] 项目可在本机执行。
● [ ] Kiro steering files 存在。
● [ ] Kiro spec 存在或已完成审查。
● [ ] Domain types 先于 UI logic 存在。
● [ ] Source files 中没有 any。
● [ ] Search 可依 machine、layer 与 symptom 运作。
● [ ] Sorting 可针对所有 configured keys 运作。
● [ ] Expand/collapse evidence panel 可运作。
● [ ] Live update loop 会改变 risk 与 trend values。
● [ ] SVG charts 可在没有 chart libraries 的情况下 render。
● [ ] Advisory-only disclaimer 可见。
● [ ] Hooks 存在,用于 type checks 与 AI review。
Lab 区段:建立完整 fixture coverage
Main lab 中的短 fixture 是为了教学而刻意保持小型。若要更丰富的 demo,请以涵盖低、中、高风险的较广 records 取代它。这会让 Kiro 与参与者在 sorting、filtering、display color 与 expanded evidence 上有更多案例。
import type { HealthLink, MachineRecord } from '../types';
export const initialMachines: MachineRecord[] = [
{
id: 'CDSEM-01',
layer: 'Gate ADI',
symptom: 'Stable master, production anchor',
risk: 18,
blindHours: 1.2,
matchingGapNm: 0.12,
slope: 1.0,
fleetSigma: 0.4,
residual3SigmaNm: 0.08,
recommendation: 'RELEASE',
deltaMeanSeries: [0.02, 0.01, 0.03, 0.01, 0.02, 0.0, 0.01, 0.02, 0.01, 0.02]
},
{
id: 'CDSEM-02',
layer: 'Gate AEI',
symptom: 'Emission current ramp, small mean offset',
risk: 64,
blindHours: 5.8,
matchingGapNm: 0.18,
slope: 1.012,
fleetSigma: 1.8,
residual3SigmaNm: 0.14,
recommendation: 'WATCH',
deltaMeanSeries: [0.02, 0.04, 0.05, 0.08, 0.10, 0.12, 0.14, 0.16, 0.17, 0.18]
},
{
id: 'CDSEM-03',
layer: 'Fin dense CD',
symptom: 'Deflector DAC wobble, slope mismatch',
risk: 91,
blindHours: 7.4,
matchingGapNm: 0.23,
slope: 1.031,
fleetSigma: 3.2,
residual3SigmaNm: 0.16,
recommendation: 'HOLD REVIEW',
deltaMeanSeries: [0.02, 0.03, 0.06, 0.05, 0.08, 0.12, 0.16, 0.20, 0.22, 0.24]
},
{
id: 'CDSEM-05',
layer: 'Contact/Via',
symptom: 'Vacuum slow degradation, residual rising',
risk: 76,
blindHours: 6.9,
matchingGapNm: 0.19,
slope: 1.006,
fleetSigma: 2.4,
residual3SigmaNm: 0.21,
recommendation: 'GOLDEN WAFER',
deltaMeanSeries: [0.02, 0.01, 0.04, 0.06, 0.08, 0.10, 0.12, 0.13, 0.16, 0.18]
},
{
id: 'CDSEM-10',
layer: 'Risk ramp product',
symptom: 'Yield-loss watch lots routed here',
risk: 82,
blindHours: 6.2,
matchingGapNm: 0.21,
slope: 0.976,
fleetSigma: 2.9,
residual3SigmaNm: 0.17,
recommendation: 'APC GUARD',
deltaMeanSeries: [0.02, 0.04, 0.07, 0.09, 0.11, 0.13, 0.15, 0.18, 0.20, 0.23]
}
];
export const healthLinks: HealthLink[] = [
{
name: 'Gun Vacuum',
sensor: 'Gun chamber vacuum / Torr',
metrologyImpact: 'Residual 3 sigma and TMP rise',
yieldRisk: 'False alarms and random CD noise',
advisoryRule: 'If vacuum degrades while residual 3 sigma rises, recommend golden-wafer review.'
},
{
name: 'Emission Current',
sensor: 'Extraction voltage / emission current',
metrologyImpact: 'Mean offset step jump',
yieldRisk: 'APC receives biased CD and may correct in the wrong direction',
advisoryRule: 'If emission slope changes for three lots, recommend virtual OOC review before next routine SPC.'
},
{
name: 'Deflector DAC',
sensor: 'Deflector linearity / DAC stability',
metrologyImpact: 'Mandel Slope moves away from 1',
yieldRisk: 'Dense/isolated feature bias and process-window narrowing',
advisoryRule: 'If slope <0.98 or >1.02, request engineering review before critical-layer routing.'
},
{
name: 'Stage Vibration',
sensor: 'Stage vibration / facility vibration mG',
metrologyImpact: 'Site-to-site Delta Max-Min expands',
yieldRisk: 'False local variation signatures can hide real yield patterns',
advisoryRule: 'If residual and site range rise after a vibration burst, recommend routing review for tight CD layers.'
}
];
商业逻辑说明
这个延伸 fixture set 包含多种 risk profiles:stable release、watch、high fleet deviation、residual rise、slope drift 与 yield-watch exposure。这种多样性很重要,因为工程仪表板必须让异常条件清楚可见,同时不失去正常 baseline context。
代码逻辑说明
Fields 与 MachineRecord 完全一致。Fixture names 使用工程友善 labels,同时保留 type-safe property names。每个 series 都有相同长度,因此 SVG scaling 与 live update logic 会保持可预测。
预期结果
Risk board 可展示所有主要 user paths:搜索 tool、依不同 metrics 排序、展开 high-risk row、检查 trend chart,并确认 advisory recommendation language。
系统设计理由
● Coverage 防止误导性 demos。 只有一两列的 dashboard,即使 sorting、threshold coloring 与 row expansion 有缺陷,也可能看起来正确。较广的 fixture set 会产生足够变化,让参与者能跨多个 paths 验证 behavior。
● Normal cases 保持可见。 Field engineering tools 不应只显示 alarms。纳入稳定 baseline tools,可协助用户将 drift candidates 与健康 anchor 比较。这个 context 对视觉解读与软件验证都很有价值。
● Fixture consistency 保护 chart logic。 保持 series length 一致,可避免在工作坊中处理分散注意力的 edge cases。Facilitator 可在核心 typed design 被理解后,再把 missing 或 uneven data 作为 advanced extension 引入。
延伸 Lab 区段:在 App.tsx 实施 top-level state
import { useEffect, useMemo, useState } from 'react';
import { initialMachines } from './data/fixtures';
import { filterMachines, sortMachines } from './domain/risk';
import type { MachineRecord, SortKey, TabKey } from './types';
const tabs: TabKey[] = ['OVERVIEW', 'LIVE RISK BOARD', 'HEALTH MATRIX', 'DYNAMIC MATCHING', 'TRIAGE', 'RUNBOOK'];
export function App() {
const [activeTab, setActiveTab] = useState<TabKey>('OVERVIEW');
const [query, setQuery] = useState('');
const [sortKey, setSortKey] = useState<SortKey>('risk');
const [expandedId, setExpandedId] = useState<string | null>(null);
const [machines, setMachines] = useState<MachineRecord[]>(initialMachines);
const visibleMachines = useMemo(() => {
return sortMachines(filterMachines(machines, query), sortKey);
}, [machines, query, sortKey]);
useEffect(() => {
let tick = 0;
const timer = window.setInterval(() => {
tick += 1;
setMachines(previous => previous.map((machine, index) => {
const wave = Math.sin((tick + index) * 0.7);
const risk = Math.max(5, Math.min(99, machine.risk + wave * 1.7));
const blindHours = Math.max(0.2, machine.blindHours + 0.05 + wave * 0.03);
const latest = machine.deltaMeanSeries[machine.deltaMeanSeries.length - 1] ?? 0;
const nextPoint = Math.max(0, Math.min(0.28, latest + wave * 0.006));
return {
...machine,
risk,
blindHours,
deltaMeanSeries: [...machine.deltaMeanSeries.slice(1), Number(nextPoint.toFixed(3))]
};
}));
}, 5000);
return () => window.clearInterval(timer);
}, []);
return (
<div className="app-shell">
<nav className="tabs" aria-label="Portal panels">
{tabs.map(tab => (
<button key={tab} className={activeTab === tab ? 'active' : ''} onClick={() => setActiveTab(tab)}>
{tab}
</button>
))}
</nav>
<pre>{JSON.stringify({ activeTab, query, sortKey, expandedId, visibleCount: visibleMachines.length }, null, 2)}</pre>
</div>
);
}
商业逻辑说明
Top-level state 捕捉主要 dashboard interactions:active panel、text search、selected sorting metric、expanded evidence row 与目前 machine records。Simulated updates 让 portal 感觉实时,同时仍与真实系统断开。
代码逻辑说明
visibleMachines 由 machines、query 与 sortKey 通过 useMemo 衍生。Update loop 会建立新的 machine objects,而不是 mutation previous state。Tab list 指定为 TabKey[],可防止不支持的 panels。
预期结果
App 应每五秒显示变化中的 derived state。这是在构建完整 UI 前的 checkpoint。
系统设计理由
● State 明确且最小化。 App 只存储用户控制或会随时间改变的值。Filtered 与 sorted data 由数据衍生。这可防止 duplicated state,这是 dashboard bugs 的常见来源。
● Derived views 被 memoized。 Search 与 sorting 可在 inputs 改变时重新计算。useMemo 让逻辑保持可见,并在 app 成长时避免不必要 recomputation。
● Update loop 有边界且可回复。 Simulated data changes 小幅、clamped 且在本机。此设计展示 live behavior,而不假装自己是 production telemetry pipeline。
延伸 Lab 区段:构建具类型 metric card
建立 src/components/MetricCard.tsx:
type MetricCardProps = {
label: string;
value: string | number;
detail: string;
tone?: 'neutral' | 'pass' | 'warn' | 'danger';
};
export function MetricCard({ label, value, detail, tone = 'neutral' }: MetricCardProps) {
return (
<article className={`metric-card ${tone}`}>
<span>{label}</span>
<strong>{value}</strong>
<em>{detail}</em>
</article>
);
}
商业逻辑说明
Metric cards 会在用户检查 detail rows 前,摘要 operational state。示例包括 tools watched、blind-window average、fleet out-of-control count 与 yield-watch lots。
代码逻辑说明
Component 接受小型具类型 prop set。tone 是 optional,并被限制为已知 display styles。Component 不计算 metrics;它只负责 rendering。
预期结果
KPI cards 可在 header 或 summary rows 中重用,而不需重复 markup。
系统设计理由
● Presentational components 应保持简单。 Metric card 应渲染 metric,而不是决定 fleet risk 如何计算。保持 presentation-only 可降低隐藏逻辑,并让 Kiro-generated UI 更容易审查。
● Typed visual tone 防止 CSS drift。 Component 支持封闭的 tones 集合,而不是任意 class strings。这呼应 risk-tone pattern,让未来 styling 更安全。
● Reusable layout 降低重复。 Dashboards 常跨 panels 重复 cards。小型具类型 component 可让 Kiro 更快建立一致 UI,而不会每次建立不一致 markup。
延伸 Lab 区段:建立 risk board component
建立 src/components/RiskBoard.tsx:
import { getRiskTone, getStatusLabel } from '../domain/risk';
import type { MachineRecord, SortKey } from '../types';
import { Sparkline } from './Sparkline';
type RiskBoardProps = {
machines: MachineRecord[];
query: string;
sortKey: SortKey;
expandedId: string | null;
onQueryChange: (query: string) => void;
onSortChange: (key: SortKey) => void;
onExpandedChange: (id: string | null) => void;
};
const sortOptions: Array<[SortKey, string]> = [
['risk', 'Risk'],
['blindHours', 'Blind Window'],
['matchingGapNm', 'TMG'],
['slope', 'Slope'],
['fleetSigma', 'Fleet sigma'],
['residual3SigmaNm', 'Residual']
];
export function RiskBoard({ machines, query, sortKey, expandedId, onQueryChange, onSortChange, onExpandedChange }: RiskBoardProps) {
return (
<section className="risk-board">
<div className="toolbar">
<input
value={query}
onChange={event => onQueryChange(event.target.value)}
placeholder="Search by machine, layer, or symptom"
aria-label="Search by machine, layer, or symptom"
/>
<div className="sorts">
{sortOptions.map(([key, label]) => (
<button key={key} className={sortKey === key ? 'active' : ''} onClick={() => onSortChange(key)}>
Sort: {label}
</button>
))}
</div>
</div>
{machines.map(machine => {
const tone = getRiskTone(machine.risk);
const isExpanded = expandedId === machine.id;
return (
<article className="machine-row" key={machine.id}>
<div className="row-main">
<strong>{machine.id}</strong>
<span>{machine.layer}</span>
<span className={`risk ${tone}`}>{Math.round(machine.risk)} {tone.toUpperCase()}</span>
<Sparkline data={machine.deltaMeanSeries} />
<button onClick={() => onExpandedChange(isExpanded ? null : machine.id)} aria-expanded={isExpanded}>
{isExpanded ? 'Hide evidence' : machine.recommendation}
</button>
</div>
{isExpanded && (
<div className="evidence-panel">
<p><b>Status:</b> {getStatusLabel(machine)}</p>
<p><b>Evidence:</b> {machine.symptom}</p>
<p><b>Blind Window:</b> {machine.blindHours.toFixed(1)}h</p>
<p><b>Fleet Sigma:</b> {machine.fleetSigma.toFixed(1)}σ</p>
</div>
)}
</article>
);
})}
</section>
);
}
商业逻辑说明
Risk Board 是工程师搜索、排序与检查 machine evidence 的地方。它显示 risk status text、layer context、trend evidence 与 advisory recommendations。
代码逻辑说明
Component 从 parent 接收所有 state,并通过 typed callbacks 发出变更。它不拥有 machine list。这让 component 更容易测试,并将 state ownership 保留在 App.tsx。
预期结果
用户可以搜索、排序并展开 rows。每列都显示 machine ID、layer、risk text、sparkline 与 recommendation button。
系统设计理由
● Controlled inputs 保留 state traceability。 Search 与 sort state 位于 parent,因此目前 board state 稍后可被 logged、tested 或传给其他 panels。这比把 local state 埋在大型 table component 中更易维护。
● Callbacks 是具类型契约。 onSortChange 只接受 SortKey,因此 component 不能发出不支持的 field。这是另一个防止 Kiro 建立 stringly typed UI controls 的护栏。
● Evidence 按需显示。 Expanded panels 让默认 board 保持密集,同时仍使 reasoning 可见。工厂工程师同时需要快速 triage 与 drill-down evidence。
延伸 Lab 区段:新增较大的 SVG trajectory chart
建立 src/components/TrajectoryChart.tsx:
type TrajectoryChartProps = {
data: number[];
advisoryLimit?: number;
};
export function TrajectoryChart({ data, advisoryLimit = 0.18 }: TrajectoryChartProps) {
const width = 620;
const height = 190;
const pad = 24;
const min = Math.min(...data, -0.02);
const max = Math.max(...data, 0.26, advisoryLimit);
const xFor = (index: number) => pad + (index / Math.max(1, data.length - 1)) * (width - pad * 2);
const yFor = (value: number) => height - pad - ((value - min) / (max - min || 1)) * (height - pad * 2);
const points = data.map((value, index) => `${xFor(index)},${yFor(value)}`).join(' ');
return (
<svg className="trajectory-chart" viewBox={`0 0 ${width} ${height}`} role="img" aria-label="DeltaMean trajectory chart">
<line x1={pad} x2={width - pad} y1={yFor(advisoryLimit)} y2={yFor(advisoryLimit)} stroke="#ff5b6e" strokeDasharray="6 6" />
<polyline points={points} fill="none" stroke="#35d5ff" strokeWidth="4" strokeLinecap="round" strokeLinejoin="round" />
{data.map((value, index) => (
<circle key={index} cx={xFor(index)} cy={yFor(value)} r="4" fill={value > advisoryLimit ? '#ff5b6e' : '#35d5ff'} />
))}
</svg>
);
}
商业逻辑说明
Expanded chart 会显示近期 DeltaMean values 是否接近或跨越 advisory threshold。它通过呈现 trend direction 与 threshold crossings,支持工程审查。
代码逻辑说明
Component 将 numeric series 转换为 SVG coordinates。Advisory limit 是有 default value 的 prop,让 chart 之后可重用于不同 layers 或 process windows。
预期结果
Evidence panel 可显示较大的 trajectory chart,包含 dashed advisory limit line 与 colored points。
系统设计理由
● Thresholds 在 context 中可见。 单一数字无法呈现 trend velocity。带有 advisory line 的 chart 有助于工程师区分稳定高值与快速上升的风险信号。
● Chart 保持决定性。 不需要外部 rendering library 或 asynchronous data source。数学透明,参与者也容易检查。
● Limit 可设置但有边界。 将 advisoryLimit 做成 typed prop,可避免把每个 threshold 都硬编码,同时仍防止隐藏 global behavior。
延伸 Lab 区段:新增可 unit-test 的 update logic
将 update function 移到 src/domain/risk.ts:
export function simulateMachineUpdate(machine: MachineRecord, tick: number, index: number): MachineRecord {
const wave = Math.sin((tick + index) * 0.7);
const risk = Math.max(5, Math.min(99, machine.risk + wave * 1.7));
const blindHours = Math.max(0.2, machine.blindHours + 0.05 + wave * 0.03);
const latest = machine.deltaMeanSeries[machine.deltaMeanSeries.length - 1] ?? 0;
const nextPoint = Math.max(0, Math.min(0.28, latest + wave * 0.006));
return {
...machine,
risk,
blindHours,
deltaMeanSeries: [...machine.deltaMeanSeries.slice(1), Number(nextPoint.toFixed(3))]
};
}
接着简化 effect:
useEffect(() => {
let tick = 0;
const timer = window.setInterval(() => {
tick += 1;
setMachines(previous => previous.map((machine, index) => simulateMachineUpdate(machine, tick, index)));
}, 5000);
return () => window.clearInterval(timer);
}, []);
商业逻辑说明
Update function 会模拟小幅 risk 与 trend changes,让 dashboard 保持活跃。它不代表实际设备遥测。
代码逻辑说明
将 function 移出 App.tsx 会让它可测试。React effect 只负责排程 updates。
预期结果
Behavior 维持不变,但代码更容易验证与维护。
系统设计理由
● Scheduling 与 calculation 是不同 concerns。 React effects 应管理时间与 lifecycle。Domain functions 应计算新值。这种分离让两部分都更容易推理。
● Pure simulation 支持测试。 Pure function 可用已知 inputs 测试。这很有用,因为 live update bugs 常以 gradual drift 或 state mutation 形式出现,若只靠 UI tests 很难诊断。
● Model 保持诚实。 将 function 命名为 simulateMachineUpdate,清楚表明 values 是 synthetic。这可避免将 demo behavior 与 validated factory data 混淆。
延伸 Lab 区段:README 内容
要求 Kiro 使用此 prompt 产生 README:
Create a README for this local-only TypeScript React factory risk portal. Include install commands, run commands, architecture summary, Kiro steering and hook notes, advisory-only disclaimer, and a warning that fixture data must be replaced with validated engineering data before operational use.
README 最低内容:
# Factory Risk Portal
Local-only TypeScript React workshop project built with Kiro.
## Run
npm install
npm run dev
## Build
npm run build
## Safety boundary
This application is advisory-only. It does not command equipment, change route state, write to dispatch systems, modify APC feedback, or bypass human approval. Fixture data is for learning only and must be replaced with validated engineering data before operational use.
系统设计理由
● Documentation 是 deliverable 的一部分。 工程软件应说明如何执行,以及它不做什么。当 UI 类似工厂控制仪表板时,这特别重要。
● Safety boundary 会跟着 code 移动。 README 可被未参加工作坊的未来开发人员阅读。它在 live Kiro session 之外保留 advisory-only constraint。
● Kiro 可产生实用 maintenance artifacts。 Documentation generation 是实施后使用 Kiro 的实用方式,但它应根据实际 project structure 与 constraints,而不是 generic boilerplate。
参与者调试指南
问题:TypeScript 表示 sort key 无法索引 machine record
可能原因:SortKey 包含了非 numeric,或不存在于 MachineRecord 的 field。
修正 prompt:
Inspect SortKey and MachineRecord. Make the sort key union include only numeric MachineRecord fields. Update sort buttons to match. Do not use type assertions to hide the problem.
问题:Risk colors 已显示,但 screen readers 没有 status
可能原因:status 只通过 CSS 传达。
修正 prompt:
Update risk display so it includes visible text and an aria-label with the numeric risk and risk tone. Keep the existing colors.
问题:Kiro 产生了新的 action label
可能原因:模型把 recommendations 当成普通 strings。
修正 prompt:
The recommendation field must use the existing Recommendation union. Replace unsupported labels with the closest existing advisory recommendation or propose a union update before changing fixtures.
问题:最终代码全部在一个文件中
可能原因:implementation prompt 没有充分约束 structure。
修正 prompt:
Refactor the existing behavior into the agreed structure. Preserve runtime behavior. Move types, fixtures, pure domain functions, and reusable components into separate files. Explain each movement before editing.
额外 Lab 区段 — 构建更完整的 fixture coverage
前面的 lab 使用 minimal fixture 来快速教学概念。若要更丰富的 workshop demo,请用额外 records 扩展 src/data/fixtures.ts。这会让 sorting、searching、color thresholds、charting 与 KPI calculations 拥有更真实的 behavior。
export const additionalMachines: MachineRecord[] = [
{
id: 'CDSEM-05',
layer: 'Contact/Via',
symptom: 'Vacuum slow degradation, residual rising',
risk: 76,
blindHours: 6.9,
matchingGapNm: 0.19,
slope: 1.006,
fleetSigma: 2.4,
residual3SigmaNm: 0.21,
recommendation: 'GOLDEN WAFER',
deltaMeanSeries: [0.02, 0.01, 0.04, 0.06, 0.08, 0.10, 0.12, 0.13, 0.16, 0.18]
},
{
id: 'CDSEM-06',
layer: 'Overlay support',
symptom: 'Vibration burst after facility event',
risk: 72,
blindHours: 4.3,
matchingGapNm: 0.17,
slope: 0.989,
fleetSigma: 2.2,
residual3SigmaNm: 0.19,
recommendation: 'ROUTE LIMIT',
deltaMeanSeries: [0.01, 0.00, 0.03, 0.02, 0.12, 0.03, 0.13, 0.05, 0.15, 0.06]
},
{
id: 'CDSEM-10',
layer: 'Risk ramp product',
symptom: 'Yield-loss watch lots routed here',
risk: 82,
blindHours: 6.2,
matchingGapNm: 0.21,
slope: 0.976,
fleetSigma: 2.9,
residual3SigmaNm: 0.17,
recommendation: 'APC GUARD',
deltaMeanSeries: [0.02, 0.04, 0.07, 0.09, 0.11, 0.13, 0.15, 0.18, 0.20, 0.23]
}
];
商业逻辑说明
Expanded records 引入三种不同 risk patterns:residual-driven review、vibration-related route advisory 与 APC guard evidence。这让开发人员能看到不同 machine symptoms 的示例,而不需连接真实 telemetry。
代码逻辑说明
Records 使用相同的 MachineRecord type。它们可用 spread operator 合并到 initialMachines。TypeScript 会验证每个 recommendation 与 metric field。
预期结果
Live Risk Board 更适合 demonstration。现在依 risk、fleet sigma、residual 或 blind-window age 排序时,visible order 会有明显变化。
系统设计理由
● 更丰富的 dataset 揭露 UI edge cases。 只有两笔 records 时,开发人员无法完整验证 sort behavior、row wrapping、warning colors 或多种 recommendation labels。额外 records 会建立真实 layout pressure,同时仍保持 lab 安全且决定性。
● 不同 symptoms 测试 domain language。 Vacuum、vibration 与 APC guard 示例迫使 UI 显示 evidence text,而不只是 risk number。这很重要,因为工程 reviewers 在采取行动前需要知道 recommendation 背后的理由。
● Typed fixture expansion 证明 scalability。 新增 records 不应需要修改 components。如果 app 在新增 records 时坏掉,表示设计耦合太紧。这会教导开发人员 data-driven rendering 是系统设计目标。
额外 Lab 区段 — 将 KPI calculations 新增为 pure functions
建立 src/domain/kpi.ts:
import type { MachineRecord } from '../types';
export type KpiSummary = {
toolsWatched: number;
averageBlindHours: number;
fleetOocRiskCount: number;
yieldWatchCount: number;
fdcHealthLinks: number;
dynamicLimitsEnabled: boolean;
};
export function calculateKpis(machines: MachineRecord[], healthLinkCount: number): KpiSummary {
const averageBlindHours = machines.reduce((sum, machine) => sum + machine.blindHours, 0) / machines.length;
const fleetOocRiskCount = machines.filter(machine => machine.fleetSigma > 2).length;
const yieldWatchCount = machines.filter(machine =>
machine.recommendation === 'HOLD REVIEW' ||
machine.recommendation === 'GOLDEN WAFER' ||
machine.recommendation === 'APC GUARD'
).length;
return {
toolsWatched: machines.length,
averageBlindHours,
fleetOocRiskCount,
yieldWatchCount,
fdcHealthLinks: healthLinkCount,
dynamicLimitsEnabled: true
};
}
商业逻辑说明
KPI cards 摘要 operational review pressure:watched tools 数量、average blind-window age、fleet out-of-control exposure、health-link coverage、dynamic limit status 与 yield-watch load。
代码逻辑说明
Function 接收 machine records 与 health-link count,然后返回具类型 KpiSummary。它将 calculations 集中在 React rendering 之外,因此相同 values 可被测试与重用。
预期结果
App.tsx 可用一个 pure function call 计算 KPI values,并将 summary 传给 KpiStrip component。
系统设计理由
● KPI calculation 属于 JSX 之外。 Dashboards 常把 KPI math 埋进 render blocks。这会让 review 与 testing 更困难。Pure KPI function 让 calculation 可见且可重用。
● Summary type 记录 business meaning。 KpiSummary 为 UI 中显示的 values 命名。这比匿名 strings 与 numbers 的 array 更容易审查。
● KPI logic 支持未来替换 fixture data。 当日后引入 live validated data 时,KPI function 可保持稳定。只有 data source 会改变。
额外 Lab 区段 — 新增 trajectory chart component
建立 src/components/TrajectoryChart.tsx:
type TrajectoryChartProps = {
data: number[];
threshold?: number;
};
export function TrajectoryChart({ data, threshold = 0.18 }: TrajectoryChartProps) {
const width = 620;
const height = 188;
const pad = 22;
const min = Math.min(...data, -0.02);
const max = Math.max(...data, 0.26);
const xFor = (index: number) => pad + (index / Math.max(1, data.length - 1)) * (width - pad * 2);
const yFor = (value: number) => height - pad - ((value - min) / (max - min || 1)) * (height - pad * 2);
const points = data.map((value, index) => `${xFor(index)},${yFor(value)}`).join(' ');
return (
<svg className="big-chart" viewBox={`0 0 ${width} ${height}`} role="img" aria-label="DeltaMean trajectory chart">
<line x1={pad} x2={width - pad} y1={yFor(threshold)} y2={yFor(threshold)} stroke="#ff5b6e" strokeDasharray="6 6" />
<polyline points={points} fill="none" stroke="#35d5ff" strokeWidth="4" strokeLinejoin="round" strokeLinecap="round" />
{data.map((value, index) => (
<circle key={index} cx={xFor(index)} cy={yFor(value)} r="4" fill={value > threshold ? '#ff5b6e' : '#35d5ff'} />
))}
</svg>
);
}
商业逻辑说明
Trajectory chart 显示近期 drift 是否接近或跨越 review threshold。它为 selected machine row 提供 expanded evidence view。
代码逻辑说明
Component 将 data points 转换成 SVG coordinates、绘制 threshold line、画出 series,并以不同颜色标示高于 threshold 的 points,同时仍依赖其他地方的文字 metrics 来传达 status。
预期结果
Expanded rows 可显示较大的 chart,以支持 engineering review。
系统设计理由
● Expanded evidence 将 summary 与 detail 分开。 Table row 应保持 compact。Detailed drift evidence 属于 expandable panel,由用户明确要求更多 context 时显示。
● Threshold rendering 支持 traceability。 视觉化显示 threshold 会让 recommendation 为何存在更容易理解。不过 status 仍必须以文字显示,以避免 color-only interpretation。
● Typed chart props 降低误用。 Chart 只接受 numeric data 与 optional numeric threshold。这让 component 可重用,并防止 Kiro 在预期 number array 的地方传入整个 machine objects。
额外 Lab 区段 — 为 pure logic 新增 unit tests
如果 workshop environment 允许加入 Vitest,请要求 Kiro 新增 tests。如果不想安装 package,请把此段视为 optional read-through exercise。
Kiro prompt 示例
Add Vitest tests for the pure domain functions only. Test risk tone thresholds, search filtering, sorting by risk, sorting by fleet sigma, KPI calculation, and simulated update bounds. Do not test CSS or implementation details of React components.
Example test file src/domain/risk.test.ts:
import { describe, expect, it } from 'vitest';
import { getRiskTone, sortMachines } from './risk';
import { initialMachines } from '../data/fixtures';
describe('risk domain logic', () => {
it('classifies risk thresholds', () => {
expect(getRiskTone(20)).toBe('pass');
expect(getRiskTone(55)).toBe('warn');
expect(getRiskTone(80)).toBe('danger');
});
it('sorts machines by highest risk first', () => {
const sorted = sortMachines(initialMachines, 'risk');
expect(sorted[0].risk).toBeGreaterThanOrEqual(sorted[1].risk);
});
});
商业逻辑说明
Tests 捕捉 dashboard 背后的工程规则。未来 refactor 不应意外改变 risk thresholds 或 sort order。
代码逻辑说明
Tests 直接调用 pure functions。它们不依赖 browser 或 rendered components。
预期结果
开发人员取得一个快速 safety net,用于保护最重要的 logic。
系统设计理由
● 先测试 pure logic,再测 UI。 Risk thresholds 与 sort order 比 CSS class 是否套用更关键。Unit tests 应先保护工程决策。
● 在短 workshop 中避免脆弱 visual tests。 Snapshot 或 pixel-style testing 可能分散参与者注意力。Pure function tests 更容易理解与维护。
● Kiro 可在 contracts 存在后产生 tests。 当 types 与 functions 已稳定时,AI-generated tests 会更好。太早要求 tests,常会产生围绕稍后会改变的 implementation details 的测试。
额外 Lab 区段 — 新增包含 运营边界 的 README 内容
要求 Kiro 建立或更新 README.md:
Update README.md with setup commands, project structure, Kiro workflow, type standards, hook descriptions, and advisory-only limitations. State clearly that fixture data is synthetic learning data and must be replaced with validated engineering data before any operational use.
建议 README section:
## Operational boundary
This project is a learning application. It does not connect to factory equipment, dispatch systems, APC systems, or production databases. All records are local fixtures. Recommendations are advisory labels for review workflows only and must not be interpreted as autonomous machine commands.
系统设计理由
● Documentation 是 safety boundary 的一部分。 开发人员可能理解 app 只在本机执行,但未来读者不一定知道。README text 会保留预期用途。
● Run instructions 降低 workshop friction。 参与者常在稍后回到项目。清楚 setup commands 可让他们不依赖记忆就重新开始。
● Kiro workflow notes 让课程可移植。 记录 steering、specs 与 hooks,有助于参与者在自己的 repositories 中重用此模式。
进阶挑战 — 让 Kiro 在不改变 behavior 的情况下 refactor
Kiro prompt 示例
Refactor the Live Risk Board into `RiskBoard.tsx`, `MachineRow.tsx`, and `EvidencePanel.tsx`. Preserve behavior exactly. Keep all props typed. Do not change CSS class names. Show a summary of files changed before implementation.
系统设计理由
● Refactoring 搭配明确 invariants 更安全。 「Preserve behavior exactly」与「do not change CSS class names」是重要 constraints。没有这些限制,Kiro 可能改善结构,却意外破坏 styling 或 interactions。
● Typed props 揭露 component boundaries。 Refactoring 会迫使开发人员决定每个 component 拥有什么。这是检验 domain model 是否乾净的好方法。
● Change summary 改善 review。 在实施前,Kiro 应说明它计划 touch 哪些 files。这可降低惊讶感,并示范专业 pull-request behavior。