feat: T4b/T4c wave 8 - weather history, phenology, honey chain, Telegram base
- Weather history from Open-Meteo behind an adapter: worker loop phenology-weather with backoff, Retry-After, User-Agent, chunked writes and forecast-to-archive correction - Phenology: growing degree sum per DWD, phase from reports, GTS and calendar, calibration from previous years, daily job step, SeasonService reads the stored state - Honey chain: prefill for extractions and batches (proposals only), plausibility and withdrawal warnings, Extraction lock, chain events and batch.created webhook from HoneyBatchRecorded - Telegram base: schema, NotificationDelivery outbox, hardened bot client, startup check without crash, no-network-outside-loops guard - ARCHITECTURE.md: sections 11.11-11.13, assumptions 42-46, env table Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
22382d53a2
commit
1971b2d9c4
90 files changed
+8431
-155
No files matched your search
@@ -50,6 +50,7 @@ describe('WithdrawalEventHandlers', () => {
|
||||
let check: {
|
||||
conflictsForHarvests: jest.Mock;
|
||||
conflictsForHoneyBatch: jest.Mock;
|
||||
conflictsForExtraction: jest.Mock;
|
||||
conflictsForTreatment: jest.Mock;
|
||||
notifyConflictsIn: jest.Mock;
|
||||
};
|
||||
@@ -64,6 +65,7 @@ describe('WithdrawalEventHandlers', () => {
|
||||
check = {
|
||||
conflictsForHarvests: jest.fn().mockResolvedValue([conflict]),
|
||||
conflictsForHoneyBatch: jest.fn().mockResolvedValue([conflict]),
|
||||
conflictsForExtraction: jest.fn().mockResolvedValue([conflict]),
|
||||
conflictsForTreatment: jest.fn().mockResolvedValue([conflict]),
|
||||
notifyConflictsIn: jest.fn().mockResolvedValue(1),
|
||||
};
|
||||
@@ -133,6 +135,37 @@ describe('WithdrawalEventHandlers', () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe('extraction check', () => {
|
||||
it('registers under its id', () => {
|
||||
expect(
|
||||
domainEventHandlerMetadata(
|
||||
Object.getOwnPropertyDescriptor(
|
||||
WithdrawalEventHandlers.prototype,
|
||||
'extractionCheck',
|
||||
)?.value as object,
|
||||
),
|
||||
).toEqual([
|
||||
{
|
||||
types: ['ExtractionRecorded', 'ExtractionCorrected'],
|
||||
handlerId: 'withdrawal.extraction-check',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it.each(['ExtractionRecorded', 'ExtractionCorrected'] as const)(
|
||||
'notifies the conflicts of the extraction on %s',
|
||||
async (type) => {
|
||||
await handlers.extractionCheck(
|
||||
envelope(type, 'e1', { harvestIds: ['h1'] }),
|
||||
asTx(),
|
||||
);
|
||||
|
||||
expect(check.conflictsForExtraction).toHaveBeenCalledWith(tx, 'e1');
|
||||
expect(check.notifyConflictsIn).toHaveBeenCalledWith(tx, [conflict]);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('treatment check', () => {
|
||||
it.each(['TreatmentRecorded', 'TreatmentCorrected'] as const)(
|
||||
'notifies harvests that already lie in the window of the treatment on %s',
|
||||
|
||||
Reference in new issue
Block a user