- packages/domain: zod schemas for the 07-scenario object set with a schemaRegistry driving schema export, fixture generation, and Python module naming; decimal-string/sha256/curve primitives enforce the docs/11 §3.3 representation rules at the type layer - contracts/: 12 JSON Schemas (draft 2020-12), 12 golden fixtures, 3 invalid fixtures crafted to fail on both sides (float money, bad digest, missing concurrency version) - skills-py: generated pydantic models (committed, never hand-edited), regeneration script, mirror pytest using JSON-mode validation — dual-side contract tests agree on all 15 fixtures - packages/services: content-addressed immutable snapshot store (memory + fs, rejects floats), LedgerService v1 with optimistic concurrency and the P7 constraint cascade (monthly position bounds day-ahead bids; no-anchor bids rejected), quality-gate stub - cascade band shape is an OPEN-QUESTION A5 placeholder (pro-rata daily share ±band) — see ledger.ts checkCascade All green: tsc typecheck, 41 TS tests, 15 Python tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019u5SLNweVio6ozJX7yfxQr 🔮 View transcript: https://logs.lojong.info/s/e8u90k3t33w590r7b5y7yzqh
49 lines
1.7 KiB
TypeScript
49 lines
1.7 KiB
TypeScript
import { z } from 'zod'
|
|
import { Curve96, DecimalString, Id, IsoUtc, MarketDate, Timescale } from './common.js'
|
|
import { ApprovalLevel } from './approval.js'
|
|
import { ProposalType } from './proposal.js'
|
|
|
|
/**
|
|
* Authority envelope (授权包络, downward): human-pre-approved autonomy bounds.
|
|
* Bound keys are type-specific and documented in docs/03 §3; initial values are
|
|
* OPEN-QUESTION B1/B2 — never hardcode them.
|
|
*/
|
|
export const Envelope = z.object({
|
|
id: Id,
|
|
scope: z.object({
|
|
proposal_type: ProposalType,
|
|
timescales: z.array(Timescale).min(1),
|
|
resource_set: Id,
|
|
}),
|
|
bounds: z.record(z.string(), DecimalString),
|
|
validity: z.object({ from: IsoUtc, to: IsoUtc }),
|
|
approval: z.object({ level: ApprovalLevel, approved_by: z.array(Id).min(1) }),
|
|
escalation: z.object({
|
|
max_consecutive_deviations: z.int().positive(),
|
|
deviation_threshold_pct: DecimalString,
|
|
}),
|
|
status: z.enum(['ACTIVE', 'SUSPENDED', 'EXPIRED']),
|
|
})
|
|
export type Envelope = z.infer<typeof Envelope>
|
|
|
|
/**
|
|
* Capability envelope (灵活性包络, upward): adjustable capacity report from an
|
|
* aggregation unit — the same schema crosses the federation boundary in
|
|
* phase 2 (docs/10 §5, no-rework reservation #1).
|
|
*/
|
|
export const FlexibilityEnvelope = z.object({
|
|
id: Id,
|
|
provider: z.object({
|
|
unit_id: Id,
|
|
level: z.enum(['SITE', 'AGGREGATION_UNIT', 'PROVINCE']),
|
|
}),
|
|
market_date: MarketDate,
|
|
up_mw: Curve96,
|
|
down_mw: Curve96,
|
|
valid_until: IsoUtc,
|
|
schema_version: z.string().min(1),
|
|
/** Signing arrives with federation (phase 2); null within-province. */
|
|
signature: z.string().nullable(),
|
|
})
|
|
export type FlexibilityEnvelope = z.infer<typeof FlexibilityEnvelope>
|