diff --git a/web/storyforge-web-v4/assets/app.js b/web/storyforge-web-v4/assets/app.js
index bfdd8d7..98f1756 100644
--- a/web/storyforge-web-v4/assets/app.js
+++ b/web/storyforge-web-v4/assets/app.js
@@ -3875,10 +3875,17 @@ function renderOneLinerActionRegistryPanel() {
OneLiner 动作注册表
-
当前后端还没返回动作注册表,先沿用默认动作。
+
当前项目还没有单独动作配置,OneLiner 会继续沿用系统默认动作。
+
+
+
+
当前沿用系统默认动作
+
你可以等真实使用场景稳定后,再回来给当前项目单独开关、改名或补充动作说明。
+
+ 系统默认仍可执行
+ 当前项目未单独覆盖
- 暂未接入
等 /v2/oneliner/action-registry 可用后,这里会显示动作开关、描述和租户级配置。
`;
}
@@ -3923,8 +3930,20 @@ function renderTenantQuotaPanel() {
if (!quota && !usage) {
return `
-
租户额度与审计
当前后端还没接入 quota / usage。
-
暂未接入
等 live collector 同步 `/v2/tenant/quota` 和 `/v2/tenant/usage` 后,这里会展示本周期预算、动作配额和最近计量记录。
+
+
+
租户额度与审计
+
当前项目还没有额度配置,会先按默认不限额模式运行。
+
+
+
+
当前项目还没有额度配置
+
先给这个项目补预算、动作配额和存储上限,再逐步收紧风险控制。
+
+ 创建额度策略
+ 默认不限额
+
+
`;
}
@@ -4236,8 +4255,24 @@ function renderPlatformAgentPanel() {
if (!items.length) {
return `
-
平台 Agent
当前后端还没接入平台 Agent 控制面。
-
暂未接入
等 live collector 同步 `/v2/platform-agents` 后,这里会切成真实视图。
+
+
+
平台 Agent
+
当前项目还没有平台 Agent 配置,先从最常用的平台补起。
+
+
+
+ ${ACTIVE_PLATFORMS.map((platformItem) => `
+
+
${escapeHtml(platformItem.label)} Agent
+
当前还没有单独配置,主 Agent 会先沿用系统默认平台方法论。
+
+ 未单独配置
+ 开始配置
+
+
+ `).join("")}
+
`;
}
diff --git a/web/storyforge-web-v4/tests/workbench-pages.test.mjs b/web/storyforge-web-v4/tests/workbench-pages.test.mjs
index 9a03a9e..3540097 100644
--- a/web/storyforge-web-v4/tests/workbench-pages.test.mjs
+++ b/web/storyforge-web-v4/tests/workbench-pages.test.mjs
@@ -254,6 +254,23 @@ test("discovery, production, and admin screens use page tabs for heavy content",
assert.match(strategy, /renderPolicyAuditFeed\(/);
});
+test("governance and quota panels use real empty-state language instead of backend-sync placeholders", () => {
+ const actionRegistry = extractBetween(APP, "function renderOneLinerActionRegistryPanel()", "function renderTenantQuotaPanel()");
+ const tenantQuota = extractBetween(APP, "function renderTenantQuotaPanel()", "function policyScopeTagLabel(");
+ const platformAgents = extractBetween(APP, "function renderPlatformAgentPanel()", "function renderTrackingScreen()");
+
+ assert.doesNotMatch(actionRegistry, /等 \/v2\/oneliner\/action-registry<\/code> 可用后/);
+ assert.match(actionRegistry, /当前项目还没有单独动作配置/);
+
+ assert.doesNotMatch(tenantQuota, /等 live collector 同步 `\/v2\/tenant\/quota` 和 `\/v2\/tenant\/usage` 后/);
+ assert.match(tenantQuota, /当前项目还没有额度配置/);
+ assert.match(tenantQuota, /data-action="open-tenant-quota"/);
+
+ assert.doesNotMatch(platformAgents, /等 live collector 同步 `\/v2\/platform-agents` 后/);
+ assert.match(platformAgents, /当前项目还没有平台 Agent 配置/);
+ assert.match(platformAgents, /open-platform-agent-profile/);
+});
+
test("discovery and production screens expose compact mobile flow summaries", () => {
const discovery = extractBetween(APP, "function renderDiscoveryScreen()", "function renderTrackingScreen()");
const production = extractBetween(APP, "function renderProductionScreen()", "function renderReviewScreen()");