문서 추가: 제약 조건 평가 계약 정의 및 데이터 요구 사항 명시

This commit is contained in:
2025-12-27 02:32:19 +00:00
parent c11527cce9
commit da89f87eaf
2 changed files with 112 additions and 0 deletions
@@ -47,6 +47,117 @@ Constraints are organized by domain:
Each constraint sets a failure reason string used by UI and logs.
## Rewrite Constraint Contract (Draft)
This section proposes a shared contract for the rewrite so both the turn daemon
(in-memory) and API server (DB-backed) can evaluate constraints consistently.
### Goals
- Single source of truth for constraint logic.
- Support full evaluation in daemon and precheck in API.
- Explicit data requirements for batching and caching.
- Deterministic reasons for deny vs unknown outcomes.
### Types (TypeScript sketch)
```ts
export type ConstraintResult =
| { kind: 'allow' }
| { kind: 'deny'; reason: string; code?: string }
| { kind: 'unknown'; missing: RequirementKey[] };
export type RequirementKey =
| { kind: 'general'; id: number }
| { kind: 'city'; id: number }
| { kind: 'nation'; id: number }
| { kind: 'destGeneral'; id: number }
| { kind: 'destCity'; id: number }
| { kind: 'destNation'; id: number }
| { kind: 'arg'; key: string }
| { kind: 'env'; key: string };
export interface ConstraintContext {
actorId: number;
cityId?: number;
nationId?: number;
destGeneralId?: number;
destCityId?: number;
destNationId?: number;
args: Record<string, unknown>;
env: Record<string, unknown>;
mode: 'full' | 'precheck';
}
export interface StateView {
has(req: RequirementKey): boolean;
get(req: RequirementKey): unknown | null;
}
export interface Constraint {
name: string;
requires(ctx: ConstraintContext): RequirementKey[];
test(ctx: ConstraintContext, view: StateView): ConstraintResult;
}
```
### Evaluation Flow
- `ConstraintPlanner` collects requirements across constraints.
- `StateView` loads those requirements (daemon: in-memory, API: DB).
- `test()` returns:
- `allow` if constraint passes.
- `deny` with a stable reason/code for UI.
- `unknown` if required data is missing and `mode === 'precheck'`.
```ts
function evaluateConstraints(
constraints: Constraint[],
ctx: ConstraintContext,
view: StateView,
): ConstraintResult {
for (const constraint of constraints) {
const missing = constraint.requires(ctx).filter((req) => !view.has(req));
if (missing.length && ctx.mode === 'precheck') {
return { kind: 'unknown', missing };
}
const result = constraint.test(ctx, view);
if (result.kind !== 'allow') {
return result;
}
}
return { kind: 'allow' };
}
```
### StateView Selection Boundary
The split between in-memory and DB-backed evaluation happens outside the
constraint logic. A factory or loader chooses the `StateView` implementation
based on the execution environment:
- Turn daemon -> `InMemoryStateView` with a full in-memory snapshot.
- API server -> `DbStateView` (or `ProjectedStateView`) that fetches only the
required fields from the DB or precomputed projections.
This keeps constraints pure and deterministic, while the infrastructure layer
decides how to satisfy `requires()` in each runtime.
### Mapping from Legacy Flags
- `REQ_GENERAL` -> `{ kind: 'general', id: actorId }`
- `REQ_CITY` -> `{ kind: 'city', id: cityId }`
- `REQ_NATION` -> `{ kind: 'nation', id: nationId }`
- `REQ_DEST_*` -> respective `dest` key
- `REQ_ARG` -> `{ kind: 'arg', key: <argName> }`
- `env` dependencies (for example `turnterm`, `year`) -> `{ kind: 'env', key: 'turnterm' }`
### Data Projection Suggestion
- API prechecks can rely on a small read model (for example `general_summary`)
updated by the turn daemon; `StateView` selects the source per requirement.
## Open Questions / Follow-ups
- Some constraints rely on `env` values (`turnterm`, `year`, etc.); document
+1
View File
@@ -8,6 +8,7 @@ Move items into the main docs once they are finalized.
- Turn daemon scheduling details and preemption rules
- Turn daemon vs API server priority policy under load
- In-memory state lifecycle and DBMS flush checkpoints
- [AI suggestion] Define a constraint evaluation contract with explicit data requirements and a tri-state result (allow/deny/unknown) to support DB-backed prechecks vs in-memory full checks.
- Recovery behavior after partial flush or crash
- Observability: metrics, logs, and alerts for turn processing
- [AI suggestion] Define a stable in-memory AI state contract (snapshot + delta invalidation rules) aligned with `GeneralAI` inputs.