@viccydev/pi-fpa 0.7.2 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,159 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "name": "fpa-strategy-planning",
4
+ "version": "4.2.0",
5
+ "description": "FP&A 组合式策略规划:在一个 Graph 内完成目标规划、并行只读数据/驱动审计、并行只读场景分析、策略推荐与独立审核,最终形成 reviewed_strategy_handoff。必须提供字符串 context.scope_id、context.cycle_id、context.forecast_role;Graph 不审批、不预测、不发布仪表盘。",
6
+ "mutationPolicy": "mutating",
7
+ "start": "plan_cycle",
8
+ "maxSteps": 24,
9
+ "nodes": [
10
+ {
11
+ "id": "plan_cycle",
12
+ "type": "subagent",
13
+ "agentName": "plan_cycle",
14
+ "label": "目标与范围规划",
15
+ "outputKey": "plan_cycle",
16
+ "next": "parallel_analysis",
17
+ "systemPrompt": "你是 FP&A 目标规划 Agent。权威上下文为 scope_id={{context.scope_id}}、cycle_id={{context.cycle_id}}、forecast_role={{context.forecast_role}}。不得从目标文本猜测或替换这些标识。",
18
+ "prompt": "目标:{{goal}}\n\n按 fpa-plan-cycle 先调用 fpa_data_catalog 实测目标期和对比期字段可用性,再写 artifacts/planning_brief.md。明确目标、预算、周期、in_scope/out_of_scope 维度与指标、App 清单及增长/成熟/收缩角色。正式预测指标白名单仅为 spend、revenue、roas。不得生成策略、预测或调用任何 fpa_dashboard_* 工具。",
19
+ "skills": ["fpa-apply-core-rules", "fpa-plan-cycle"],
20
+ "tools": ["read", "write", "fpa_data_catalog"]
21
+ },
22
+ {
23
+ "id": "parallel_analysis",
24
+ "type": "parallel",
25
+ "label": "并行数据与经营审计",
26
+ "concurrency": 2,
27
+ "next": "synthesize_analysis",
28
+ "children": [
29
+ {
30
+ "id": "actuals_audit",
31
+ "type": "subagent",
32
+ "agentName": "actuals_audit",
33
+ "systemPrompt": "你是只读 FP&A 数据质量审计 Agent。不得写文件或发布仪表盘。",
34
+ "prompt": "目标:{{goal}}\n\n读取 artifacts/planning_brief.md,按 fpa-diagnose-actuals 检查数据窗口、字段覆盖、revenue 回刷成熟度、cohort 可用性、scope reduction 与 blocking issue。只输出结构化 JSON 证据给汇总节点,不写任何 artifact。",
35
+ "skills": ["fpa-apply-core-rules", "fpa-diagnose-actuals"],
36
+ "tools": ["read", "fpa_data_catalog", "fpa_query", "fpa_cohort"]
37
+ },
38
+ {
39
+ "id": "driver_audit",
40
+ "type": "subagent",
41
+ "agentName": "driver_audit",
42
+ "systemPrompt": "你是只读 FP&A 经营驱动审计 Agent。不得写文件或发布仪表盘。",
43
+ "prompt": "目标:{{goal}}\n\n读取 artifacts/planning_brief.md,按 in_scope_dimensions 独立查询 spend、revenue、roas、cpi、installs,分析组合、App、商店、渠道和平台驱动;明确每个 App/切片的增长、保持、削减或止损证据。只输出结构化 JSON,不写任何 artifact。",
44
+ "skills": ["fpa-apply-core-rules", "fpa-analyze-drivers"],
45
+ "tools": ["read", "fpa_query", "fpa_cohort", "fpa_compare", "fpa_calc"]
46
+ }
47
+ ]
48
+ },
49
+ {
50
+ "id": "synthesize_analysis",
51
+ "type": "subagent",
52
+ "agentName": "synthesize_analysis",
53
+ "label": "汇总上周期分析",
54
+ "outputKey": "driver_analysis",
55
+ "next": "parallel_scenarios",
56
+ "systemPrompt": "你是 FP&A 分析汇总 Agent。只整合并复核并行审计证据,不补造数据。",
57
+ "prompt": "目标:{{goal}}\n\n并行审计:{{data.parallel_analysis}}\n\n读取 planning_brief,交叉核对两个只读审计结果;冲突时重新用确定性工具复算。写 artifacts/actuals_snapshot.md、artifacts/data_issue_report.md、artifacts/driver_analysis.md 和机器可读 artifacts/driver_analysis.json。JSON 必须符合 driver_analysis contract,包含 artifact_type、status、headline_results、drivers、data_limits/limitations,并对每个 App 或 in-scope 切片给出增长/保持/削减/止损结论与证据。不得生成策略或发布仪表盘。",
58
+ "skills": ["fpa-apply-core-rules", "fpa-diagnose-actuals", "fpa-analyze-drivers"],
59
+ "tools": ["read", "write", "fpa_query", "fpa_compare", "fpa_calc"]
60
+ },
61
+ {
62
+ "id": "parallel_scenarios",
63
+ "type": "parallel",
64
+ "label": "并行策略场景分析",
65
+ "concurrency": 3,
66
+ "next": "synthesize_scenarios",
67
+ "children": [
68
+ {
69
+ "id": "efficiency_lane",
70
+ "type": "subagent",
71
+ "agentName": "efficiency_lane",
72
+ "systemPrompt": "你是只读 FP&A 稳健效率场景 Agent。不得写文件、批准策略或发布仪表盘。",
73
+ "prompt": "读取 planning_brief、actuals_snapshot 与 driver_analysis,构造维持硬 ROAS 下限的稳健/效率候选场景,逐 App/商店/渠道给出完整 allocation、downside/base/upside、假设和止损。只输出结构化 JSON 候选,不写 artifact。",
74
+ "skills": ["fpa-apply-core-rules", "fpa-simulate-strategies"],
75
+ "tools": ["read", "fpa_query", "fpa_calc"]
76
+ },
77
+ {
78
+ "id": "growth_lane",
79
+ "type": "subagent",
80
+ "agentName": "growth_lane",
81
+ "systemPrompt": "你是只读 FP&A 增长与探索场景 Agent。不得写文件、批准策略或发布仪表盘。",
82
+ "prompt": "读取 planning_brief、actuals_snapshot 与 driver_analysis,构造增长/探索候选场景;探索预算约 10%,逐 App/商店/渠道给出完整 allocation、downside/base/upside、假设和止损。只输出结构化 JSON 候选,不写 artifact。",
83
+ "skills": ["fpa-apply-core-rules", "fpa-simulate-strategies"],
84
+ "tools": ["read", "fpa_query", "fpa_calc"]
85
+ },
86
+ {
87
+ "id": "risk_lane",
88
+ "type": "subagent",
89
+ "agentName": "risk_lane",
90
+ "systemPrompt": "你是只读 FP&A 约束与风险挑战 Agent。不得写文件、批准策略或发布仪表盘。",
91
+ "prompt": "读取 planning_brief 与 driver_analysis,独立检查预算上下限、ROAS 硬下限、Revenue 次目标、ROAS<0.5 止损、集中度、外推和数据成熟度。输出每个候选策略必须满足的约束、压力测试区间与淘汰规则,只输出结构化 JSON。",
92
+ "skills": ["fpa-apply-core-rules", "fpa-simulate-strategies"],
93
+ "tools": ["read", "fpa_query", "fpa_calc"]
94
+ }
95
+ ]
96
+ },
97
+ {
98
+ "id": "synthesize_scenarios",
99
+ "type": "subagent",
100
+ "agentName": "synthesize_scenarios",
101
+ "label": "汇总候选策略",
102
+ "outputKey": "strategy_scenarios",
103
+ "next": "recommend_strategy",
104
+ "systemPrompt": "你是 FP&A 场景汇总 Agent。所有加总、ROAS 和约束判断必须确定性复算。",
105
+ "prompt": "目标:{{goal}}\n\n并行场景与风险审计:{{data.parallel_scenarios}}\n\n读取权威上游工件,合并、去重并复算候选场景,至少保留现状、稳健和增长场景。写 artifacts/strategy_scenarios.md 与符合 contract 的 artifacts/strategy_scenarios.json;逐切片完整覆盖,探索/利用分开,所有 ROAS<0.5 切片必须削减或清零。不得推荐、批准、预测或发布仪表盘。",
106
+ "skills": ["fpa-apply-core-rules", "fpa-simulate-strategies"],
107
+ "tools": ["read", "write", "fpa_calc"]
108
+ },
109
+ {
110
+ "id": "recommend_strategy",
111
+ "type": "subagent",
112
+ "agentName": "recommend_strategy",
113
+ "label": "形成执行策略",
114
+ "outputKey": "strategy_proposal",
115
+ "next": "review_strategy",
116
+ "systemPrompt": "你是 FP&A 策略推荐 Agent。不得自我批准、生成预测或发布仪表盘。",
117
+ "prompt": "目标:{{goal}}\n\n读取 planning_brief、driver_analysis 和 strategy_scenarios,按 fpa-recommend-strategy 选择推荐策略。写 artifacts/strategy_proposal.md 与符合 contract 的 artifacts/strategy_proposal.json。allocation 必须逐 App/商店/渠道包含显式 action(grow/hold/cut/stop)、spend 与 change_from_baseline,使 Dashboard 能明确展示增长、保持、削减和止损;保留完整 expected_outcomes、理由、风险、阈值和 required_human_decisions。",
118
+ "skills": ["fpa-apply-core-rules", "fpa-recommend-strategy"],
119
+ "tools": ["read", "write", "fpa_calc"]
120
+ },
121
+ {
122
+ "id": "review_strategy",
123
+ "type": "subagent",
124
+ "agentName": "review_strategy",
125
+ "label": "独立审核",
126
+ "outputKey": "strategy_review",
127
+ "parseJson": true,
128
+ "next": "route_review",
129
+ "systemPrompt": "你是未参与推荐生成的 FP&A 独立审核 Agent。不得批准策略、生成预测或发布仪表盘。",
130
+ "prompt": "读取 proposal 及全部上游机器工件,按 fpa-review-strategy 独立复算覆盖、加总、ROAS、止损、探索占比、外推与数据血缘。写 artifacts/strategy_review.md 和 artifacts/strategy_review.json。最终只输出路由 JSON:{\"status\":\"support|support_with_conditions|reject\",\"summary\":\"...\",\"conditions\":[]}。",
131
+ "skills": ["fpa-apply-core-rules", "fpa-review-strategy"],
132
+ "tools": ["read", "write", "fpa_query", "fpa_calc"]
133
+ },
134
+ {
135
+ "id": "route_review",
136
+ "type": "router",
137
+ "label": "审核结果路由",
138
+ "path": "data.strategy_review.status",
139
+ "cases": [
140
+ { "equals": "reject", "label": "审核拒绝,重新推荐", "to": "recommend_strategy" },
141
+ { "equals": "support", "label": "审核支持", "to": "prepare_strategy_handoff" },
142
+ { "equals": "support_with_conditions", "label": "有条件支持", "to": "prepare_strategy_handoff" }
143
+ ],
144
+ "default": { "label": "其他结果,重新推荐", "to": "recommend_strategy" }
145
+ },
146
+ {
147
+ "id": "prepare_strategy_handoff",
148
+ "type": "subagent",
149
+ "agentName": "prepare_strategy_handoff",
150
+ "label": "形成已审核策略交接",
151
+ "outputKey": "strategy_handoff",
152
+ "parseJson": true,
153
+ "systemPrompt": "你是 FP&A 策略交接 Agent。权威上下文为 scope_id={{context.scope_id}}、cycle_id={{context.cycle_id}}、forecast_role={{context.forecast_role}}。不批准、不预测、不发布仪表盘。",
154
+ "prompt": "读取 planning_brief、driver_analysis.json、strategy_scenarios.json、strategy_proposal.json 与 strategy_review.json,先调用 fpa_json_fingerprint 对 proposal/review 两个 JSON 生成确定性 SHA-256,再严格按 fpa-review-strategy 的 reviewed_strategy_handoff contract 核验并写 artifacts/reviewed_strategy_handoff.json。ready 文件必须包含 kind=fpa.reviewed-strategy-handoff、scope_id/cycle_id/forecast_role、相同的 strategy_version 与 reviewed_strategy_version、工具返回的 proposal/review fingerprint、独立审核身份、review_opinion、条件、剩余风险和 next_graph=fpa-forecast-freeze;失败时写 blocked 结果且不得覆盖已有 ready 文件。最终只输出 fpa.graph-handoff JSON。Graph 到此结束,由主 Agent 依次发布 period-review 与 next-strategy 模块并等待用户决策。",
155
+ "skills": ["fpa-apply-core-rules", "fpa-review-strategy"],
156
+ "tools": ["read", "write", "fpa_json_fingerprint"]
157
+ }
158
+ ]
159
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viccydev/pi-fpa",
3
- "version": "0.7.2",
3
+ "version": "0.8.1",
4
4
  "type": "module",
5
5
  "description": "Full-cycle FP&A planning, strategy, forecast, and review prompts, skills, and data tools for Pi",
6
6
  "license": "UNLICENSED",
@@ -22,6 +22,7 @@
22
22
  "files": [
23
23
  "README.md",
24
24
  "bin",
25
+ "graphs",
25
26
  "prompts",
26
27
  "skills",
27
28
  "extensions"
@@ -30,9 +31,9 @@
30
31
  "fpa-dashboard-worker": "./bin/fpa-dashboard-worker.mjs"
31
32
  },
32
33
  "scripts": {
33
- "test": "node tests/package-structure.test.mjs && node tests/workflow-routing.test.mjs && node --test tests/workflow-routing-guard.test.mjs && node tests/extension-unit.test.mjs && node --test tests/catalog-timeout.test.mjs tests/artifact-store.test.mjs tests/artifact-ledger.test.mjs tests/artifact-handoff.test.mjs tests/forecast-compose.test.mjs tests/dashboard-actuals.test.mjs tests/dashboard-projector.test.mjs tests/cycle-operating-projection.test.mjs tests/forward-outlook.test.mjs tests/forecast-accuracy.test.mjs tests/dashboard-publisher.test.mjs tests/dashboard-provenance.test.mjs tests/dashboard-coordinator.test.mjs && node tests/pi-loader-smoke.mjs && node tests/worker-loader-smoke.mjs && node tests/publish-workflow.test.mjs",
34
+ "test": "node tests/package-structure.test.mjs && node tests/workflow-routing.test.mjs && node --test tests/workflow-routing-guard.test.mjs tests/graph-contract.test.mjs tests/graph-installer.test.mjs && node tests/extension-unit.test.mjs && node --test tests/catalog-timeout.test.mjs tests/artifact-store.test.mjs tests/artifact-ledger.test.mjs tests/artifact-handoff.test.mjs tests/forecast-compose.test.mjs tests/dashboard-actuals.test.mjs tests/dashboard-projector.test.mjs tests/dashboard-module-publisher.test.mjs tests/dashboard-stage-projector.test.mjs tests/strategy-decision.test.mjs tests/cycle-operating-projection.test.mjs tests/forward-outlook.test.mjs tests/forecast-accuracy.test.mjs tests/dashboard-publisher.test.mjs tests/dashboard-provenance.test.mjs tests/dashboard-coordinator.test.mjs && node tests/pi-loader-smoke.mjs && node tests/worker-loader-smoke.mjs && node tests/publish-workflow.test.mjs",
34
35
  "test:structure": "node tests/package-structure.test.mjs",
35
- "test:unit": "node tests/extension-unit.test.mjs && node --test tests/catalog-timeout.test.mjs tests/artifact-store.test.mjs tests/artifact-ledger.test.mjs tests/artifact-handoff.test.mjs tests/forecast-compose.test.mjs tests/dashboard-actuals.test.mjs tests/dashboard-projector.test.mjs tests/cycle-operating-projection.test.mjs tests/forward-outlook.test.mjs tests/forecast-accuracy.test.mjs tests/dashboard-publisher.test.mjs tests/dashboard-provenance.test.mjs tests/dashboard-coordinator.test.mjs",
36
+ "test:unit": "node tests/extension-unit.test.mjs && node --test tests/catalog-timeout.test.mjs tests/artifact-store.test.mjs tests/artifact-ledger.test.mjs tests/artifact-handoff.test.mjs tests/forecast-compose.test.mjs tests/dashboard-actuals.test.mjs tests/dashboard-projector.test.mjs tests/dashboard-module-publisher.test.mjs tests/dashboard-stage-projector.test.mjs tests/strategy-decision.test.mjs tests/cycle-operating-projection.test.mjs tests/forward-outlook.test.mjs tests/forecast-accuracy.test.mjs tests/dashboard-publisher.test.mjs tests/dashboard-provenance.test.mjs tests/dashboard-coordinator.test.mjs",
36
37
  "test:loader": "node tests/pi-loader-smoke.mjs && node tests/worker-loader-smoke.mjs",
37
38
  "test:live": "node tests/live-smoke.mjs",
38
39
  "pack:check": "npm pack --dry-run"
@@ -17,10 +17,20 @@ argument-hint: "<project-root> <cycle-id> [instructions]"
17
17
  ## 强制 Graph 路由
18
18
 
19
19
  先读取 `fpa-apply-core-rules`。如果当前 Agent 提供 `graph_list` 和
20
- `graph_run`,必须先调用 `graph_list`,确认 `fpa-strategy-planning` 后再以
21
- 完整用户目标、已解析的项目根、周期边界、业务范围和数据上下文调用
22
- `graph_run`。在这两步之前不得直接调用任何 `fpa_*` 工具或写 Artifact,
23
- Agent 也不得自行串行模拟 Graph 内的阶段。
20
+ `graph_run`,必须先调用 `graph_list`,确认 `fpa-strategy-planning` 后按以下边界执行:
21
+
22
+ 1. 以完整用户目标运行一个组合式 `fpa-strategy-planning`。`graph_run.context`
23
+ 的所有值必须是字符串,并明确提供 `scope_id`、`cycle_id`、
24
+ `forecast_role`;对象、数组、数字和其他结构化要求全部留在 `goal`。
25
+ 2. Graph 返回 `driver_analysis.json`、`strategy_proposal.json`、
26
+ `strategy_review.json` 与 `reviewed_strategy_handoff.json` 后,父 Agent 先调用
27
+ `fpa_dashboard_publish_review` preview/publish,取得最新 revision;再调用
28
+ `fpa_dashboard_publish_strategy`,传入 proposal/review/handoff 三个路径及精确
29
+ `scope_id`、`cycle_id`、`forecast_role` 做 preview/publish,发布
30
+ `next-strategy` 并等待仪表盘决策。
31
+
32
+ Graph 不得拥有或调用任何 `fpa_dashboard_*` 工具。发布是父 Agent
33
+ 在 Graph 返回后的职责;父 Agent不得自行模拟 Graph 内的业务阶段。
24
34
 
25
35
  如果匹配 Graph 不在 catalog 中或无法加载,列出缺口并保持 `blocked`;不得把
26
36
  本多阶段入口自动降级为父 Agent 本地执行。用户之后可另行显式请求一个隔离阶段。
@@ -31,7 +41,10 @@ Graph 返回业务阻塞同样不构成降级理由。所需上下文缺失时
31
41
  - 策略推荐者不得批准或独立复核自己的提案。若宿主不能证明复核上下文与提案作者独立,复核阶段必须报告 `blocked`。
32
42
  - 独立复核完成后,`fpa-strategy-planning` 必须生成精确绑定提案与复核版本的 `reviewed_strategy_handoff`,然后停止。
33
43
  - 聊天中的认可、模型自我确认或 Forecast 授权都不等于策略执行授权。
34
- - 人工批准与正式预测属于后续独立的 `fpa-forecast-freeze` Graph;父 Agent 不得在本入口中继续执行。
44
+ - 仪表盘响应回到原主会话后,先由主 Agent 调用
45
+ `fpa_strategy_decision_commit`。只有 `confirm` 成功才可在后续运行
46
+ `fpa-forecast-freeze`;Graph 返回 immutable forecast ref 后仍由主 Agent
47
+ 调用 `fpa_dashboard_publish_forecast`。本入口发布策略后停止等待用户。
35
48
  - 本入口不得加载 Forecast 或策略执行 Skill,不得声称已经冻结 Forecast 或修改外部投放状态。
36
49
 
37
50
  ## 全局计算与证据底线
@@ -20,15 +20,18 @@ writing artifacts. It applies only when the current agent exposes both
20
20
 
21
21
  | Eligible request and evidence | Required Graph |
22
22
  | --- | --- |
23
- | New or changed objective requiring planning, Actuals diagnosis, driver analysis, scenarios, recommendation, or independent review | `fpa-strategy-planning` |
24
- | Ready `reviewed_strategy_handoff` plus a request for human approval and an official forecast | `fpa-forecast-freeze` |
23
+ | New or changed objective requiring planning, Actuals diagnosis, driver analysis, scenarios, recommendation, and independent review | `fpa-strategy-planning` |
24
+ | Ready `reviewed_strategy_handoff` plus an exact confirmed `strategy_decision` and a request for an official forecast | `fpa-forecast-freeze` |
25
25
  | Exact committed approved Forecast ref plus an authorized execution request | `fpa-strategy-execution` |
26
26
  | Exact Forecast and Execution refs plus newly arrived comparable Actuals | `fpa-cycle-review` |
27
27
 
28
- 3. Call `graph_run` with the user's complete goal and the exact immutable
29
- context required by that Graph. The parent agent must not reproduce its
30
- nodes, pre-run their `fpa_*` calls, or automatically cross the next approval
31
- or artifact handoff after the Graph returns.
28
+ 3. Call `graph_run` with the user's complete goal. Every `context` value must
29
+ be a string; provide exact `scope_id`, `cycle_id`, and `forecast_role`, and
30
+ keep structured planning details in `goal`. The parent agent must not
31
+ reproduce Graph nodes or pre-run their `fpa_*` calls. After the combined
32
+ planning Graph succeeds, the main Agent publishes `period-review` and then
33
+ `next-strategy` with their matching `fpa_dashboard_publish_*` tools. Graph
34
+ nodes must never receive dashboard publication tools.
32
35
  4. If required context is missing or ambiguous, return `blocked` and request
33
36
  the exact identity or ref. Do not fall back to direct phase execution.
34
37
 
@@ -2,22 +2,32 @@
2
2
 
3
3
  ## 1. Workflow and artifacts
4
4
 
5
- Strategy-planning workflow (`fpa-strategy-planning`):
5
+ Combined strategy-planning workflow (`fpa-strategy-planning`):
6
6
 
7
- `planning_brief -> actuals_snapshot + data_issue_report -> driver_analysis -> strategy_scenarios -> strategy_proposal -> strategy_review -> reviewed_strategy_handoff`
7
+ `planning_brief -> parallel(actuals audit, driver audit) -> driver_analysis -> parallel(efficiency, growth, risk) -> strategy_scenarios -> strategy_proposal -> strategy_review -> reviewed_strategy_handoff`
8
8
 
9
- This Graph stops after an independently reviewed strategy handoff. It does not
9
+ The Graph stops at the reviewed strategy handoff and may not publish dashboard
10
+ content. Parallel children are independent and read-only; sequential reducer
11
+ nodes alone write the canonical artifacts. The strategy Graph does not
10
12
  approve the strategy, create an official forecast, or execute the allocation.
11
13
 
14
+ The calling main Agent first publishes the exact `driver_analysis` through
15
+ `fpa_dashboard_publish_review`, then publishes the exact proposal, independent
16
+ review, ready handoff, and immutable scope/cycle/role through
17
+ `fpa_dashboard_publish_strategy`, waits for the dashboard response in the
18
+ originating main session, and commits it with `fpa_strategy_decision_commit`.
19
+ Dashboard publishing and decision commit tools are forbidden from every Graph
20
+ tool allowlist.
21
+
12
22
  Forecast-freeze workflow (`fpa-forecast-freeze`), entered only with that exact
13
- ready handoff:
23
+ ready handoff plus the exact confirmed strategy-decision fingerprint:
14
24
 
15
- `reviewed_strategy_handoff -> human strategy_approval -> forecast_plan -> approved_cycle_forecast`
25
+ `reviewed_strategy_handoff + strategy_decision -> forecast_plan -> approved_cycle_forecast`
16
26
 
17
- The forecast Graph owns approval recording, deterministic composition, and
18
- artifact freezing. A rejected approval returns to a new
19
- `fpa-strategy-planning` version rather than modifying the reviewed proposal in
20
- place.
27
+ The main Agent owns approval recording; the forecast Graph owns deterministic
28
+ composition and artifact freezing. A rejected approval reruns
29
+ `fpa-strategy-planning` with the exact feedback and produces a new version
30
+ rather than modifying the reviewed proposal in place.
21
31
 
22
32
  Execution is a separate `fpa-strategy-execution` workflow:
23
33
 
@@ -28,7 +38,8 @@ after new Actuals arrive:
28
38
 
29
39
  `exact approved_cycle_forecast ref + exact execution_receipt ref + next actuals_snapshot -> cycle_review -> optional new planning cycle`
30
40
 
31
- The main agent routes to only the currently eligible Graph. It must not emulate
41
+ The main agent routes to only the currently eligible Graph and is solely
42
+ responsible for publishing the returned stage module. It must not emulate
32
43
  multiple phases itself or automatically cross a human approval or immutable
33
44
  artifact handoff.
34
45
 
@@ -17,7 +17,9 @@ Require all of the following:
17
17
  `fpa-strategy-planning`, including its bound proposal and review identities;
18
18
  - the exact `strategy_proposal` version;
19
19
  - a completed independent `strategy_review` supporting that version;
20
- - explicit human `strategy_approval` identifying the same version and any conditions;
20
+ - the exact immutable `strategy_decision` fingerprint returned by
21
+ `fpa_strategy_decision_commit` in the originating main session, confirming
22
+ the same version and handoff fingerprint;
21
23
  - the eligible data snapshot, assumptions, and model version used for forecasting.
22
24
 
23
25
  If approval evidence is absent, ambiguous, expired, conditional but unmet, or refers to another strategy version, return `blocked` without forecasting.
@@ -26,7 +28,9 @@ from it, return `blocked`; never reconstruct or substitute the handoff.
26
28
 
27
29
  ## Procedure
28
30
 
29
- 1. Verify approval and artifact lineage.
31
+ 1. Verify the committed strategy decision and artifact lineage. The Graph must
32
+ consume that decision as input; it must not display, request, or record a
33
+ second approval itself.
30
34
  2. Lock the approved allocation, accountable owner for each slice when known, and all approval conditions.
31
35
  3. Recalculate future-period operating outcomes from that allocation using the declared model.
32
36
  4. Provide downside, base, and upside values for each supported KPI.
@@ -74,12 +78,11 @@ Work the planning stage explicitly placed outside this cycle's scope is neither
74
78
  a limit nor a defect: it does not belong in `unsupported_metrics` and does not
75
79
  downgrade `status`.
76
80
 
77
- This matters downstream: `fpa_dashboard_refresh` with `mode: publish` accepts
78
- only `complete`, so `complete_with_limits` blocks the dashboard. Do not
79
- misreport a narrowed scope as a limit and stall the publish, and do not hide a
80
- real defect to get through the gate. When something that was promised cannot be
81
- delivered, report `complete_with_limits` honestly and say that the scope
82
- declaration upstream needs correcting.
81
+ The calling main Agent publishes the committed result with
82
+ `fpa_dashboard_publish_forecast`; the Graph itself never calls a dashboard
83
+ tool. `complete_with_limits` remains publishable when its limitations are
84
+ explicit, while `blocked` is not. Do not hide a real defect to get through the
85
+ gate.
83
86
 
84
87
  ## Boundaries
85
88
 
@@ -12,7 +12,7 @@ Load `$fpa-apply-core-rules` first. Recommend one plan while keeping alternative
12
12
  1. Consume `planning_brief`, `driver_analysis`, and `strategy_scenarios`.
13
13
  2. Remove scenarios that breach hard constraints.
14
14
  3. Rank remaining scenarios using the objective priorities and declared trade-off rule.
15
- 4. Select one recommendation and specify exact allocation, changes from baseline, expected ranges, assumptions, and risks.
15
+ 4. Select one recommendation and specify exact allocation, an explicit `grow | hold | cut | stop` action for every App/store/channel row, changes from baseline, expected ranges, assumptions, and risks.
16
16
  5. State why rejected alternatives were not chosen.
17
17
  6. Define next-cycle evaluation thresholds; do not create a real-time monitoring obligation.
18
18
  7. Write `strategy_proposal` using [artifact-contract.md](references/artifact-contract.md).
@@ -12,6 +12,7 @@ allocation:
12
12
  - app_id: string
13
13
  store: string
14
14
  channel_group: string
15
+ action: grow | hold | cut | stop
15
16
  spend: number
16
17
  change_from_baseline: number
17
18
  expected_outcomes:
@@ -27,4 +28,4 @@ next_cycle_evaluation_thresholds: []
27
28
  required_human_decisions: []
28
29
  ```
29
30
 
30
- The total allocation must reconcile to the proposed total budget, and every allocation row must map to a simulated scenario row.
31
+ The total allocation must reconcile to the proposed total budget, and every allocation row must map to a simulated scenario row. `action` is explicit and mandatory: use `grow` for a budget increase, `hold` for an unchanged allocation, `cut` for a non-zero reduction, and `stop` when the slice is removed or held at zero under a stop-loss decision.
@@ -1,13 +1,48 @@
1
1
  ---
2
2
  name: fpa-refresh-dashboard
3
- description: Preview, validate, and atomically publish the forecast closed-loop FP&A dashboard from a committed approved forecast, optional execution receipt, and current read-only Actuals. Use when the user asks to inspect, rebuild, or publish the tenant dashboard.
3
+ description: Preview, validate, and publish independent FP&A dashboard modules for period review, reviewed strategy approval, confirmed forecast, and execution evidence. Use after each Graph stage returns or when the user asks to inspect, rebuild, or publish the tenant dashboard.
4
4
  ---
5
5
 
6
- # FP&A Dashboard Refresh
6
+ # FP&A Dashboard Module Publication
7
7
 
8
8
  Load `$fpa-apply-core-rules` first. Follow [dashboard-policy.md](references/dashboard-policy.md).
9
9
 
10
- ## Entry gate
10
+ ## Ownership boundary
11
+
12
+ Dashboard publication belongs to the calling main Agent. A Graph may analyze,
13
+ review, forecast, and return exact artifact paths or refs, but no Graph node or
14
+ Graph tool allowlist may contain any `fpa_dashboard_*` tool. The main Agent must
15
+ wait for the Graph result, then preview and publish the corresponding module.
16
+
17
+ Do not publish the whole dashboard after every stage. The root manifest is only
18
+ an atomic catalog of independently versioned modules; publishing one module must
19
+ preserve every other module revision.
20
+
21
+ ## Module sequence
22
+
23
+ 1. After the analysis Graph returns `driver_analysis`, preview then publish
24
+ `period-review` with `fpa_dashboard_publish_review`.
25
+ 2. After the strategy Graph returns the exact `strategy_proposal`, independent
26
+ `strategy_review`, and `reviewed_strategy_handoff`, preview then publish
27
+ `next-strategy` with `fpa_dashboard_publish_strategy`. Supply all three paths
28
+ and the exact `scope_id`, `cycle_id`, and `forecast_role`; the tool verifies
29
+ fingerprints, review independence, opinion, conditions, and next-stage
30
+ binding. Publication binds its decision action to the current main session;
31
+ never copy or expose a session id in dashboard data.
32
+ 3. Stop and wait for the dashboard action. The Web host sends a canonical
33
+ decision message back to the bound original session. In that session call
34
+ `fpa_strategy_decision_commit` with the exact `action_id`.
35
+ 4. On `confirm`, run `fpa-forecast-freeze`; after it returns an exact committed
36
+ forecast ref, preview then publish `next-forecast` with
37
+ `fpa_dashboard_publish_forecast`.
38
+ 5. On `request_changes`, pass the verbatim feedback back into strategy planning,
39
+ publish the replacement `next-strategy` module, and wait for a new decision.
40
+
41
+ Every preview returns both `preview_fingerprint` and `dashboard_revision`.
42
+ Publish with both exact values. A `null` dashboard revision is an explicit CAS
43
+ value for a dashboard that did not exist at preview time.
44
+
45
+ ## Legacy closed-loop entry gate
11
46
 
12
47
  Require a committed `approved_cycle_forecast` for the target project. Treat a committed `execution_receipt` as optional execution evidence; never describe manual reported execution as independently verified.
13
48
 
@@ -17,7 +52,10 @@ only part of this tuple or fall back to a mutable current pointer.
17
52
 
18
53
  ## Procedure
19
54
 
20
- ### Post-Graph handoff
55
+ ### Legacy post-Graph handoff
56
+
57
+ This path remains only for legacy execution-evidence refreshes. It must not be
58
+ used to replace review, strategy, or forecast modules.
21
59
 
22
60
  1. Take the exact `artifact_ref` from `fpa_artifact_commit.dashboard_handoff`.
23
61
  2. Call `fpa_dashboard_refresh_queue` with `action: enqueue_artifact` and that
@@ -60,6 +98,11 @@ answer, and do not describe it as "the period has no data yet".
60
98
  ## Boundaries
61
99
 
62
100
  - Never write `.fpa-dashboard` with generic file or shell tools.
101
+ - Never let pi-graph or a Graph node call dashboard publication tools.
102
+ - Never accept caller-authored widgets; module tools project widgets from exact
103
+ business artifacts and immutable forecast refs.
104
+ - Never start forecast generation before the strategy decision is durably
105
+ committed in the bound original main session.
63
106
  - Never fabricate Actuals, replace missing values with zero, or average row-level ratios.
64
107
  - Do not edit the approved forecast during projection.
65
108
  - Never relabel a backtest as `original`, `eac`, or `next_plan` to display it.
@@ -23,3 +23,25 @@ reviewed_at: timestamp
23
23
  ```
24
24
 
25
25
  Set `independence_confirmed: false` and `status: blocked` if the reviewer also authored the proposal. Any unresolved critical finding requires `reject`.
26
+
27
+ # `reviewed_strategy_handoff` contract
28
+
29
+ ```yaml
30
+ kind: fpa.reviewed-strategy-handoff
31
+ status: ready | blocked
32
+ scope_id: string
33
+ cycle_id: string
34
+ forecast_role: string
35
+ strategy_version: string
36
+ reviewed_strategy_version: string
37
+ proposal_fingerprint: sha256
38
+ review_fingerprint: sha256
39
+ reviewer_identity: string
40
+ independence_confirmed: true
41
+ review_opinion: support | support_with_conditions
42
+ review_conditions: []
43
+ review_residual_risks: []
44
+ next_graph: fpa-forecast-freeze
45
+ ```
46
+
47
+ `strategy_version` and `reviewed_strategy_version` must be identical and must bind the exact proposal reviewed. A rejected or non-independent review cannot produce a ready handoff.