NEO-150: Document economy validation at issue and reconcile plan
Update server README, E7.M4 module doc, alignment register, and implementation plan reconciliation for E7M4-07.pull/192/head
parent
3d49230c3c
commit
d5de4e81ef
|
|
@ -59,6 +59,10 @@ Epic 7 **Slice 4** — `contract_issued`, `contract_complete`, reward anomalies.
|
|||
|
||||
**Generator operations (NEO-147):** **`ContractGeneratorOperations.TryIssue`** — template selection, deterministic instance ids, structured deny codes; [server README — Contract generator operations](../../../server/README.md#contract-generator-operations-neo-147).
|
||||
|
||||
**Economy validation at issue (NEO-150):** **`ContractEconomyValidation.TryValidateTemplate`** — band caps + reward-bundle cross-refs before persist; deny **`economy_cap_exceeded`** / **`invalid_reward_bundle`**; [server README — Contract generator operations](../../../server/README.md#contract-generator-operations-neo-147).
|
||||
|
||||
**Reward parity stub:** prototype band caps enforce Slice 4 policy only. Full [E6.M4](E6_M4_RewardParityEnforcer.md) **`RewardParityMap`** and [E3.M5](E3_M5_EconomyBalancePolicy.md) balance dashboards are deferred.
|
||||
|
||||
**Contract reward router (NEO-148):** **`RewardRouterOperations.TryDeliverContractCompletion`** — idempotent contract **`completionRewardBundle`** apply with key **`{playerId}:contract_complete:{contractInstanceId}`**; [server README — Reward router](../../../server/README.md#reward-router-neo-127).
|
||||
|
||||
**Contract completion wiring (NEO-149):** **`ContractCompletionOperations.TryCompleteOnEncounterClear`** — encounter clear completes matching active instance + outcome audit; [server README — Contract completion operations](../../../server/README.md#contract-completion-operations-neo-149).
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -118,7 +118,7 @@ Gameplay **content and curves** default to **boot load** with optional **dev-onl
|
|||
**E7.M3 note:** Epic 7 **Slice 3** backlog in Linear ([Epic 7 — Questing, Narrative, and Faction Reputation](https://linear.app/neon-sprawl/project/epic-7-questing-narrative-and-faction-reputation-a9416783ceee)): [NEO-133](https://linear.app/neon-sprawl/issue/NEO-133) → [NEO-143](https://linear.app/neon-sprawl/issue/NEO-143) **landed**; label **`E7.M3`**. See [E7M3-pre-production-backlog.md](../../plans/E7M3-pre-production-backlog.md), [E7_M3_FactionReputationLedger.md](E7_M3_FactionReputationLedger.md). Upstream: E7.M1 **Ready**, E7.M2 **Ready**. Prototype spine: two frozen factions; operator chain grants **+15 Grid Operators**; **`prototype_quest_grid_contract`** gated at **minStanding 15**; rep grants via **`completionRewardBundle.reputationGrants`**; accept deny **`faction_gate_blocked`**. **E7M3-11 / NEO-143** client capstone landed — [`NEO-143` manual QA](../../manual-qa/NEO-143.md), [client README — End-to-end faction reputation loop (NEO-143)](../../../client/README.md#end-to-end-faction-reputation-loop-neo-143), plan [NEO-143](../../plans/NEO-143-implementation-plan.md). Epic 7 Slice 3 client capstone complete.
|
||||
| E7.M4 | ContractMissionGenerator | E4.M1, E5.M3, E7.M3 | ContractTemplate, ContractSeed, ContractOutcome | Pre-production | In Progress |
|
||||
|
||||
**E7.M4 note:** Epic 7 **Slice 4** backlog in Linear ([Epic 7 — Questing, Narrative, and Faction Reputation](https://linear.app/neon-sprawl/project/epic-7-questing-narrative-and-faction-reputation-a9416783ceee)): [NEO-144](https://linear.app/neon-sprawl/issue/NEO-144) → [NEO-154](https://linear.app/neon-sprawl/issue/NEO-154); label **`E7.M4`**. See [E7M4-pre-production-backlog.md](../../plans/E7M4-pre-production-backlog.md), [E7_M4_ContractMissionGenerator.md](E7_M4_ContractMissionGenerator.md). **E7M4-01 / NEO-144** catalog + CI landed; **E7M4-02 / NEO-145** fail-fast server catalog load + **`IContractTemplateRegistry`** landed ([NEO-145 plan](../../plans/NEO-145-implementation-plan.md)); **E7M4-03 / NEO-146** contract instance + outcome stores landed ([NEO-146 plan](../../plans/NEO-146-implementation-plan.md)); **E7M4-04 / NEO-147** contract generator **`TryIssue`** landed ([NEO-147 plan](../../plans/NEO-147-implementation-plan.md)). Upstream: E5.M3 **Ready**, E7.M3 **Ready**; E4.M1 live zone read deferred (content-only **`zoneDifficultyBand`** in Slice 4 v1). Prototype spine: one template **`prototype_contract_clear_combat_pocket`** → **`prototype_combat_pocket`** encounter clear → repeat **`scrap_metal_bulk` ×5** + salvage XP; economy band caps at issue. Client capstone **E7M4-11** [NEO-154](https://linear.app/neon-sprawl/issue/NEO-154).
|
||||
**E7.M4 note:** Epic 7 **Slice 4** backlog in Linear ([Epic 7 — Questing, Narrative, and Faction Reputation](https://linear.app/neon-sprawl/project/epic-7-questing-narrative-and-faction-reputation-a9416783ceee)): [NEO-144](https://linear.app/neon-sprawl/issue/NEO-144) → [NEO-154](https://linear.app/neon-sprawl/issue/NEO-154); label **`E7.M4`**. See [E7M4-pre-production-backlog.md](../../plans/E7M4-pre-production-backlog.md), [E7_M4_ContractMissionGenerator.md](E7_M4_ContractMissionGenerator.md). **E7M4-01 / NEO-144** catalog + CI landed; **E7M4-02 / NEO-145** fail-fast server catalog load + **`IContractTemplateRegistry`** landed ([NEO-145 plan](../../plans/NEO-145-implementation-plan.md)); **E7M4-03 / NEO-146** contract instance + outcome stores landed ([NEO-146 plan](../../plans/NEO-146-implementation-plan.md)); **E7M4-04 / NEO-147** contract generator **`TryIssue`** landed ([NEO-147 plan](../../plans/NEO-147-implementation-plan.md)); **E7M4-07 / NEO-150** issue-time economy validation landed ([NEO-150 plan](../../plans/NEO-150-implementation-plan.md)). Upstream: E5.M3 **Ready**, E7.M3 **Ready**; E4.M1 live zone read deferred (content-only **`zoneDifficultyBand`** in Slice 4 v1). Prototype spine: one template **`prototype_contract_clear_combat_pocket`** → **`prototype_combat_pocket`** encounter clear → repeat **`scrap_metal_bulk` ×5** + salvage XP; economy band caps at issue. Client capstone **E7M4-11** [NEO-154](https://linear.app/neon-sprawl/issue/NEO-154).
|
||||
|
||||
### Epic 8 — Social / Guild
|
||||
|
||||
|
|
|
|||
|
|
@ -45,9 +45,17 @@ Slice 4 AC — issued contracts validate against **prototype economy caps** and
|
|||
|
||||
## Acceptance criteria checklist
|
||||
|
||||
- [ ] Template at freeze caps issues successfully.
|
||||
- [ ] Tampered catalog row over caps fails at startup (CI) and cannot issue if slipped through.
|
||||
- [ ] `dotnet test` covers economy validation gates.
|
||||
- [x] Template at freeze caps issues successfully.
|
||||
- [x] Tampered catalog row over caps fails at startup (CI) and cannot issue if slipped through.
|
||||
- [x] `dotnet test` covers economy validation gates.
|
||||
|
||||
## Implementation reconciliation (shipped)
|
||||
|
||||
- **`ContractEconomyValidation.TryValidateTemplate`** — delegates to `PrototypeE7M4ContractCatalogRules.TryGetBandCapGateError` + `TryGetCrossRefError` for one template row against live registries.
|
||||
- **`ContractGeneratorOperations.TryIssue`** — extended signature (encounter/item/skill/faction registries); economy validation after template selection, before persist.
|
||||
- **`ContractGeneratorReasonCodes`:** `economy_cap_exceeded`, `invalid_reward_bundle`.
|
||||
- **Tests:** `ContractEconomyValidationTests` (3 unit), `ContractGeneratorOperationsTests` (+2 deny paths); all `TryIssue` call sites updated; **911** tests green.
|
||||
- **Docs:** `server/README.md`, `E7_M4_ContractMissionGenerator.md`, alignment register, module dependency register.
|
||||
|
||||
## Technical approach
|
||||
|
||||
|
|
|
|||
|
|
@ -298,6 +298,8 @@ Completed instances are immutable (no status regression). Player, template, and
|
|||
- **Omitted/empty `templateId`:** first template from **`GetDefinitionsInIdOrder()`** matching band + standing.
|
||||
- Faction floor uses **`FactionGateOperations`** on the template **`minFactionStanding`** row.
|
||||
|
||||
**Economy validation (NEO-150):** after template selection, **`ContractEconomyValidation.TryValidateTemplate`** re-checks band caps and reward-bundle cross-refs against live encounter/item/skill/faction registries (same rules as startup catalog load). Fail-closed before persist.
|
||||
|
||||
**Deterministic instance id:** **`ContractInstanceIds.MakeDeterministicInstanceId`** — SHA-256 of `{playerId}|{templateId}|{seedBucket}` (normalized) → **`ci_{32 lowercase hex}`**.
|
||||
|
||||
**Reason codes:**
|
||||
|
|
@ -309,10 +311,12 @@ Completed instances are immutable (no status regression). Player, template, and
|
|||
| **`active_contract_exists`** | Player already has an active instance |
|
||||
| **`unknown_template`** | Explicit template id not in registry |
|
||||
| **`no_eligible_template`** | No template matches band + standing filters |
|
||||
| **`economy_cap_exceeded`** | Item qty, skill XP, or rep grant exceeds band policy |
|
||||
| **`invalid_reward_bundle`** | Unknown encounter/item/skill/faction ref or disallowed skill XP source |
|
||||
|
||||
**Result:** **`ContractIssueOperationResult`** — `success`, optional `reasonCode`, optional **`ContractInstanceState`** snapshot, **`encounterTemplateId`** from the selected template.
|
||||
|
||||
Economy band-cap lint at issue time lands in **NEO-150** (E7M4-07). HTTP **`POST …/contracts/issue`** lands in **NEO-151** (E7M4-08). Plan: [NEO-147 implementation plan](../../docs/plans/NEO-147-implementation-plan.md).
|
||||
HTTP **`POST …/contracts/issue`** lands in **NEO-151** (E7M4-08). Plan: [NEO-147 implementation plan](../../docs/plans/NEO-147-implementation-plan.md), [NEO-150 implementation plan](../../docs/plans/NEO-150-implementation-plan.md).
|
||||
|
||||
## Contract completion operations (NEO-149)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue