import { Injectable } from '@nestjs/common';
import { createHash } from 'node:crypto';
export interface DistributionChannelDemand {
channel: string;
requestedUnits: number;
unitValue: number;
acquisitionCost: number;
eligible?: boolean;
/** Optional policy cap; demand acquisition must never exceed it. */
maxAllocatableUnits?: number;
}
export interface DistributionAllocation {
channel: string;
requestedUnits: number;
allocatedUnits: number;
displacedUnits: number;
score: number;
blocker?: 'channel_ineligible' | 'economically_unfavorable' | 'channel_allocation_cap' | 'fulfillable_capacity';
}
export interface DistributionIntelligenceInput {
fulfillableCapacity: number;
channels: DistributionChannelDemand[];
}
export interface DistributionIntelligenceRecommendation {
/** Stable, non-secret fingerprint for correlating a recommendation with its inputs. */
decisionFingerprint: string;
fulfillableCapacity: number;
requestedDemand: number;
allocatedDemand: number;
displacedDemand: number;
allocations: DistributionAllocation[];
limitingFactors: Array<'fulfillable_capacity' | 'channel_eligibility' | 'economic_viability' | 'channel_allocation_cap'>;
evidence: {
capacitySource: 'fulfillable_capacity';
channelCount: number;
eligibleChannelCount: number;
policyCappedChannelCount: number;
ineligibleChannelCount: number;
economicallyUnfavorableChannelCount: number;
};
explanation: string;
requiresHumanConfirmation: true;
}
/**
* Produces a bounded channel-mix recommendation. It never creates demand
* above the capacity supplied by the operational truth layer and never
* activates a channel or campaign itself.
*/
@Injectable()
export class DistributionIntelligenceService {
recommend(input: DistributionIntelligenceInput): DistributionIntelligenceRecommendation {
if (!input || !Number.isSafeInteger(input.fulfillableCapacity) || input.fulfillableCapacity < 0 || !Array.isArray(input.channels) || input.channels.length > 100_000) {
throw new Error('distribution_intelligence.invalid');
}
const channels = input.channels.map((channel) => {
if (!channel || typeof channel !== 'object' || typeof channel.channel !== 'string' || (channel.eligible !== undefined && typeof channel.eligible !== 'boolean')) {
throw new Error('distribution_intelligence.invalid');
}
const name = channel.channel.trim();
if (!name || name.length > 120 || !Number.isSafeInteger(channel.requestedUnits) || channel.requestedUnits < 0 || !Number.isFinite(channel.unitValue) || channel.unitValue < 0 || !Number.isFinite(channel.acquisitionCost) || channel.acquisitionCost < 0 || (channel.maxAllocatableUnits !== undefined && (!Number.isSafeInteger(channel.maxAllocatableUnits) || channel.maxAllocatableUnits < 0))) {
throw new Error('distribution_intelligence.invalid');
}
return {
...channel,
channel: name,
eligible: channel.eligible !== false,
score: channel.unitValue - channel.acquisitionCost,
};
});
if (new Set(channels.map((channel) => channel.channel.toLowerCase())).size !== channels.length) {
throw new Error('distribution_intelligence.duplicate_channel');
}
const requestedDemand = channels.reduce((total, channel) => {
if (total > Number.MAX_SAFE_INTEGER - channel.requestedUnits) throw new Error('distribution_intelligence.invalid');
return total + channel.requestedUnits;
}, 0);
const decisionFingerprint = createHash('sha256').update(JSON.stringify({
fulfillableCapacity: input.fulfillableCapacity,
channels: [...channels]
.sort((left, right) => left.channel.localeCompare(right.channel))
.map((channel) => ({
channel: channel.channel,
requestedUnits: channel.requestedUnits,
unitValue: channel.unitValue,
acquisitionCost: channel.acquisitionCost,
eligible: channel.eligible,
maxAllocatableUnits: channel.maxAllocatableUnits ?? null,
})),
})).digest('hex').slice(0, 24);
let remainingCapacity = input.fulfillableCapacity;
const allocations = [...channels]
.sort((left, right) => right.score - left.score || left.channel.localeCompare(right.channel))
.map((channel): DistributionAllocation => {
if (!channel.eligible) {
return {channel: channel.channel, requestedUnits: channel.requestedUnits, allocatedUnits: 0, displacedUnits: channel.requestedUnits, score: channel.score, blocker: 'channel_ineligible'};
}
if (channel.score <= 0) {
return {channel: channel.channel, requestedUnits: channel.requestedUnits, allocatedUnits: 0, displacedUnits: channel.requestedUnits, score: channel.score, blocker: 'economically_unfavorable'};
}
const policyCap = channel.maxAllocatableUnits ?? channel.requestedUnits;
const availableCapacity = remainingCapacity;
const allocatedUnits = Math.min(channel.requestedUnits, policyCap, remainingCapacity);
remainingCapacity -= allocatedUnits;
const displacedUnits = channel.requestedUnits - allocatedUnits;
const blocker = displacedUnits > 0
? (allocatedUnits < Math.min(channel.requestedUnits, policyCap) && availableCapacity < policyCap ? 'fulfillable_capacity' as const : 'channel_allocation_cap' as const)
: undefined;
return {channel: channel.channel, requestedUnits: channel.requestedUnits, allocatedUnits, displacedUnits, score: channel.score, ...(blocker ? {blocker} : {})};
});
const allocatedDemand = allocations.reduce((total, allocation) => total + allocation.allocatedUnits, 0);
const limitingFactors = new Set<DistributionIntelligenceRecommendation['limitingFactors'][number]>();
if (requestedDemand > allocatedDemand && allocations.some((allocation) => allocation.blocker === 'fulfillable_capacity')) limitingFactors.add('fulfillable_capacity');
if (allocations.some((allocation) => allocation.blocker === 'channel_ineligible')) limitingFactors.add('channel_eligibility');
if (allocations.some((allocation) => allocation.blocker === 'economically_unfavorable')) limitingFactors.add('economic_viability');
if (allocations.some((allocation) => allocation.blocker === 'channel_allocation_cap')) limitingFactors.add('channel_allocation_cap');
return {
decisionFingerprint,
fulfillableCapacity: input.fulfillableCapacity,
requestedDemand,
allocatedDemand,
displacedDemand: requestedDemand - allocatedDemand,
allocations,
limitingFactors: [...limitingFactors],
evidence: {
capacitySource: 'fulfillable_capacity',
channelCount: channels.length,
eligibleChannelCount: channels.filter((channel) => channel.eligible).length,
policyCappedChannelCount: channels.filter((channel) => channel.maxAllocatableUnits !== undefined && channel.maxAllocatableUnits < channel.requestedUnits).length,
ineligibleChannelCount: allocations.filter((allocation) => allocation.blocker === 'channel_ineligible').length,
economicallyUnfavorableChannelCount: allocations.filter((allocation) => allocation.blocker === 'economically_unfavorable').length,
},
explanation: limitingFactors.size === 0 ? 'All eligible, economically favorable demand fits the fulfillable operational capacity.' : limitingFactors.size === 1 && limitingFactors.has('fulfillable_capacity') ? 'Demand was capped at the fulfillable operational capacity.' : 'Demand was bounded by operational capacity and channel policy constraints.',
requiresHumanConfirmation: true,
};
}
optimize(input: DistributionIntelligenceInput): DistributionIntelligenceRecommendation {
return this.recommend(input);
}
}
