feat(domain): subscription grouping, coverage row states, auto-fill resolution and fill budget
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
99a3e17210
commit
e77fdc6549
4 files changed
+240
No files matched your search
@@ -0,0 +1,70 @@
|
||||
// 多版本自动补全(docs/design/subscriptions.md §2.2):非主版本目标在主版本已满足的单元上补下其他版本。
|
||||
// 开关按 订阅 → 规则组(链上后者优先)→ 系统缺省(开)取值;补全预算按订阅、按自然日计,超出记延后。
|
||||
|
||||
export type AutoFillModeValue = "inherit" | "on" | "off";
|
||||
|
||||
export interface AutoFillResolution {
|
||||
enabled: boolean;
|
||||
mode: AutoFillModeValue;
|
||||
source: "subscription" | "rule_group" | "default";
|
||||
/** source = rule_group 时,决定取值的规则组 */
|
||||
ruleGroupId?: string;
|
||||
}
|
||||
|
||||
/** groupFlags:订阅生效规则链上各组的 auto_fill(null = 未设),按链顺序 */
|
||||
export function resolveAutoFill(
|
||||
mode: AutoFillModeValue | undefined,
|
||||
groupFlags: readonly { id: string; autoFill: boolean | null }[] = [],
|
||||
systemDefault = true,
|
||||
): AutoFillResolution {
|
||||
if (mode === "on" || mode === "off") return { enabled: mode === "on", mode, source: "subscription" };
|
||||
for (let k = groupFlags.length - 1; k >= 0; k--) {
|
||||
const g = groupFlags[k]!;
|
||||
if (g.autoFill !== null) return { enabled: g.autoFill, mode: "inherit", source: "rule_group", ruleGroupId: g.id };
|
||||
}
|
||||
return { enabled: systemDefault, mode: "inherit", source: "default" };
|
||||
}
|
||||
|
||||
export interface FillBudgetLimits {
|
||||
bytesPerDay?: number | undefined;
|
||||
unitsPerDay?: number | undefined;
|
||||
}
|
||||
|
||||
export interface FillBudgetUsage {
|
||||
bytesToday: number;
|
||||
unitsToday: number;
|
||||
}
|
||||
|
||||
export interface FillBudgetDecision {
|
||||
allow: boolean;
|
||||
violations: { kind: "bytes" | "units"; limit: number; current: number; requested: number }[];
|
||||
}
|
||||
|
||||
/** 补全预算:未设的维度不限;请求体积未知时只看单元数(体积由全局预算的 unknown 规则兜底) */
|
||||
export function checkFillBudget(
|
||||
limits: FillBudgetLimits | undefined,
|
||||
usage: FillBudgetUsage,
|
||||
request: { bytes?: number | null | undefined; units: number },
|
||||
): FillBudgetDecision {
|
||||
const violations: FillBudgetDecision["violations"] = [];
|
||||
if (limits?.unitsPerDay !== undefined && usage.unitsToday + request.units > limits.unitsPerDay)
|
||||
violations.push({
|
||||
kind: "units",
|
||||
limit: limits.unitsPerDay,
|
||||
current: usage.unitsToday,
|
||||
requested: request.units,
|
||||
});
|
||||
if (
|
||||
limits?.bytesPerDay !== undefined &&
|
||||
request.bytes !== null &&
|
||||
request.bytes !== undefined &&
|
||||
usage.bytesToday + request.bytes > limits.bytesPerDay
|
||||
)
|
||||
violations.push({
|
||||
kind: "bytes",
|
||||
limit: limits.bytesPerDay,
|
||||
current: usage.bytesToday,
|
||||
requested: request.bytes,
|
||||
});
|
||||
return { allow: violations.length === 0, violations };
|
||||
}
|
||||
@@ -15,6 +15,15 @@ export {
|
||||
type ThresholdConfig,
|
||||
type VolumeSnapshot,
|
||||
} from "./disk.ts";
|
||||
export {
|
||||
type AutoFillModeValue,
|
||||
type AutoFillResolution,
|
||||
checkFillBudget,
|
||||
type FillBudgetDecision,
|
||||
type FillBudgetLimits,
|
||||
type FillBudgetUsage,
|
||||
resolveAutoFill,
|
||||
} from "./fill.ts";
|
||||
export { type AcquisitionMode, determineMode, type ModeDecision, type ModeInput } from "./mode.ts";
|
||||
export {
|
||||
DEFAULT_PRIORITY_ORDER,
|
||||
|
||||
Reference in new issue
Block a user