@things-factory/headless-twin 10.0.14 โ 10.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-server/engine/attention-digest.d.ts +4 -4
- package/dist-server/engine/attention-digest.js +7 -7
- package/dist-server/engine/attention-digest.js.map +1 -1
- package/dist-server/engine/canonical-ingest.d.ts +11 -2
- package/dist-server/engine/canonical-ingest.js +137 -8
- package/dist-server/engine/canonical-ingest.js.map +1 -1
- package/dist-server/engine/command-routing.js +1 -1
- package/dist-server/engine/command-routing.js.map +1 -1
- package/dist-server/engine/declared-stimulus.js +1 -1
- package/dist-server/engine/declared-stimulus.js.map +1 -1
- package/dist-server/engine/energy-topology.js +1 -1
- package/dist-server/engine/energy-topology.js.map +1 -1
- package/dist-server/engine/ingest-dedupe.d.ts +38 -0
- package/dist-server/engine/ingest-dedupe.js +145 -0
- package/dist-server/engine/ingest-dedupe.js.map +1 -0
- package/dist-server/engine/ingest-health.d.ts +124 -9
- package/dist-server/engine/ingest-health.js +169 -15
- package/dist-server/engine/ingest-health.js.map +1 -1
- package/dist-server/engine/integration-probes.d.ts +3 -3
- package/dist-server/engine/integration-probes.js +6 -6
- package/dist-server/engine/integration-probes.js.map +1 -1
- package/dist-server/engine/kpi-baseline.js +4 -4
- package/dist-server/engine/kpi-baseline.js.map +1 -1
- package/dist-server/engine/kpi-fold.d.ts +122 -12
- package/dist-server/engine/kpi-fold.js +247 -18
- package/dist-server/engine/kpi-fold.js.map +1 -1
- package/dist-server/engine/kpi-query.d.ts +11 -11
- package/dist-server/engine/kpi-query.js +185 -28
- package/dist-server/engine/kpi-query.js.map +1 -1
- package/dist-server/engine/live-feed-registry.d.ts +1 -1
- package/dist-server/engine/live-feed-registry.js +1 -1
- package/dist-server/engine/live-feed-registry.js.map +1 -1
- package/dist-server/engine/load-meter.d.ts +1 -1
- package/dist-server/engine/load-meter.js.map +1 -1
- package/dist-server/engine/local-declarations.d.ts +7 -7
- package/dist-server/engine/local-declarations.js +9 -9
- package/dist-server/engine/local-declarations.js.map +1 -1
- package/dist-server/engine/log.d.ts +1 -1
- package/dist-server/engine/log.js +1 -1
- package/dist-server/engine/log.js.map +1 -1
- package/dist-server/engine/measured-estimator.js +1 -1
- package/dist-server/engine/measured-estimator.js.map +1 -1
- package/dist-server/engine/measured-yield.js +1 -1
- package/dist-server/engine/measured-yield.js.map +1 -1
- package/dist-server/engine/model-basis.d.ts +1 -1
- package/dist-server/engine/model-basis.js +1 -1
- package/dist-server/engine/model-basis.js.map +1 -1
- package/dist-server/engine/model-gap.d.ts +3 -3
- package/dist-server/engine/model-gap.js +1 -1
- package/dist-server/engine/model-gap.js.map +1 -1
- package/dist-server/engine/model-vocabulary.js +1 -1
- package/dist-server/engine/model-vocabulary.js.map +1 -1
- package/dist-server/engine/oee-accumulator.d.ts +4 -4
- package/dist-server/engine/oee-accumulator.js +3 -3
- package/dist-server/engine/oee-accumulator.js.map +1 -1
- package/dist-server/engine/property-effects.js +2 -2
- package/dist-server/engine/property-effects.js.map +1 -1
- package/dist-server/engine/read-time.d.ts +22 -0
- package/dist-server/engine/read-time.js +81 -0
- package/dist-server/engine/read-time.js.map +1 -0
- package/dist-server/engine/restart-policy.js +1 -1
- package/dist-server/engine/restart-policy.js.map +1 -1
- package/dist-server/engine/runtime-key.js +1 -1
- package/dist-server/engine/runtime-key.js.map +1 -1
- package/dist-server/engine/spec-coverage.d.ts +2 -2
- package/dist-server/engine/spec-coverage.js +1 -1
- package/dist-server/engine/spec-coverage.js.map +1 -1
- package/dist-server/engine/stage-path.d.ts +4 -4
- package/dist-server/engine/stage-path.js +1 -1
- package/dist-server/engine/stage-path.js.map +1 -1
- package/dist-server/engine/state-axes.d.ts +1 -1
- package/dist-server/engine/state-axes.js +2 -2
- package/dist-server/engine/state-axes.js.map +1 -1
- package/dist-server/engine/travel-estimator.d.ts +2 -2
- package/dist-server/engine/travel-estimator.js +1 -1
- package/dist-server/engine/travel-estimator.js.map +1 -1
- package/dist-server/engine/twin-engine.d.ts +243 -53
- package/dist-server/engine/twin-engine.js +690 -191
- package/dist-server/engine/twin-engine.js.map +1 -1
- package/dist-server/engine/warm-start.d.ts +2 -2
- package/dist-server/engine/warm-start.js +5 -5
- package/dist-server/engine/warm-start.js.map +1 -1
- package/dist-server/index.js +1 -1
- package/dist-server/index.js.map +1 -1
- package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js +1 -1
- package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +1 -1
- package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js +3 -3
- package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +1 -1
- package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js +2 -2
- package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +1 -1
- package/dist-server/migrations/1786300000000-IndexEventTypeByTime.d.ts +5 -0
- package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js +54 -0
- package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +1 -0
- package/dist-server/migrations/1786400000000-IndexEventCreatedAt.d.ts +5 -0
- package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js +44 -0
- package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +1 -0
- package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.d.ts +6 -0
- package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js +84 -0
- package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +1 -0
- package/dist-server/migrations/index.js +7 -1
- package/dist-server/migrations/index.js.map +1 -1
- package/dist-server/routes.d.ts +1 -0
- package/dist-server/routes.js +69 -5
- package/dist-server/routes.js.map +1 -1
- package/dist-server/service/index.d.ts +2 -2
- package/dist-server/service/index.js +27 -24
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/reference/control-routing.d.ts +1 -1
- package/dist-server/service/reference/control-routing.js +1 -1
- package/dist-server/service/reference/control-routing.js.map +1 -1
- package/dist-server/service/reference/discovery-result.d.ts +2 -2
- package/dist-server/service/reference/discovery-result.js +3 -3
- package/dist-server/service/reference/discovery-result.js.map +1 -1
- package/dist-server/service/reference/hook-contract.d.ts +43 -0
- package/dist-server/service/reference/hook-contract.js +59 -0
- package/dist-server/service/reference/hook-contract.js.map +1 -0
- package/dist-server/service/reference/ingest-space.d.ts +1 -1
- package/dist-server/service/reference/ingest-space.js +4 -4
- package/dist-server/service/reference/ingest-space.js.map +1 -1
- package/dist-server/service/reference/knob-defaults.d.ts +1 -1
- package/dist-server/service/reference/knob-defaults.js +4 -4
- package/dist-server/service/reference/knob-defaults.js.map +1 -1
- package/dist-server/service/reference/reference-adapter.d.ts +140 -8
- package/dist-server/service/reference/reference-adapter.js +27 -0
- package/dist-server/service/reference/reference-adapter.js.map +1 -1
- package/dist-server/service/reference/reference-hook.d.ts +20 -0
- package/dist-server/service/reference/reference-hook.js +133 -0
- package/dist-server/service/reference/reference-hook.js.map +1 -0
- package/dist-server/service/reference/reference-live.d.ts +2 -2
- package/dist-server/service/reference/reference-live.js +88 -13
- package/dist-server/service/reference/reference-live.js.map +1 -1
- package/dist-server/service/reference/reference-master.d.ts +14 -14
- package/dist-server/service/reference/reference-master.js +34 -12
- package/dist-server/service/reference/reference-master.js.map +1 -1
- package/dist-server/service/reference/reference-resolver.d.ts +1 -1
- package/dist-server/service/reference/reference-resolver.js +10 -10
- package/dist-server/service/reference/reference-resolver.js.map +1 -1
- package/dist-server/service/reference/twin-reference.d.ts +3 -3
- package/dist-server/service/reference/twin-reference.js.map +1 -1
- package/dist-server/service/twin-attention/twin-attention-query.d.ts +1 -1
- package/dist-server/service/twin-attention/twin-attention-query.js +1 -1
- package/dist-server/service/twin-attention/twin-attention-query.js.map +1 -1
- package/dist-server/service/twin-audit/command-audit.d.ts +1 -1
- package/dist-server/service/twin-audit/command-audit.js.map +1 -1
- package/dist-server/service/twin-audit/twin-audit-event.d.ts +1 -1
- package/dist-server/service/twin-audit/twin-audit-event.js.map +1 -1
- package/dist-server/service/twin-audit/twin-audit-query.js +1 -1
- package/dist-server/service/twin-audit/twin-audit-query.js.map +1 -1
- package/dist-server/service/twin-control/twin-control-mutation.js +1 -1
- package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
- package/dist-server/service/twin-event/twin-event-keys.d.ts +22 -2
- package/dist-server/service/twin-event/twin-event-keys.js +37 -5
- package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
- package/dist-server/service/twin-event/twin-event-type.d.ts +1 -0
- package/dist-server/service/twin-event/twin-event-type.js +8 -1
- package/dist-server/service/twin-event/twin-event-type.js.map +1 -1
- package/dist-server/service/twin-event/twin-event.d.ts +2 -2
- package/dist-server/service/twin-event/twin-event.js +32 -4
- package/dist-server/service/twin-event/twin-event.js.map +1 -1
- package/dist-server/service/twin-forecast/forecast-metrics.js +1 -1
- package/dist-server/service/twin-forecast/forecast-metrics.js.map +1 -1
- package/dist-server/service/twin-forecast/gap-analytics.d.ts +1 -1
- package/dist-server/service/twin-forecast/gap-analytics.js.map +1 -1
- package/dist-server/service/twin-forecast/twin-forecast-query.js +29 -11
- package/dist-server/service/twin-forecast/twin-forecast-query.js.map +1 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.d.ts +1 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js +1 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +1 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js +1 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +1 -1
- package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
- package/dist-server/service/twin-journal/event-type-split-shape.d.ts +50 -0
- package/dist-server/service/twin-journal/event-type-split-shape.js +111 -0
- package/dist-server/service/twin-journal/event-type-split-shape.js.map +1 -0
- package/dist-server/service/twin-journal/event-type-split.d.ts +15 -0
- package/dist-server/service/twin-journal/event-type-split.js +102 -0
- package/dist-server/service/twin-journal/event-type-split.js.map +1 -0
- package/dist-server/service/twin-journal/journal-order.d.ts +15 -0
- package/dist-server/service/twin-journal/journal-order.js +17 -0
- package/dist-server/service/twin-journal/journal-order.js.map +1 -0
- package/dist-server/service/twin-journal/twin-journal-query.d.ts +5 -5
- package/dist-server/service/twin-journal/twin-journal-query.js +232 -21
- package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -1
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +27 -1
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +59 -3
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
- package/dist-server/service/twin-metrics/twin-metrics-query.js +14 -1
- package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -1
- package/dist-server/service/twin-model/axis-journal-evidence.js +1 -1
- package/dist-server/service/twin-model/axis-journal-evidence.js.map +1 -1
- package/dist-server/service/twin-model/epcis-coverage.js +36 -1
- package/dist-server/service/twin-model/epcis-coverage.js.map +1 -1
- package/dist-server/service/twin-model/iec61850-coverage.js +1 -1
- package/dist-server/service/twin-model/iec61850-coverage.js.map +1 -1
- package/dist-server/service/twin-model/isa95-coverage.d.ts +15 -2
- package/dist-server/service/twin-model/isa95-coverage.js +32 -8
- package/dist-server/service/twin-model/isa95-coverage.js.map +1 -1
- package/dist-server/service/twin-model/item-ref.js +2 -2
- package/dist-server/service/twin-model/item-ref.js.map +1 -1
- package/dist-server/service/twin-model/name-index.d.ts +1 -1
- package/dist-server/service/twin-model/name-index.js +1 -1
- package/dist-server/service/twin-model/name-index.js.map +1 -1
- package/dist-server/service/twin-model/project-structure.d.ts +1 -1
- package/dist-server/service/twin-model/project-structure.js +3 -3
- package/dist-server/service/twin-model/project-structure.js.map +1 -1
- package/dist-server/service/twin-model/twin-equipment.d.ts +1 -1
- package/dist-server/service/twin-model/twin-equipment.js +1 -1
- package/dist-server/service/twin-model/twin-equipment.js.map +1 -1
- package/dist-server/service/twin-model/twin-lineage-query.js +16 -5
- package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-location.d.ts +1 -1
- package/dist-server/service/twin-model/twin-location.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-item-query.d.ts +3 -3
- package/dist-server/service/twin-model/twin-model-item-query.js +14 -14
- package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-mutation.d.ts +2 -2
- package/dist-server/service/twin-model/twin-model-mutation.js +4 -4
- package/dist-server/service/twin-model/twin-model-mutation.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-query.js +117 -28
- package/dist-server/service/twin-model/twin-model-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-tree-query.js +22 -0
- package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-operation.d.ts +1 -1
- package/dist-server/service/twin-model/twin-operation.js +1 -1
- package/dist-server/service/twin-model/twin-operation.js.map +1 -1
- package/dist-server/service/twin-space/move-space.js +2 -2
- package/dist-server/service/twin-space/move-space.js.map +1 -1
- package/dist-server/service/twin-space/representation-role.d.ts +2 -0
- package/dist-server/service/twin-space/representation-role.js +18 -0
- package/dist-server/service/twin-space/representation-role.js.map +1 -0
- package/dist-server/service/twin-space/space-integrity.d.ts +1 -1
- package/dist-server/service/twin-space/space-integrity.js.map +1 -1
- package/dist-server/service/twin-space/twin-space-representation.d.ts +2 -0
- package/dist-server/service/twin-space/twin-space-representation.js +16 -0
- package/dist-server/service/twin-space/twin-space-representation.js.map +1 -1
- package/dist-server/service/twin-space/twin-space-resolver.d.ts +2 -2
- package/dist-server/service/twin-space/twin-space-resolver.js +36 -7
- package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
- package/dist-server/service/twin-structure/twin-structure.js +3 -3
- package/dist-server/service/twin-structure/twin-structure.js.map +1 -1
- package/dist-server/service/twin-subject/event-subjects.d.ts +43 -0
- package/dist-server/service/twin-subject/event-subjects.js +137 -0
- package/dist-server/service/twin-subject/event-subjects.js.map +1 -0
- package/dist-server/service/twin-subject/index.d.ts +9 -0
- package/dist-server/service/twin-subject/index.js +16 -0
- package/dist-server/service/twin-subject/index.js.map +1 -0
- package/dist-server/service/twin-subject/item-resolver.d.ts +10 -0
- package/dist-server/service/twin-subject/item-resolver.js +93 -0
- package/dist-server/service/twin-subject/item-resolver.js.map +1 -0
- package/dist-server/service/twin-subject/subject-query-shape.d.ts +22 -0
- package/dist-server/service/twin-subject/subject-query-shape.js +88 -0
- package/dist-server/service/twin-subject/subject-query-shape.js.map +1 -0
- package/dist-server/service/twin-subject/twin-subject-backfill.d.ts +23 -0
- package/dist-server/service/twin-subject/twin-subject-backfill.js +159 -0
- package/dist-server/service/twin-subject/twin-subject-backfill.js.map +1 -0
- package/dist-server/service/twin-subject/twin-subject-event.d.ts +14 -0
- package/dist-server/service/twin-subject/twin-subject-event.js +111 -0
- package/dist-server/service/twin-subject/twin-subject-event.js.map +1 -0
- package/dist-server/service/twin-subject/twin-subject-fast-path.d.ts +39 -0
- package/dist-server/service/twin-subject/twin-subject-fast-path.js +295 -0
- package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +1 -0
- package/dist-server/service/twin-subject/twin-subject-query.d.ts +27 -0
- package/dist-server/service/twin-subject/twin-subject-query.js +232 -0
- package/dist-server/service/twin-subject/twin-subject-query.js.map +1 -0
- package/dist-server/service/twin-subject/twin-subject-writer.d.ts +27 -0
- package/dist-server/service/twin-subject/twin-subject-writer.js +166 -0
- package/dist-server/service/twin-subject/twin-subject-writer.js.map +1 -0
- package/dist-server/service/twin-target/twin-target-resolver.js +1 -1
- package/dist-server/service/twin-target/twin-target-resolver.js.map +1 -1
- package/dist-shared/entity-delta.d.ts +1 -1
- package/dist-shared/entity-delta.js +3 -3
- package/dist-shared/entity-delta.js.map +1 -1
- package/dist-shared/touched-items.js +2 -2
- package/dist-shared/touched-items.js.map +1 -1
- package/dist-shared/twin-level.js +1 -1
- package/dist-shared/twin-level.js.map +1 -1
- package/package.json +3 -3
- package/server/engine/attention-digest.ts +9 -9
- package/server/engine/canonical-ingest.ts +170 -13
- package/server/engine/command-routing.ts +1 -1
- package/server/engine/declared-stimulus.ts +1 -1
- package/server/engine/energy-topology.ts +1 -1
- package/server/engine/ingest-dedupe.ts +149 -0
- package/server/engine/ingest-health.ts +234 -20
- package/server/engine/integration-probes.ts +7 -7
- package/server/engine/kpi-baseline.ts +4 -4
- package/server/engine/kpi-fold.ts +395 -27
- package/server/engine/kpi-query.ts +212 -46
- package/server/engine/live-feed-registry.ts +1 -1
- package/server/engine/load-meter.ts +1 -1
- package/server/engine/local-declarations.ts +13 -13
- package/server/engine/log.ts +1 -1
- package/server/engine/measured-estimator.ts +1 -1
- package/server/engine/measured-yield.ts +1 -1
- package/server/engine/model-basis.ts +2 -2
- package/server/engine/model-gap.ts +3 -3
- package/server/engine/model-vocabulary.ts +1 -1
- package/server/engine/oee-accumulator.ts +4 -4
- package/server/engine/property-effects.ts +2 -2
- package/server/engine/read-time.ts +77 -0
- package/server/engine/restart-policy.ts +1 -1
- package/server/engine/runtime-key.ts +1 -1
- package/server/engine/spec-coverage.ts +3 -3
- package/server/engine/stage-path.ts +5 -5
- package/server/engine/state-axes.ts +2 -2
- package/server/engine/travel-estimator.ts +2 -2
- package/server/engine/twin-engine.ts +764 -201
- package/server/engine/warm-start.ts +6 -6
- package/server/index.ts +1 -1
- package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +1 -1
- package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +3 -3
- package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +2 -2
- package/server/migrations/1786300000000-IndexEventTypeByTime.ts +48 -0
- package/server/migrations/1786400000000-IndexEventCreatedAt.ts +38 -0
- package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +93 -0
- package/server/migrations/index.ts +7 -1
- package/server/routes.ts +68 -5
- package/server/service/index.ts +4 -1
- package/server/service/reference/control-routing.ts +1 -1
- package/server/service/reference/discovery-result.ts +3 -3
- package/server/service/reference/hook-contract.ts +103 -0
- package/server/service/reference/ingest-space.ts +4 -4
- package/server/service/reference/knob-defaults.ts +4 -4
- package/server/service/reference/reference-adapter.ts +166 -9
- package/server/service/reference/reference-hook.ts +145 -0
- package/server/service/reference/reference-live.ts +92 -14
- package/server/service/reference/reference-master.ts +39 -17
- package/server/service/reference/reference-resolver.ts +10 -10
- package/server/service/reference/twin-reference.ts +3 -3
- package/server/service/twin-attention/twin-attention-query.ts +1 -1
- package/server/service/twin-audit/command-audit.ts +1 -1
- package/server/service/twin-audit/twin-audit-event.ts +2 -2
- package/server/service/twin-audit/twin-audit-query.ts +1 -1
- package/server/service/twin-control/twin-control-mutation.ts +1 -1
- package/server/service/twin-event/twin-event-keys.ts +37 -5
- package/server/service/twin-event/twin-event-type.ts +18 -1
- package/server/service/twin-event/twin-event.ts +32 -6
- package/server/service/twin-forecast/forecast-metrics.ts +1 -1
- package/server/service/twin-forecast/gap-analytics.ts +1 -1
- package/server/service/twin-forecast/twin-forecast-query.ts +30 -11
- package/server/service/twin-ingest-window/twin-ingest-window-query.ts +1 -1
- package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +1 -1
- package/server/service/twin-instance/twin-instance.ts +4 -4
- package/server/service/twin-journal/event-type-split-shape.ts +112 -0
- package/server/service/twin-journal/event-type-split.ts +144 -0
- package/server/service/twin-journal/journal-order.ts +20 -0
- package/server/service/twin-journal/twin-journal-query.ts +224 -20
- package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +57 -3
- package/server/service/twin-metrics/twin-metrics-query.ts +14 -1
- package/server/service/twin-model/axis-journal-evidence.ts +1 -1
- package/server/service/twin-model/epcis-coverage.ts +36 -1
- package/server/service/twin-model/iec61850-coverage.ts +1 -1
- package/server/service/twin-model/isa95-coverage.ts +45 -8
- package/server/service/twin-model/item-ref.ts +2 -2
- package/server/service/twin-model/name-index.ts +1 -1
- package/server/service/twin-model/project-structure.ts +4 -4
- package/server/service/twin-model/twin-equipment.ts +2 -2
- package/server/service/twin-model/twin-lineage-query.ts +16 -5
- package/server/service/twin-model/twin-location.ts +1 -1
- package/server/service/twin-model/twin-model-item-query.ts +14 -14
- package/server/service/twin-model/twin-model-mutation.ts +4 -4
- package/server/service/twin-model/twin-model-query.ts +117 -28
- package/server/service/twin-model/twin-model-tree-query.ts +25 -1
- package/server/service/twin-model/twin-operation.ts +2 -2
- package/server/service/twin-space/move-space.ts +3 -3
- package/server/service/twin-space/representation-role.ts +15 -0
- package/server/service/twin-space/space-integrity.ts +1 -1
- package/server/service/twin-space/twin-space-representation.ts +37 -0
- package/server/service/twin-space/twin-space-resolver.ts +39 -7
- package/server/service/twin-structure/twin-structure.ts +3 -3
- package/server/service/twin-subject/event-subjects.ts +155 -0
- package/server/service/twin-subject/index.ts +10 -0
- package/server/service/twin-subject/item-resolver.ts +92 -0
- package/server/service/twin-subject/subject-query-shape.ts +84 -0
- package/server/service/twin-subject/twin-subject-backfill.ts +196 -0
- package/server/service/twin-subject/twin-subject-event.ts +101 -0
- package/server/service/twin-subject/twin-subject-fast-path.ts +346 -0
- package/server/service/twin-subject/twin-subject-query.ts +210 -0
- package/server/service/twin-subject/twin-subject-writer.ts +189 -0
- package/server/service/twin-target/twin-target-resolver.ts +1 -1
- package/shared/entity-delta.ts +3 -3
- package/shared/touched-items.ts +2 -2
- package/shared/twin-level.ts +1 -1
- package/test/adopt-structure-live.test.ts +3 -3
- package/test/aggregate-not-findone.test.ts +112 -0
- package/test/attention-digest.test.ts +6 -6
- package/test/axis-read.test.ts +2 -2
- package/test/boot-resume.test.ts +20 -7
- package/test/broadcast-period.test.ts +2 -2
- package/test/broadcast-queue-overflow.test.ts +244 -0
- package/test/canonical-ingest-vocabularies.test.ts +179 -7
- package/test/canonical-quantity-door.test.ts +2 -2
- package/test/checkpoint-refuses-empty.test.ts +2 -2
- package/test/connector-capability-declaration.test.ts +88 -0
- package/test/control-capability.test.ts +1 -1
- package/test/cursor-stall-not-read-failure.test.ts +2 -2
- package/test/declaration-reaches-model.test.ts +5 -5
- package/test/declared-stimulus.test.ts +4 -4
- package/test/discovery-result.test.ts +2 -2
- package/test/entity-delta.test.ts +4 -4
- package/test/event-subjects.test.ts +147 -0
- package/test/event-time-column.test.ts +3 -3
- package/test/event-type-split.test.ts +155 -0
- package/test/fold-gap-speaks.test.ts +53 -0
- package/test/forecast-metrics.test.ts +1 -1
- package/test/forecast-tuning.test.ts +1 -1
- package/test/ingest-health-engine.test.ts +2 -2
- package/test/ingest-health-wiring.test.ts +7 -5
- package/test/ingest-health.test.ts +6 -6
- package/test/ingest-history.test.ts +2 -2
- package/test/ingest-idempotent.test.ts +132 -0
- package/test/ingest-space.test.ts +3 -3
- package/test/integration-probes.test.ts +3 -3
- package/test/integration-runner.test.ts +1 -1
- package/test/item-ref.test.ts +1 -1
- package/test/journal-order-axis.test.ts +80 -0
- package/test/journal-read-discipline.test.ts +16 -6
- package/test/journal-retention.test.ts +171 -29
- package/test/journal-sort-axis.test.ts +1 -1
- package/test/journal-write-door.test.ts +3 -3
- package/test/journal-write-trend.test.ts +1 -1
- package/test/kernel-kind-guard.test.ts +3 -3
- package/test/knob-defaults.test.ts +1 -1
- package/test/kpi-baseline-db.test.ts +2 -2
- package/test/kpi-fold.test.ts +185 -14
- package/test/kpi-query-bench.test.ts +3 -3
- package/test/live-cursor-wiring.test.ts +6 -6
- package/test/live-kernel-facts.test.ts +11 -11
- package/test/live-mirror-parity.test.ts +3 -3
- package/test/load-meter.test.ts +1 -1
- package/test/local-declarations.test.ts +10 -10
- package/test/log-stamp.test.ts +1 -1
- package/test/measured-yield.test.ts +2 -2
- package/test/merge-streams.test.ts +70 -0
- package/test/mirror-resumes-from-checkpoint.test.ts +13 -13
- package/test/model-basis.test.ts +2 -2
- package/test/model-gap.test.ts +4 -4
- package/test/model-vocabulary.test.ts +2 -2
- package/test/move-space.test.ts +1 -1
- package/test/oee-accumulator.test.ts +2 -2
- package/test/operational-vocabulary.test.ts +2 -2
- package/test/project-structure-db.test.ts +2 -2
- package/test/projection-reaches-screen.test.ts +2 -2
- package/test/property-effects.test.ts +3 -3
- package/test/read-failure-ledger.test.ts +106 -0
- package/test/read-failure-visible.test.ts +7 -7
- package/test/read-time.test.ts +118 -0
- package/test/reference-grounding.test.ts +1 -1
- package/test/reference-hook.test.ts +86 -0
- package/test/registry-key-guard.test.ts +1 -1
- package/test/rename-twin.test.ts +81 -0
- package/test/restart-policy.test.ts +3 -3
- package/test/resync-origin-site.test.ts +3 -3
- package/test/revision-axis.test.ts +14 -8
- package/test/runtime-key.test.ts +3 -3
- package/test/snapshot-freshness.test.ts +4 -4
- package/test/source-outcome-audit.test.ts +1 -1
- package/test/space-integrity.test.ts +1 -1
- package/test/space-representation.test.ts +66 -0
- package/test/space-scope-includes-stopped.test.ts +55 -0
- package/test/spec-coverage.test.ts +1 -1
- package/test/standard-coverage.test.ts +43 -1
- package/test/status-tally.test.ts +1 -1
- package/test/structure-revision-db.test.ts +7 -7
- package/test/subject-fast-path.test.ts +148 -0
- package/test/subject-read-model.test.ts +175 -0
- package/test/touched-items.test.ts +2 -2
- package/test/twin-audit.test.ts +1 -1
- package/test/twin-event-keys.test.ts +49 -3
- package/test/twin-model-item-db.test.ts +5 -5
- package/test/twin-model-tree-db.test.ts +35 -2
- package/test/twin-origin-resync.test.ts +1 -1
- package/test/warm-start-seam.test.ts +1 -1
- package/test/warm-start.test.ts +6 -6
- package/test/withheld-door.test.ts +95 -0
- package/test/yield-loop.test.ts +4 -4
- package/tsconfig.shared.tsbuildinfo +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
* โโ ํ ์ง๋ฌธ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
6
6
|
* ํ๋ฉด์์ ๊ฐ์ด ๋ณํ์ง ์์ ๋ ์์ธ์ด ๋ท์ธ๋ฐ, ์ง๊ธ๊น์ง **๋ท์ด ๋๊ฐ์ด ๋ณด์๋ค.**
|
|
7
7
|
* โ ํผ๋๊ฐ ๋ถ์ง ์์๋ค โก ๋ถ์๋๋ฐ ์๋ฌด๊ฒ๋ ์ค์ง ์๋๋ค
|
|
8
|
-
* โข ์ค๋๋ฐ ์ ๋ถ ๊ฑฐ๋ถ๋๋ค โฃ ์ ์์ธ๋ฐ ํ์ฅ์ด
|
|
8
|
+
* โข ์ค๋๋ฐ ์ ๋ถ ๊ฑฐ๋ถ๋๋ค โฃ ์ ์์ธ๋ฐ ํ์ฅ์ด ๋ค์ด์จ ๊ฒ์ด ์๋ค
|
|
9
9
|
* โข์ ํนํ ๋์๋ค โ ์ปค๋ฅํฐ์ ๋งคํ์ด ํ ๊ธ์ ํ๋ฆฌ๋ฉด ํธ์์ ใ๋น ๊ณต์ฅใ์ด ๋๊ณ , ๊ทธ ์ฌ์ค์ด ์๋ฒ ๋ก๊ทธ
|
|
10
10
|
* ํ ์ค์๋ง ๋จ์๋ค. ํ์ฅ์ ๋๊ฐ ์ฌ๋์ ๋ก๊ทธ๋ฅผ ๋ค์ ธ์ผ ํ๋ค.
|
|
11
11
|
*
|
|
12
12
|
* โโ ์ ์ ๋๋ก๋ ๋ตํ ์ ์๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
13
|
-
* **๊ฑฐ๋ถ๋ ๊ฒ์ ์ ๋์ ์๋ค** โ ๊ฑฐ๋ถ์ ๋ป์ด ๊ทธ๊ฒ์ด๋ค. ์ ๋์
|
|
13
|
+
* **๊ฑฐ๋ถ๋ ๊ฒ์ ์ ๋์ ์๋ค** โ ๊ฑฐ๋ถ์ ๋ป์ด ๊ทธ๊ฒ์ด๋ค. ์ ๋์ ๊ณ์ฐํ๋ฉด ํต๊ณผํ ์ชฝ๋ง ๋์จ๋ค. ๊ฑฐ๋ถ์ ์ถ์ด๋
|
|
14
14
|
* ์ธ๋ ์๋ฆฌ๋ฅผ ๋ฐ๋ก ๋์ด์ผ ๋์จ๋ค. ์ด ์ฅ๋ถ๊ฐ ๊ทธ ์๋ฆฌ๋ค.
|
|
15
15
|
*
|
|
16
16
|
* โโ ์ ๊ฑด๋ง๋ค ์ ์ฅํ์ง ์๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -24,14 +24,18 @@
|
|
|
24
24
|
* โโ ์งํค๋ ๊ท์จ ๋ท โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
25
25
|
* โ **๋ซํ ์ฐฝ๋ง ใ์ต๊ทผใ์ด๋ค** โ ์ฑ์ฐ๋ ์ค์ธ ์ฐฝ์ ๊ณผ์ ์ง๊ณ๋ค(๋ถํ ๊ณ๊ธฐํ์์ ๊ฒช์๋ค).
|
|
26
26
|
* โก **0 ๊ณผ ใ์์ใ์ ๊ฐ๋ฅธ๋ค** โ ์ ๋ฐ์ ๊ฒ์ `null`, ๋ฐ์์ง๋ง ๊ฑฐ๋ถ 0 ์ `0`.
|
|
27
|
-
* โข
|
|
27
|
+
* โข **์๋ฆฌ์ง ์๊ณ ์๋ฅด์ง ์๋๋ค** โ ํ๋ณธยท์ถ์ด ์ํ์์ ๋ฐ๋ ค๋ ์๋ฅผ ํจ๊ป ๋ธ๋ค.
|
|
28
28
|
* โฃ **ํต๊ณผ์จ์ 1 ์ ํจ๋ถ๋ก ์ฐ์ง ์๋๋ค** โ 1,000๊ฑด ์ค 1๊ฑด ๊ฑฐ๋ถ๋ 0.999 ๋ค.
|
|
29
29
|
*/
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
31
|
exports.HEALTHY_ACCEPTED_RATIO = exports.RECORD_MAX = exports.SAMPLE_LIMIT = exports.OTHER_REASON = exports.REASON_LIMIT = exports.TREND_LIMIT = exports.STALE_AFTER_MS = exports.INGEST_WINDOW_MS = void 0;
|
|
32
32
|
exports.recordReadFailure = recordReadFailure;
|
|
33
|
+
exports.recordRecovered = recordRecovered;
|
|
33
34
|
exports.clearReadFailure = clearReadFailure;
|
|
34
35
|
exports.recordCursorStall = recordCursorStall;
|
|
36
|
+
exports.recordIngestSource = recordIngestSource;
|
|
37
|
+
exports.recordDuplicates = recordDuplicates;
|
|
38
|
+
exports.recordWithheld = recordWithheld;
|
|
35
39
|
exports.clearCursorStall = clearCursorStall;
|
|
36
40
|
exports.newIngestLedger = newIngestLedger;
|
|
37
41
|
exports.rollIngestWindow = rollIngestWindow;
|
|
@@ -46,21 +50,44 @@ exports.ingestHealth = ingestHealth;
|
|
|
46
50
|
* ์ฐ์ ์คํจ์ ์์ ์๊ฐ์ ์งํค๋ ๊ฒ์ด ์ด ํจ์์ ์์ ์ด๋ค: ๋งค๋ฒ ์๋ก ์ ์ผ๋ฉด ใ20๋ถ์งธ ๋ชป ์ฝ๋๋คใ๋ฅผ
|
|
47
51
|
* ๋งํ ์ ์๊ณ , ํ๋ฉด์ ๋ ใ๋ฐฉ๊ธ ์คํจํ๋คใ๋ง ๋ณด๊ฒ ๋๋ค.
|
|
48
52
|
*/
|
|
49
|
-
function recordReadFailure(ledger, reason, nowMs, stream
|
|
53
|
+
function recordReadFailure(ledger, reason, nowMs, stream,
|
|
54
|
+
/**
|
|
55
|
+
* ๋ค์์ ๋ค์ ๋ฌผ์ ๋๊น์ง ๋จ์ ์๊ฐ(ms) โ ์ปค๋ฅํฐ๊ฐ ๋ฌผ๋ฌ์ฐ์ผ๋ฉด ๊ทธ ๊ฐ์ ์ค๋ค (2026-08-27).
|
|
56
|
+
*
|
|
57
|
+
* ์ด๊ฒ์ด ์์ผ๋ฉด ํ๋ฉด์ด ใ๋ฟ์ง ๋ชปํ๊ณ ์๋คใ๊น์ง๋ง ๋งํ๊ณ , ์ฌ๋์ **์ธ์ ๋ค์ ์๋ํ๋์ง** ์ ์
|
|
58
|
+
* ์๋ค. ๊ทธ๋ฌ๋ฉด ๊ธฐ๋ค๋ ค์ผ ํ๋์ง ์์ ์จ์ผ ํ๋์ง ํ๋จํ์ง ๋ชปํ๋ค.
|
|
59
|
+
*
|
|
60
|
+
* **์ฐ๋ฌ์ ํ์์ ์์ ์๊ฐ์ ์ปค๋ฅํฐ๊ฐ ๋ณด๋ด์ง ์๋๋ค** โ ์ด ํจ์๊ฐ ์ด๋ฏธ ์ผ๋ค. ๋ ๊ณณ์์ ์ธ๋ฉด
|
|
61
|
+
* ๊ฐ๋ผ์ง๊ณ , ๊ฐ๋ผ์ง๋ฉด ์ด๋ ์ชฝ์ด ์ฌ์ค์ธ์ง ์ ์ ์๋ค.
|
|
62
|
+
*/
|
|
63
|
+
nextRetryMs) {
|
|
50
64
|
const prev = ledger.readFailure;
|
|
51
65
|
ledger.readFailure = {
|
|
52
66
|
consecutive: (prev?.consecutive ?? 0) + 1,
|
|
53
67
|
sinceMs: prev?.sinceMs ?? nowMs,
|
|
54
68
|
lastAtMs: nowMs,
|
|
55
69
|
reason,
|
|
56
|
-
...(stream ? { stream } : {})
|
|
70
|
+
...(stream ? { stream } : {}),
|
|
71
|
+
...(Number.isFinite(nextRetryMs) && nextRetryMs > 0 ? { nextRetryMs: nextRetryMs } : {})
|
|
57
72
|
};
|
|
58
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* **๋๊ฒผ๋ค๊ฐ ๋์์๋ค** โ ๊ทธ ์ฌ์ค์ ๋จ๊ธด๋ค (2026-08-27).
|
|
76
|
+
*
|
|
77
|
+
* ์คํจ ๊ธฐ๋ก๋ง ์ง์ฐ๋ฉด ใ๋๊ธด ์ ์ด ์์๋คใ๊ฐ ํ๋ฉด์์ ์ฌ๋ผ์ง๋ค. ๊ทธ๋ฌ๋ฉด ๋ฐค์ ๋ ์๊ฐ ๋๊ฒผ๋ ์ฐ๊ฒฐ๊ณผ ํ
|
|
78
|
+
* ๋ฒ๋ ๋๊ธฐ์ง ์์ ์ฐ๊ฒฐ์ด ์์นจ์ ๋๊ฐ์ด ๋ณด์ธ๋ค. ๋ช ๋ฒ ์คํจํ ๋ค์ ๋์์๋์ง, ์ผ๋ง๋ ๋๊ฒผ๋์ง๋ฅผ ํจ๊ป
|
|
79
|
+
* ๋จ๊ธด๋ค.
|
|
80
|
+
*/
|
|
81
|
+
function recordRecovered(ledger, afterFailures, downMs, nowMs) {
|
|
82
|
+
if (ledger.readFailure)
|
|
83
|
+
delete ledger.readFailure;
|
|
84
|
+
ledger.lastRecovery = { atMs: nowMs, afterFailures, downMs };
|
|
85
|
+
}
|
|
59
86
|
/**
|
|
60
87
|
* ์ฝ๊ธฐ๊ฐ ์ฑ๊ณตํ๋ค โ ๋จ์ ๊ธฐ๋ก์ ์ง์ด๋ค.
|
|
61
88
|
*
|
|
62
89
|
* **๋น ์ฝ๊ธฐ๋ ์ฑ๊ณต์ด๋ค**: ์๋ณธ์ด ใ์ ๊ฒ์ด ์๋คใ๊ณ ๋ตํ ๊ฒ์ ๋ฟ์๋ค๋ ๋ป์ด๋ค. ๊ทธ ๋์ ๊ฐ๊ฒ ๋๋ฉด
|
|
63
|
-
*
|
|
90
|
+
* ๋ค์ด์จ ๊ฒ์ด ์๋ ์ฐ๊ฒฐ์ด ๋๊ธด ์๋ณธ์ผ๋ก ๋ณด์ธ๋ค(๊ณ ์น๋ ค๋ ๊ฒ์ ๋ฐ๋ ๋ฐฉํฅ์ผ๋ก ํ๋ฆฐ๋ค).
|
|
64
91
|
*/
|
|
65
92
|
function clearReadFailure(ledger) {
|
|
66
93
|
if (ledger.readFailure)
|
|
@@ -83,6 +110,48 @@ function recordCursorStall(ledger, reason, nowMs, stream) {
|
|
|
83
110
|
...(stream ? { stream } : {})
|
|
84
111
|
};
|
|
85
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* **์ธ์ฐ์ง ์์ ๊ฒ์ ์ ๋๋ค** โ ์ด์ ๋ณ ๋์ .
|
|
115
|
+
*
|
|
116
|
+
* ์ฃผ๊ธฐ๋ง๋ค ๋ค์ ์๋ ค๋ ์๋๋ฌ์์ง์ง ์๊ฒ **์ด์ ๋ก ๋ฌถ์ด ์ผ๋ค**(์ค์ด ๋์ง ์๋๋ค). ๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง ์๊ฐ์
|
|
117
|
+
* ํจ๊ป ๋ ๋ค โ ใ์ง๊ธ๋ ๊ทธ๋ฐ๊ฐใ์ ใํ๋ ๊ทธ๋ฌ๋ใ๋ ๋ค๋ฅธ ์ฌ์ค์ด๊ณ , ์๊ฐ ์์ด๋ ๊ตฌ๋ณํ ์ ์๋ค.
|
|
118
|
+
*
|
|
119
|
+
* ์ด์ ๊ฐ ๊ฐ๊ณ ์๊ฐ ๋ฌ๋ผ์ง๋ฉด **๋ง์ง๋ง ์๋ก ๋ฎ๋๋ค**: ์ด๊ฒ์ ๋์ ์ฌ๊ฑด์ด ์๋๋ผ **์ง๊ธ ์ธ์ฐ์ง ์์ ๊ฒ์
|
|
120
|
+
* ์**๋ค. ์ฃผ๊ธฐ๋ง๋ค 8๊ฑด์ด๋ฉด 8์ด๊ณ , ๋ํด์ 800์ด ๋๋ฉด ๊ฑฐ์ง์ด๋ค.
|
|
121
|
+
*/
|
|
122
|
+
/**
|
|
123
|
+
* ์ด๋ค ๊ธธ๋ก ๋ช ๊ฑด์ด ๋ค์ด์๋ โ ๊ฒฝ๋ก ์ด๋ฆ์ ๋ถ๋ฅด๋ ์ชฝ์ด ์ ํ๋ค.
|
|
124
|
+
*
|
|
125
|
+
* ์ด๋ฆ์ ์์ ๋ฌธ์์ด๋ก ๋๋ ์ด์ : ๊ธธ์ด ๋์ด๋๋ค(์ง๊ธ์ ๋ฌผ์ด๋ณด๊ธฐยท์๋๋ฆฌ์คยท๋ถํ ๋๊ตฌ, ๋ค์์ ์นํ
).
|
|
126
|
+
* ์ด๊ฑฐ๋ก ๋ชป ๋ฐ์ผ๋ฉด ์ ๊ธธ์ด ์๊ธธ ๋ ์ด ํ์ผ์ ํจ๊ป ๊ณ ์ณ์ผ ํ๊ณ , ์์ผ๋ฉด ๊ทธ ๊ธธ์ด ํต๊ณ์์ ์ฌ๋ผ์ง๋ค.
|
|
127
|
+
*/
|
|
128
|
+
function recordIngestSource(ledger, source, count, nowMs) {
|
|
129
|
+
const key = String(source ?? '').trim() || 'unknown';
|
|
130
|
+
if (count <= 0)
|
|
131
|
+
return;
|
|
132
|
+
const cur = (ledger.bySource[key] ??= { count: 0, lastAtMs: -1 });
|
|
133
|
+
cur.count += count;
|
|
134
|
+
cur.lastAtMs = nowMs;
|
|
135
|
+
}
|
|
136
|
+
/** ๊ฐ์ ์ฌ์ค์ด ๋ ๋ฒ ์์ ๋ฒ๋ฆฐ ์ โ ์๋ฆฌ์ง ์๊ณ ๋ฒ๋ฆฌ์ง ์๋๋ค. */
|
|
137
|
+
function recordDuplicates(ledger, count, nowMs) {
|
|
138
|
+
if (count <= 0)
|
|
139
|
+
return;
|
|
140
|
+
ledger.duplicates += count;
|
|
141
|
+
ledger.lastDuplicateAtMs = nowMs;
|
|
142
|
+
}
|
|
143
|
+
function recordWithheld(ledger, reason, count, nowMs) {
|
|
144
|
+
if (!reason || !(count > 0))
|
|
145
|
+
return;
|
|
146
|
+
const list = (ledger.withheld ??= []);
|
|
147
|
+
const at = list.find(w => w.reason === reason);
|
|
148
|
+
if (at) {
|
|
149
|
+
at.count = count;
|
|
150
|
+
at.lastAtMs = nowMs;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
list.push({ reason, count, lastAtMs: nowMs });
|
|
154
|
+
}
|
|
86
155
|
/** ์ฐฝ์ ๋๊ฒผ์ผ๋ฉด ์ง์ด๋ค โ ํ๋ฆฐ ์ ์ฒด๊ฐ ํ๋ฉด์ ๋จ์ ์์ผ๋ฉด ๊ทธ๊ฒ๋ ๊ฑฐ์ง์ด๋ค. */
|
|
87
156
|
function clearCursorStall(ledger) {
|
|
88
157
|
if (ledger.cursorStall)
|
|
@@ -106,7 +175,7 @@ exports.TREND_LIMIT = 36;
|
|
|
106
175
|
* (`unknown bizStep "PUTAWAY_X17"`, `โฆX18`, โฆ) ํค๊ฐ ๋ฌดํํ ๋์ด๋๋ค. ์ด๋น 1๋ง ๊ฑด ๊ท๋ชจ์์ ์ด๊ฒ์
|
|
107
176
|
* ๋ฏธ๋ฏธํ ์ค๋ฒํค๋๊ฐ ์๋๋ผ ๋์๋ค.
|
|
108
177
|
*
|
|
109
|
-
* ๋์น๋ฉด `OTHER_REASON` ํ ์นธ์ ๋ชจ์ผ๊ณ **๋ช ์ข
์
|
|
178
|
+
* ๋์น๋ฉด `OTHER_REASON` ํ ์นธ์ ๋ชจ์ผ๊ณ **๋ช ์ข
์ ๋ชจ์๋์ง ํจ๊ป ๋ธ๋ค**(์๋ฆฌ์ง ์๊ณ ์๋ฅด์ง ์๋๋ค).
|
|
110
179
|
* 30์ข
์ด๋ฉด ๊ณ ์น ๊ณณ์ ์ฐพ๊ธฐ์ ์ถฉ๋ถํ๋ค โ ๋ชฉ๋ก์ ํ๋ ์ผ์ด ์๋๋ผ ๋งคํ ๋ช ์ค์ ๊ณ ์น๋ ์ผ์ด๋ค.
|
|
111
180
|
*/
|
|
112
181
|
exports.REASON_LIMIT = 30;
|
|
@@ -142,6 +211,9 @@ function newIngestLedger() {
|
|
|
142
211
|
flushes: 0,
|
|
143
212
|
lastWriteAtMs: -1,
|
|
144
213
|
lastUndeliveredAtMs: -1,
|
|
214
|
+
bySource: {},
|
|
215
|
+
duplicates: 0,
|
|
216
|
+
lastDuplicateAtMs: -1,
|
|
145
217
|
byReason: {},
|
|
146
218
|
reasonsCapped: false,
|
|
147
219
|
sampledReasons: new Set(),
|
|
@@ -230,7 +302,7 @@ undelivered = 0) {
|
|
|
230
302
|
for (const it of items) {
|
|
231
303
|
const raw = reasonKey(it?.errors);
|
|
232
304
|
const known = raw in ledger.byReason;
|
|
233
|
-
/* ์ฌ์ ์ข
๋ฅ ์ํ โ ๋์น๋ฉด ํ ์นธ์ผ๋ก
|
|
305
|
+
/* ์ฌ์ ์ข
๋ฅ ์ํ โ ๋์น๋ฉด ํ ์นธ์ผ๋ก ๋ชจ์ผ๊ณ , **๋ฟ์๋ค๋ ์ฌ์ค**์ ํ์ํ๋ค. */
|
|
234
306
|
let key = raw;
|
|
235
307
|
if (!known && Object.keys(ledger.byReason).length >= exports.REASON_LIMIT) {
|
|
236
308
|
key = exports.OTHER_REASON;
|
|
@@ -286,14 +358,14 @@ function recordJournalWrite(ledger, rows, nowMs, onClosed) {
|
|
|
286
358
|
/*
|
|
287
359
|
* **`lastAtMs` ๋ ๊ฑด๋๋ฆฌ์ง ์๋๋ค.** ๊ทธ ๊ฐ์ ใ๋ง์ง๋ง ์ ์
ใ์ด๊ณ , ๋๊ธด ํผ๋๋ฅผ ๊ฐ๋ ค๋ด๋ ๊ทผ๊ฑฐ๋ค. ์ฐ๊ธฐ๋ก
|
|
288
360
|
* ๊ฐฑ์ ํ๋ฉด ๋ผ์ด๋ธ ํธ์์ ์ ์
์ด ๋๊ฒจ๋ ํฑ์ด ๋ง๋ ๋ธํ๋ฅผ ๊ณ์ ์ ์ผ๋ฏ๋ก **์์ํ ใ๋ฐฉ๊ธ ๋ฐ์๋คใ**๊ฐ ๋๊ณ ,
|
|
289
|
-
* ใ์ค๋ ๋๊ธด ํผ๋์ ์ ์ฐฝ์ผ๋ก ์ด๋ก์ ๋ด์ง ์๋๋คใ๊ฐ
|
|
361
|
+
* ใ์ค๋ ๋๊ธด ํผ๋์ ์ ์ฐฝ์ผ๋ก ์ด๋ก์ ๋ด์ง ์๋๋คใ๊ฐ ์ค๋ฅ ํ๋ ์์ด ๋ฌด๋ ฅํด์ง๋ค. ์ถ์ ๋ฐ๋ก ๋ ๋ค.
|
|
290
362
|
*/
|
|
291
363
|
ledger.lastWriteAtMs = nowMs;
|
|
292
364
|
}
|
|
293
365
|
function syncVerdictOf(args) {
|
|
294
366
|
/*
|
|
295
367
|
* โโ ๋ฒ๋ ค์ง๊ณ ์๋ ๊ฒ์ด ๊ฐ์ฅ ๋จผ์ ๋ค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
296
|
-
* ํธ์์ด ๋ฉ์ถ๋ฉด ํผ๋๋ ๋จ์ ๊ณ์ ๋ ์ฝ๋๋ฅผ ๋๋ฅด๊ณ , ์ปค๋์ ๊ทธ๊ฒ์
|
|
368
|
+
* ํธ์์ด ๋ฉ์ถ๋ฉด ํผ๋๋ ๋จ์ ๊ณ์ ๋ ์ฝ๋๋ฅผ ๋๋ฅด๊ณ , ์ปค๋์ ๊ทธ๊ฒ์ ์๋ฆฌ์ง ์๊ณ ๋ฒ๋ฆฐ๋ค. ๊ทธ ์ํ๋ฅผ ใํด๋น ์์ใ
|
|
297
369
|
* ์ด๋ผ ๋ถ๋ฅด๋ฉด **์ฌ์ค์ด ์ฌ๋ผ์ง๋ ๋์ ํ๋ฉด์ด ์์ฌ์ํจ๋ค** โ ์ค์ ๋ก ๊ทธ๋ ๊ฒ ๋ด๋ค(๋ฉ์ถ ํธ์ ์์ ใ150
|
|
298
370
|
* ํต๊ณผ ยท 100%ใ). ๊ทธ๋์ ์๋ฎฌยท๋ฉ์ถค ํ์ ๋ณด๋ค ๋จผ์ ๋ณธ๋ค.
|
|
299
371
|
*
|
|
@@ -331,8 +403,29 @@ function syncVerdictOf(args) {
|
|
|
331
403
|
if (args.nowMs - args.lastAtMs > exports.STALE_AFTER_MS)
|
|
332
404
|
return 'no-traffic';
|
|
333
405
|
}
|
|
334
|
-
|
|
335
|
-
|
|
406
|
+
/*
|
|
407
|
+
* โโ **๋ฟ์๋๋ฐ ์ค๋ ๊ฒ์ด ์๋ค** ๋ฅผ ใ๋ชจ๋ฅธ๋คใ๋ก ๋ตํ์ง ์๋๋ค (2026-08-28) โโโโ
|
|
408
|
+
*
|
|
409
|
+
* ์ฐฝ์ **๋ค์ ์ ์
์ด ์์ ๋** ๋ซํ๋ค. ๊ทธ๋์ ์ค๋ ๊ฒ์ด ํ๋๋ ์๋ ํธ์์ ์ฐฝ์ด ์์ํ ๋ซํ์ง ์๊ณ ,
|
|
410
|
+
* ์ด ์๋ฆฌ๊ฐ `unknown` ์ ๋๋ค โ ๋ถ์ด ์๊ณ 37์ด๋ง๋ค ์ฑ๊ณต์ ์ผ๋ก ์ฝ๋ ํธ์์ด ํ๋ฉด์์ ใ๋ชจ๋ฅธ๋คใ์๋ค.
|
|
411
|
+
*
|
|
412
|
+
* ๊ทธ๊ฒ์ด ๋๋ฌ๋ ๊ณ๊ธฐ: ์ปค๋ฅํฐ๊ฐ ์ฌ๊ธฐ๋๋ง๋ค ์ฌ๊ณ 2,665๊ฑด์ ๋ค์ ๋งํ๋ ๊ฒ์ ์์ด๋ค. ๊ทธ๋ฌ์ ์ ์ ์ํ์
|
|
413
|
+
* ์ ์
์ด 0 ์ด ๋์๊ณ , **๊ฑด๊ฐ ์ ํธ๊ฐ ๊ทธ ์์์ ํ๊ณ ์์๋ค**๋ ๊ฒ์ด ๋ณด์๋ค.
|
|
414
|
+
*
|
|
415
|
+
* โโ ๊ฐ๋ฅด๋ ์ฌ์ค์ **๋ฐ์ ๊ฒ์ด ์๋**๋ค (์ฒซ ํ์ ๊ณ ์นจ) โโโโโโโโโโโโโโโโโโโโโ
|
|
416
|
+
* ์ฒ์์๋ ๋ฟ์ ์๊ฐ์ผ๋ก ๊ฐ๋๋ค. ๊ทธ๊ฒ์ด ํ๋ ธ๋ค โ **๋น ์ฝ๊ธฐ๋ ๋ฟ์ ๊ฒ**์ด๋ผ ๊ทธ ์๊ฐ์ ์ธ์ ๋ ์ ๋ค.
|
|
417
|
+
* ๊ทธ๋์ ์ฐฝ์ ์ฑ์ฐ๋ ์ค์ธ ํธ์(์ ์ 200๊ฑด)๊น์ง ใ์ค๋ ๊ฒ์ด ์๋คใ๋ก ๋ตํ๊ฒ ๋๊ณ , ์ํ์ด ๊ทธ๊ฒ์ ์ก์๋ค.
|
|
418
|
+
* ๋ฐ๊ณ ์๋ ์ค์ธ๋ฐ ์ค๋ ๊ฒ์ด ์๋ค๊ณ ๋งํ๋ ๊ฒ์ **์๋ ๊ฒ๊ณผ ๋ชป ๋ณธ ๊ฒ์ ๋ค์ง๋ ๊ฒ**์ด๋ค.
|
|
419
|
+
*
|
|
420
|
+
* ๋ฟ์๊ณ ยท ์ ์๊ฐ 0 ์ค๋ ๊ฒ์ด ์๋ค `no-traffic`
|
|
421
|
+
* ๋ฟ์๊ณ ยท ์ ์๊ฐ ์๋ค ๋ฐ๋ ์ค์ด๊ณ ํ์ ํ ์ฐฝ์ด ์์ง ์๋ค `unknown`
|
|
422
|
+
* ํ ๋ฒ๋ ๋ฟ์ง ์์๋ค `unknown`(์ `lastAtMs < 0` ๊ฐ๋)
|
|
423
|
+
*/
|
|
424
|
+
if (!args.recent) {
|
|
425
|
+
const touched = typeof args.lastAtMs === 'number' && args.lastAtMs >= 0;
|
|
426
|
+
const nothingOffered = (args.offeredTotal ?? 0) <= 0;
|
|
427
|
+
return touched && nothingOffered ? 'no-traffic' : 'unknown';
|
|
428
|
+
}
|
|
336
429
|
if (args.recent.offered <= 0)
|
|
337
430
|
return 'no-traffic';
|
|
338
431
|
const ratio = (args.recent.offered - args.recent.rejected) / args.recent.offered;
|
|
@@ -372,6 +465,8 @@ function ingestHealth(ledger, feedState, threshold = exports.HEALTHY_ACCEPTED_RA
|
|
|
372
465
|
recent: recentRaw,
|
|
373
466
|
lastAtMs: ledger?.lastAtMs ?? -1,
|
|
374
467
|
lastUndeliveredAtMs: ledger?.lastUndeliveredAtMs ?? -1,
|
|
468
|
+
/* ์ฐฝ์ด ๋ซํ์ง ์์์ ๋ ใ๋ฐ๋ ์คใ๊ณผ ใ์ค๋ ๊ฒ์ด ์๋คใ๋ฅผ ๊ฐ๋ฅด๋ ์ฌ์ค. */
|
|
469
|
+
offeredTotal: ledger?.offered ?? 0,
|
|
375
470
|
nowMs,
|
|
376
471
|
threshold
|
|
377
472
|
});
|
|
@@ -407,12 +502,22 @@ function ingestHealth(ledger, feedState, threshold = exports.HEALTHY_ACCEPTED_RA
|
|
|
407
502
|
since: new Date(ledger.readFailure.sinceMs).toISOString(),
|
|
408
503
|
lastAt: new Date(ledger.readFailure.lastAtMs).toISOString(),
|
|
409
504
|
reason: ledger.readFailure.reason,
|
|
410
|
-
...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {})
|
|
505
|
+
...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {}),
|
|
506
|
+
...(ledger.readFailure.nextRetryMs ? { nextRetryMs: ledger.readFailure.nextRetryMs } : {})
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
: {}),
|
|
510
|
+
...(ledger?.lastRecovery
|
|
511
|
+
? {
|
|
512
|
+
lastRecovery: {
|
|
513
|
+
at: new Date(ledger.lastRecovery.atMs).toISOString(),
|
|
514
|
+
afterFailures: ledger.lastRecovery.afterFailures,
|
|
515
|
+
downMs: ledger.lastRecovery.downMs
|
|
411
516
|
}
|
|
412
517
|
}
|
|
413
518
|
: {}),
|
|
414
519
|
/* ์ปค์ ์ ์ฒด๋ **์ด ๊ฐ๋์์** ๋ด๋ณด๋ธ๋ค โ ์ ์
์ด ์๋ ์ฅ๋ถ์์๋ ์ ์ฒด๋ ์ค์ฌํ๋ค(์ฝ์์ผ๋ ๋ชป
|
|
415
|
-
๋๊ฒผ์ผ๋ฉด ์ ์
์ด 0์ด๋ค). ์ฌ๊ธฐ์ ๋จ์ด๋จ๋ฆฌ๋ฉด ๋ฐ๋ก ๊ทธ ์ํฉ์์
|
|
520
|
+
๋๊ฒผ์ผ๋ฉด ์ ์
์ด 0์ด๋ค). ์ฌ๊ธฐ์ ๋จ์ด๋จ๋ฆฌ๋ฉด ๋ฐ๋ก ๊ทธ ์ํฉ์์ ๋ค์ด์จ ๊ฒ์ด ์์ด์ง๋ค. */
|
|
416
521
|
...(ledger?.cursorStall
|
|
417
522
|
? {
|
|
418
523
|
cursorStall: {
|
|
@@ -423,6 +528,19 @@ function ingestHealth(ledger, feedState, threshold = exports.HEALTHY_ACCEPTED_RA
|
|
|
423
528
|
...(ledger.cursorStall.stream ? { stream: ledger.cursorStall.stream } : {})
|
|
424
529
|
}
|
|
425
530
|
}
|
|
531
|
+
: {}),
|
|
532
|
+
/*
|
|
533
|
+
* **์ธ์ฐ์ง ์์ ๊ฒ๋ ๋ธ๋ค โ ์์ชฝ ๊ฐ๋์์.** ์ ์
์ด ํ ๊ฑด๋ ์๋ ์ฅ๋ถ์์๋ ์ด ์ฌ์ค์ ์ค์ฌํ๋ค
|
|
534
|
+
* (์๋ณธ์ด ๋งํ๋๋ฐ ์ ๋ถ ์ ๋ฐ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค). ์ฌ๊ธฐ์ ๋จ์ด๋จ๋ฆฌ๋ฉด ๋ฐ๋ก ๊ทธ ์ํฉ์์ ๋ค์ด์จ ๊ฒ์ด ์์ด์ง๋ค.
|
|
535
|
+
*/
|
|
536
|
+
...(ledger?.withheld?.length
|
|
537
|
+
? {
|
|
538
|
+
withheld: ledger.withheld.map(w => ({
|
|
539
|
+
reason: w.reason,
|
|
540
|
+
count: w.count,
|
|
541
|
+
lastAt: new Date(w.lastAtMs).toISOString()
|
|
542
|
+
}))
|
|
543
|
+
}
|
|
426
544
|
: {})
|
|
427
545
|
};
|
|
428
546
|
}
|
|
@@ -434,6 +552,31 @@ function ingestHealth(ledger, feedState, threshold = exports.HEALTHY_ACCEPTED_RA
|
|
|
434
552
|
recent: recentRaw ? toWindowView(recentRaw, lastAnyMs) : null,
|
|
435
553
|
trend: ledger.trend.map(w => toWindowView(w, lastAnyMs)),
|
|
436
554
|
trendDropped: ledger.trendDropped,
|
|
555
|
+
/* ์ธ์ฐ์ง ์์ ๊ฒ โ ์์ชฝ ๊ฐ๋์์ ๊ฐ์ ๋ชจ์์ผ๋ก ๋ธ๋ค(ยง`IngestLedger.withheld`). */
|
|
556
|
+
...(ledger.withheld?.length
|
|
557
|
+
? {
|
|
558
|
+
withheld: ledger.withheld.map(w => ({
|
|
559
|
+
reason: w.reason,
|
|
560
|
+
count: w.count,
|
|
561
|
+
lastAt: new Date(w.lastAtMs).toISOString()
|
|
562
|
+
}))
|
|
563
|
+
}
|
|
564
|
+
: {}),
|
|
565
|
+
/*
|
|
566
|
+
* **์ด๋ค ๊ธธ๋ก ๋ค์ด์ค๊ณ ์๋** โ ํ๋ฉด์ด ใ์ด ํธ์์ ๋ฌด์์ ํตํด ๊ฐ์ ๋ฐ๋ใ๋ฅผ ๋งํ ์ ์๊ฒ.
|
|
567
|
+
* ๋น์ด ์์ผ๋ฉด ์นธ์ ๋ง๋ค์ง ์๋๋ค: ์์ง ์๋ฌด๊ฒ๋ ์ ๋ฐ์ ํธ์๊ณผ ใ๊ธธ์ด ์๋คใ๋ฅผ ๊ตฌ๋ณํ๋ค.
|
|
568
|
+
*/
|
|
569
|
+
...(Object.keys(ledger.bySource).length
|
|
570
|
+
? {
|
|
571
|
+
sources: Object.entries(ledger.bySource)
|
|
572
|
+
.map(([source, v]) => ({ source, count: v.count, lastAt: new Date(v.lastAtMs).toISOString() }))
|
|
573
|
+
.sort((a, b) => b.count - a.count)
|
|
574
|
+
}
|
|
575
|
+
: {}),
|
|
576
|
+
/* ๊ฐ์ ์ฌ์ค์ด ๋ ๋ฒ ์์ ๋ฒ๋ฆฐ ์ โ 0 ์ด๋ฉด ์นธ์ ๋ง๋ค์ง ์๋๋ค(๋ฒ๋ฆฐ ์ ์ด ์๋ค๋ ๋ป์ด๋ค). */
|
|
577
|
+
...(ledger.duplicates
|
|
578
|
+
? { duplicates: { count: ledger.duplicates, lastAt: new Date(ledger.lastDuplicateAtMs).toISOString() } }
|
|
579
|
+
: {}),
|
|
437
580
|
total: {
|
|
438
581
|
offered: ledger.offered,
|
|
439
582
|
accepted,
|
|
@@ -460,7 +603,18 @@ function ingestHealth(ledger, feedState, threshold = exports.HEALTHY_ACCEPTED_RA
|
|
|
460
603
|
since: new Date(ledger.readFailure.sinceMs).toISOString(),
|
|
461
604
|
lastAt: new Date(ledger.readFailure.lastAtMs).toISOString(),
|
|
462
605
|
reason: ledger.readFailure.reason,
|
|
463
|
-
...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {})
|
|
606
|
+
...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {}),
|
|
607
|
+
...(ledger.readFailure.nextRetryMs ? { nextRetryMs: ledger.readFailure.nextRetryMs } : {})
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
: {}),
|
|
611
|
+
/* ๋๊ฒผ๋ค๊ฐ ๋์์จ ๊ฒ โ ์ง๊ธ ๋ฟ๊ณ ์์ด๋ ๋จ๊ธด๋ค(๊ทธ๊ฒ์ด ์์ผ๋ฉด ๋ฐค์์ ๋จ์ ์ด ์ฌ๋ผ์ง๋ค). */
|
|
612
|
+
...(ledger.lastRecovery
|
|
613
|
+
? {
|
|
614
|
+
lastRecovery: {
|
|
615
|
+
at: new Date(ledger.lastRecovery.atMs).toISOString(),
|
|
616
|
+
afterFailures: ledger.lastRecovery.afterFailures,
|
|
617
|
+
downMs: ledger.lastRecovery.downMs
|
|
464
618
|
}
|
|
465
619
|
}
|
|
466
620
|
: {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingest-health.js","sourceRoot":"","sources":["../../server/engine/ingest-health.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * ๋๊ธฐํ ๊ฑด๊ฐ โ **์ด ํธ์์ด ํ์ฅ๊ณผ ๋ง์ถฐ์ง๊ณ ์๋.** ์์(import ์์).\n *\n * โโ ํ ์ง๋ฌธ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ํ๋ฉด์์ ๊ฐ์ด ๋ณํ์ง ์์ ๋ ์์ธ์ด ๋ท์ธ๋ฐ, ์ง๊ธ๊น์ง **๋ท์ด ๋๊ฐ์ด ๋ณด์๋ค.**\n * โ ํผ๋๊ฐ ๋ถ์ง ์์๋ค โก ๋ถ์๋๋ฐ ์๋ฌด๊ฒ๋ ์ค์ง ์๋๋ค\n * โข ์ค๋๋ฐ ์ ๋ถ ๊ฑฐ๋ถ๋๋ค โฃ ์ ์์ธ๋ฐ ํ์ฅ์ด ์กฐ์ฉํ๋ค\n * โข์ ํนํ ๋์๋ค โ ์ปค๋ฅํฐ์ ๋งคํ์ด ํ ๊ธ์ ํ๋ฆฌ๋ฉด ํธ์์ ใ๋น ๊ณต์ฅใ์ด ๋๊ณ , ๊ทธ ์ฌ์ค์ด ์๋ฒ ๋ก๊ทธ\n * ํ ์ค์๋ง ๋จ์๋ค. ํ์ฅ์ ๋๊ฐ ์ฌ๋์ ๋ก๊ทธ๋ฅผ ๋ค์ ธ์ผ ํ๋ค.\n *\n * โโ ์ ์ ๋๋ก๋ ๋ตํ ์ ์๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * **๊ฑฐ๋ถ๋ ๊ฒ์ ์ ๋์ ์๋ค** โ ๊ฑฐ๋ถ์ ๋ป์ด ๊ทธ๊ฒ์ด๋ค. ์ ๋์ ์ ์ผ๋ฉด ํต๊ณผํ ์ชฝ๋ง ๋์จ๋ค. ๊ฑฐ๋ถ์ ์ถ์ด๋\n * ์ธ๋ ์๋ฆฌ๋ฅผ ๋ฐ๋ก ๋์ด์ผ ๋์จ๋ค. ์ด ์ฅ๋ถ๊ฐ ๊ทธ ์๋ฆฌ๋ค.\n *\n * โโ ์ ๊ฑด๋ง๋ค ์ ์ฅํ์ง ์๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ๋ผ์ด๋ธ ๊ณ์ธก์ ์ด๋น ์ฌ๋ฌ ๊ฑด์ด๋ค. ๊ฑฐ๋ถ๋ง๋ค ํ์ ์ฐ๋ฉด ๊ทธ ์์ฒด๊ฐ ๋ถํ๊ฐ ๋๋ค(`reference-live.ts` ๊ฐ\n * ์ด๋ฏธ ๊ทธ๋ ๊ฒ ์ ์ด ๋์๋ค). ๊ทธ๋ฆฌ๊ณ ์ด ํจํค์ง๋ **`integration-base` ๋ฅผ ์์ง ์๋๋ค**(์ด์์ฑ ๊ท์ฝ) โ\n * ์๋๋ฆฌ์ค ๊ฒฝ๋ก๊ฐ ์ฐ๋ dead-letter ๋ฅผ ์ฌ๊ธฐ์ ๋ถ๋ฅผ ์ ์๋ค. ๊ทธ๋์ **์ง๊ณํ๋ค.**\n *\n * โโ ํต๊ณผ์ ๊ฑฐ๋ถ๋ฅผ ํจ๊ป ์ผ๋ค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ๊ฑฐ๋ถ๋ง ๊ทธ๋ฆฌ๋ฉด ใ์ ์
์์ใ๊ณผ ใ์ ์ใ์ด **๋ ๋ค ๊ฑฐ๋ถ 0** ์ผ๋ก ๊ฐ์ ๋ณด์ธ๋ค. ์ ์ ์๊ฐ ์์ด์ผ ๊ฐ๋ฆฐ๋ค.\n *\n * โโ ์งํค๋ ๊ท์จ ๋ท โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * โ **๋ซํ ์ฐฝ๋ง ใ์ต๊ทผใ์ด๋ค** โ ์ฑ์ฐ๋ ์ค์ธ ์ฐฝ์ ๊ณผ์ ์ง๊ณ๋ค(๋ถํ ๊ณ๊ธฐํ์์ ๊ฒช์๋ค).\n * โก **0 ๊ณผ ใ์์ใ์ ๊ฐ๋ฅธ๋ค** โ ์ ๋ฐ์ ๊ฒ์ `null`, ๋ฐ์์ง๋ง ๊ฑฐ๋ถ 0 ์ `0`.\n * โข **์กฐ์ฉํ ์๋ฅด์ง ์๋๋ค** โ ํ๋ณธยท์ถ์ด ์ํ์์ ๋ฐ๋ ค๋ ์๋ฅผ ํจ๊ป ๋ธ๋ค.\n * โฃ **ํต๊ณผ์จ์ 1 ์ ํจ๋ถ๋ก ์ฐ์ง ์๋๋ค** โ 1,000๊ฑด ์ค 1๊ฑด ๊ฑฐ๋ถ๋ 0.999 ๋ค.\n */\n\n/** ์ถ์ด ์ฐฝ ํ๋ โ ์ ์ยทํต๊ณผยท๊ฑฐ๋ถยท๋ฏธ์ ๋ฌ, ๊ทธ๋ฆฌ๊ณ **์ ํ ๊ฒ**์ ํจ๊ป ๋ ๋ค. */\nexport interface IngestWindow {\n /** ์ฐฝ์ด ์ด๋ฆฐ ์๊ฐ(ms). */\n startMs: number\n /** ์ฐฝ์ด ๋ซํ ์๊ฐ(ms). ์์ง ์ฑ์ฐ๋ ์ค์ด๋ฉด `-1`. */\n endMs: number\n /** ์ด ์ฐฝ์ ์ ์๋ ๋ ์ฝ๋ ์(๊ฑฐ๋ถ ์ฌ๋ถ ๋ฌด๊ด). */\n offered: number\n /** ๊ทธ์ค **๋งคํ์ด ๊ฑฐ๋ถํ** ์ โ ์ฒ๋ฐฉ์ ๋งคํ์ ๊ณ ์น๋ ๊ฒ์ด๋ค. */\n rejected: number\n /**\n * ๋งคํ์ ํต๊ณผํ์ง๋ง **ํธ์์ ๋ฟ์ง ๋ชปํ** ์ โ ์ฒ๋ฐฉ์ ํธ์์ ์ธ์ฐ๋ ๊ฒ์ด๋ค.\n *\n * โโ ์ ๊ฑฐ๋ถ์ ๋ฐ๋ก ์ธ๋ (2026-08-20์ ๊ฒช์๋ค) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ํธ์์ด ๋ผ์ด๋ธ๋ก ๋์ง ์์ผ๋ฉด ์ปค๋์ด ๋ ์ฝ๋๋ฅผ **์กฐ์ฉํ ๋ฒ๋ฆฐ๋ค**. ๊ทธ๋ฐ๋ฐ ์ฅ๋ถ๋ ๊ทธ๊ฒ์ ใํต๊ณผใ๋ก ์
๋ค.\n * ํ๋ฉด์ด ใ150 ๋ค์ด์ด ยท 150 ํต๊ณผ ยท 100%ใ๋ผ๊ณ ๋งํ๋ ๋์ 150๊ฑด์ ๋ฐ๋ฅ์ ๋ฒ๋ ค์ง๊ณ ์์๋ค. ์ด ๊ธฐ๋ฅ์ด\n * ๋ง์ผ๋ ค๋ ๋ฐ๋ก ๊ทธ๊ฒ์ ์ด ๊ธฐ๋ฅ์ด ์ ์ง๋ฅธ ์
์ด๋ค.\n *\n * ๊ฑฐ๋ถ์ ํฉ์น๋ ๊ฒ๋ ๋ต์ด ์๋๋ค โ ๊ฑฐ๋ถ๋ ใ๋งคํ์ ๊ณ ์ณ๋ผใ๋ ๋ง์ด๊ณ , ์ฌ๊ธฐ์ ํ์ํ ๋ง์ ใํธ์์ด ์\n * ๋๊ณ ์๋คใ๋ค. **์ฒ๋ฐฉ์ด ๋ค๋ฅด๋ฉด ๋ค๋ฅธ ์๋ก ์ผ๋ค.**\n */\n undelivered: number\n /**\n * ์ด ์ฐฝ์ **์ ๋์ ์ ํ ํ** ์ โ ใ๋ฌด์์ด ๋จ์๋ใ.\n *\n * ์ ์
๊ณผ ๋ค๋ฅธ ์ถ์ด๋ค: ์๋ฎฌ ํธ์์ ๋ฐ๋ ๊ฒ ์์ด ์๊ธฐ๊ฐ ๋ธ ์ฌ์ค์ ์ ๋๋ค(๊ทธ๋์ `offered` ๋ 0 ์ด๊ณ \n * `rows` ๋ 0 ์ด ์๋๋ค). ์ด ์นธ์ด ์์ผ๋ฉด ๊ทธ ํธ์์ ํ๋์ ์ด๋ ์ถ์ด์๋ ๋ํ๋์ง ์๋๋ค.\n */\n rows: number\n /**\n * ๊ทธ๊ฒ์ ์ ๊ธฐ ์ํด **DB ๋ฅผ ๋๋๋ฆฐ ํ์**(flush) โ ใ์ฐ๋ฆฌ๊ฐ ๋ช ๋ฒ ๊ฐ๋ใ.\n *\n * ํ ์์ ๋ฐ๋ก ์ธ๋ ์ด์ : 2026-08-20 ์ ๊ณ ์น ๊ฒ์ด ๋ฐ๋ก ์ด ๊ฐ์ด๋ค(ํ๋ง๋ค ํ ๋ฒ โ ์ฐฝ๋น ํ ๋ฒ). ํ๋ง\n * ์ธ๋ฉด ๊ทธ ๊ฐ์ ๋, ๋๋์๊ฐ๋ ๊ฒ๋ ๋ณด์ด์ง ์๋๋ค.\n */\n flushes: number\n}\n\n/** ๊ฑฐ๋ถ ํ๋ณธ ํ๋ โ ๋งคํ์ ๊ณ ์น๋ ค๋ฉด ์ค์ ๋ชจ์์ ๋ด์ผ ํ๋ค. */\nexport interface RejectSample {\n atMs: number\n /** ์ปค๋์ด ๋ธ ์ฌ์ . ์ฐ๋ฆฌ๊ฐ ๋ค์ ์ฐ์ง ์๊ณ ๊ทธ๋๋ก ์ฎ๊ธด๋ค. */\n errors: string[]\n /** ๋งํ ๋ ์ฝ๋์ ์ง๋ ฌํ. ๊ธธ๋ฉด ์๋ฅด๊ณ , ์๋๋ค๊ณ ํ์ํ๋ค. */\n record: string\n recordTruncated?: boolean\n}\n\nexport interface IngestLedger {\n /** ์ง๊ธ ์ฑ์ฐ๋ ์ค์ธ ์ฐฝ. `startMs < 0` ์ด๋ฉด ์์ง ์๋ฌด๊ฒ๋ ๋ฐ์ง ์์๋ค. */\n window: IngestWindow\n /** ๋ซํ ์ฐฝ๋ค โ ์ค๋๋ ๊ฒ์ด ์. ์ํ์ ๋์ผ๋ฉด ์์์ ๋ฐ๋ ค๋๋ค. */\n trend: IngestWindow[]\n /** ์ถ์ด์์ ๋ฐ๋ ค๋ ์ฐฝ ์. */\n trendDropped: number\n /** ๋์ ์ ์ยท๊ฑฐ๋ถยท๋ฏธ์ ๋ฌ. */\n offered: number\n rejected: number\n undelivered: number\n /** ๋์ โ ์ ํ ํ๊ณผ ๋๋๋ฆฐ ํ์. */\n rows: number\n flushes: number\n /**\n * ๋ง์ง๋ง์ผ๋ก **์ ์** ์๊ฐ. ํ ๋ฒ๋ ์์ผ๋ฉด `-1`.\n *\n * ์ ์
์๊ฐ(`lastAtMs`)๊ณผ ๊ฐ๋ผ ๋๋ ์ด์ ๋ ์ `recordJournalWrite` ์ฃผ์์ ์๋ค โ ์์ผ๋ฉด ๋๊ธด ํผ๋๊ฐ\n * ์ด๋ก์ผ๋ก ๋ณด์ธ๋ค.\n */\n lastWriteAtMs: number\n /**\n * ๋ง์ง๋ง์ผ๋ก **๋ฒ๋ ค์ง** ์๊ฐ(ms). ํ ๋ฒ๋ ์์ผ๋ฉด `-1`.\n *\n * ์ฐฝ๊ณผ ๋ฐ๋ก ๋๋ค: ๋ฏธ์ ๋ฌ์ ์ฐฝ์ด ๋ซํ๊ธฐ ์ ์ ์์์ผ ํ๋ค(๊ทธ ์ฌ์ด์๋ ์ฌ์ค์ ๊ณ์ ์ฌ๋ผ์ง๊ณ ์๋ค).\n */\n lastUndeliveredAtMs: number\n /** ์ฌ์ ๋ณ ๋์ ๊ฑด์์ **๋ง์ง๋ง์ผ๋ก ๊ทธ ์ฌ์ ๊ฐ ๋ ์๊ฐ** โ ๊ณ ์น ์ฌ์ ๋ ์๊ฐ์ด ๋ฉ์ถ๋ค. */\n byReason: Record<string, { count: number; lastAtMs: number }>\n /**\n * ์ฌ์ ์ข
๋ฅ๊ฐ ์ํ์ ๋ฟ์๋.\n *\n * **์ ํ ์ข
๋ฅ ์๋ ์ธ์ง ์๋๋ค** โ ๊ทธ๊ฒ์ ์ธ๋ ค๋ฉด ์ด๋ฏธ ๋ณธ ์ฌ์ ๋ฅผ ๋ชจ๋ ๊ธฐ์ตํด์ผ ํ๊ณ , ๊ทธ ์งํฉ์ด\n * ๋ฐ๋ก ์ด ์ํ์ผ๋ก ๋ง์ผ๋ ค๋ ๋ฌดํํ ์งํฉ์ด๋ค. ์ ํ **๊ฑด์**๋ `byReason[OTHER_REASON].count` ๊ฐ ๋ตํ๋ค.\n */\n reasonsCapped: boolean\n /** ํ๋ณธ์ ์ด๋ฏธ ๋ฌ ์ฌ์ ๋ค โ ๊ฐ์ ์ฌ์ ๋ฅผ ๋ค์ ์ง๋ ฌํํ์ง ์๊ธฐ ์ํ ์์ธ(O(1) ์กฐํ). */\n sampledReasons: Set<string>\n /** ์ต๊ทผ ๊ฑฐ๋ถ ํ๋ณธ. */\n samples: RejectSample[]\n /** ํ๋ณธ์์ ๋ฐ๋ ค๋ ๊ฑฐ๋ถ ๊ฑด์. */\n sampleDropped: number\n /** ๋ง์ง๋ง์ผ๋ก ๋ฌด์์ด๋ ๋ฐ์ ์๊ฐ(ms). **ํ ๋ฒ๋ ์์ผ๋ฉด `-1`** โ 0 ์ผ๋ก ๋๋ฉด ์๊ฐ 0 ๊ณผ ๊ตฌ๋ณ๋์ง ์๋๋ค. */\n lastAtMs: number\n /**\n * **์๋ณธ์ ๋ฟ์ง ๋ชปํ ์ฌ์ค** (2026-08-23) โ ใ๋ฐ์ ๊ฒ์ด ์๋คใ์ **๋ค๋ฅธ ์ฌ์ค**์ด๋ค.\n *\n * โโ ๋ฌด์์ด ์กฐ์ฉํ๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์ค ์๋ณธ์ด ๋๊ฒผ์ ๋(์ ์ ์๊ฐ ์ด๊ณผ) ํธ์์ **์กฐํ ๊ฐ๋ฅํ ์ํ ์ด๋์๋** ๊ทธ ์ฌ์ค์ด ์์๋ค.\n * `recordIngest` ๋ `onRecords` ๊ฐ ๋ถ๋ฆด ๋๋ง ๋๋ฌํ๊ณ , ์ฝ๊ธฐ๊ฐ ์คํจํ๋ฉด ๊ทธ ๋ฌธ์ ์ค์ง ์๋๋ค.\n * `TwinReference.lastError` ๋ ๋ง์คํฐ ๋๊ธฐยท์ ์ ์ํ์๋ง ์ ํ๋ค.\n *\n * ๊ทธ๋์ ํ๋ฉด์ด ๋ณผ ์ ์๋ ๊ฒ์ ใ์ ์ฌ์ค์ด ์๋คใ๋ฟ์ด์๊ณ , ๊ทธ๊ฒ์ **ใ์๋ณธ์ด ์กฐ์ฉํ๋คใ์ ๊ตฌ๋ณ๋์ง\n * ์๋๋ค.** ์ค์ฆ ๋ฐ๋ชจ ์ค์ ์๋ณธ์ด ๋๊ธฐ๋ฉด ์ฌ์ฉ์๊ฐ ์์ธ์ ์ฐพ์ ์ ์๋ค.\n *\n * โโ ์ ใ๋ช ๋ฒใ๊ณผ ใ์ธ์ ๋ถํฐใ๋ฅผ ํจ๊ป ๋๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ํ ๋ฒ ์คํจํ ๊ฒ๊ณผ 20๋ถ์งธ ๋ชป ์ฝ๋ ๊ฒ์ ๋ค๋ฅธ ์ฌ์ค์ด๋ค. ๊ทธ ๊ตฌ๋ณ์ด ์์ผ๋ฉด ํ๋ฉด์ด ์๊ฐ์ ์คํจ์ ๋๋ผ๊ฑฐ๋\n * ๊ณ์๋ ๋จ์ ์ ๋์๋กญ์ง ์๊ฒ ๋งํ๋ค. ๊ทธ๋์ **์ฐ์ ์คํจ ์**์ **์ฒ์ ์คํจํ ์๊ฐ**์ ํจ๊ป ๋ ๋ค.\n *\n * ์ฑ๊ณตํ๋ฉด ์ง์ด๋ค โ ๊ณ ์ณ์ง ๋จ์ ์ด ํ๋ฉด์ ๋จ์ ์์ผ๋ฉด ๊ทธ๊ฒ๋ ๊ฑฐ์ง์ด๋ค.\n */\n readFailure?: {\n /** ์ฐ์ ์คํจ ์ โ ์ฑ๊ณต ํ ๋ฒ์ 0 ์ผ๋ก ๋์๊ฐ๋ค. */\n consecutive: number\n /** ์ด ๋จ์ ์ด **์ฒ์** ์์๋ ์๊ฐ(ms). ์ฐ์์ด ๋๊ธฐ๋ฉด ๋ค์ ์ ํด์ง๋ค. */\n sinceMs: number\n /** ๋ง์ง๋ง ์คํจ ์๊ฐ(ms). */\n lastAtMs: number\n /** ๋ง์ง๋ง ์คํจ์ ์ฌ์ โ ์ฌ๋์ด ์ฝ๋ ํ ์ค(์๋ณธ์ด ์ค ๋ง ๊ทธ๋๋ก). */\n reason: string\n /** ์ด๋ ํ๋ฆ์์ ๋ฌ๋(์ด๋ํฐ๊ฐ ๋งํด ์ฃผ๋ฉด). ์๋ณธ๋ง๋ค ํ๋ฆ์ด ๋ค๋ฅด๋ฏ๋ก ์ด๋ ค ์๋ค. */\n stream?: string\n }\n /**\n * **์ฝ์๋๋ฐ ์ฐฝ์ ๋๊ธธ ์ ์๋ค** (2026-08-24) โ ์์ **๋ค๋ฅธ ์ฌ์ค**์ด๋ค.\n *\n * โโ ์ ๊ฐ๋๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์ด ์นธ์ ๋ง๋ค๊ธฐ ์ ์๋ ๋ ์ฌ์ค์ด ๊ฐ์ ์ด๋ฆ์ผ๋ก ๋๊ฐ๋ค.\n *\n * readFailure ์๋ณธ์ ๋ฟ์ง ๋ชปํ๋ค โ **๊ธฐ๋ค๋ฆฌ๋ฉด ํ๋ฆฐ๋ค**\n * cursorStall ์ฝ์๋๋ฐ ์ปค์๊ฐ ๋ชป ๋์ด๊ฐ๋ค โ **๊ธฐ๋ค๋ ค๋ ์ ํ๋ฆฐ๋ค**\n *\n * ๋์งธ๋ ์ฝ๊ธฐ๊ฐ ์ฑ๊ณตํ ์คํจ๋ค: ํ ์๊ฐ์ ํ ํ์ด์ง๋ณด๋ค ๋ง์ ํ์ด ๋ชฐ๋ ค ์ปค์๋ฅผ ๊ทธ ์๊ฐ ๋ฐ์ผ๋ก ์ฎ๊ธธ ์\n * ์๋ค. ํ๋ฉด์ด ใ์๋ณธ์ ๋ฟ์ง ๋ชปํ๋คใ๊ณ ๋งํ๋ฉด ์ฌ๋์ ์๋ณธ์ ์์ฌํ๊ณ ๊ธฐ๋ค๋ฆฌ๋๋ฐ, ํ์ํ ์กฐ์น๋\n * ํ์ด์ง๋ฅผ ํค์ฐ๊ฑฐ๋ ๊ฐ์ ์๊ฐ ์์์ ์์๋ฅผ ์ ํ๋ ๊ฒ์ด๋ค. **์กฐ์น๊ฐ ๋ฐ๋์ธ ๋ ์ฌ์ค์ ํ ์ด๋ฆ์ผ๋ก\n * ๋ถ๋ฅด๋ฉด ๊ทธ ์ด๋ฆ์ ์ ๋ณด๊ฐ ์๋๋ผ ์คํด๋ค.**\n *\n * ๋ชจ์์ ์์ ๊ฐ๊ฒ ๋๋ค โ ใ๋ช ๋ฒใ๊ณผ ใ์ธ์ ๋ถํฐใ๊ฐ ์ฌ๊ธฐ์๋ ๊ฐ์ ๊ฐ์ ํ๋ค(ํ ๋ฒ์ ๋ฐ๋ฆผ๊ณผ ์ฌํ์งธ\n * ๋ชป ๋์ด๊ฐ๋ ๊ฒ์ ๋ค๋ฅด๋ค). ๋์ด๊ฐ๋ฉด ์ง์ด๋ค.\n */\n cursorStall?: {\n /** ์ฐ์ ์ ์ฒด ์ โ ๋์ด๊ฐ๋ฉด 0 ์ผ๋ก ๋์๊ฐ๋ค. */\n consecutive: number\n /** ์ด ์ ์ฒด๊ฐ **์ฒ์** ์์๋ ์๊ฐ(ms). */\n sinceMs: number\n /** ๋ง์ง๋ง ์ ์ฒด ์๊ฐ(ms). */\n lastAtMs: number\n /** ์ฌ์ โ ์ฌ๋์ด ์ฝ๋ ํ ์ค(์ด๋ ์๊ฐ์์ ๋งํ๋๊น์ง ์ด๋ํฐ๊ฐ ๋งํด ์ฃผ๋ฉด ์ข๋ค). */\n reason: string\n /** ์ด๋ ํ๋ฆ์ธ๊ฐ. ๋ฐ๋๊ฐ ๋์ ํ๋ ์๋ณธ๋ง๋ค ๋ค๋ฅด๋ฏ๋ก ์ด ์ด๋ฆ์ด ์กฐ์น์ ์ ๋ฐ์ด๋ค. */\n stream?: string\n }\n}\n\n/**\n * ์ฝ๊ธฐ ์คํจ๋ฅผ ์ฅ๋ถ์ ์ ๋๋ค โ **๋ฐ์ ๊ฒ์ด ์๋ ๊ฒ๊ณผ ๊ฐ๋ฅธ๋ค.**\n *\n * ์ฐ์ ์คํจ์ ์์ ์๊ฐ์ ์งํค๋ ๊ฒ์ด ์ด ํจ์์ ์์ ์ด๋ค: ๋งค๋ฒ ์๋ก ์ ์ผ๋ฉด ใ20๋ถ์งธ ๋ชป ์ฝ๋๋คใ๋ฅผ\n * ๋งํ ์ ์๊ณ , ํ๋ฉด์ ๋ ใ๋ฐฉ๊ธ ์คํจํ๋คใ๋ง ๋ณด๊ฒ ๋๋ค.\n */\nexport function recordReadFailure(\n ledger: IngestLedger,\n reason: string,\n nowMs: number,\n stream?: string\n): void {\n const prev = ledger.readFailure\n ledger.readFailure = {\n consecutive: (prev?.consecutive ?? 0) + 1,\n sinceMs: prev?.sinceMs ?? nowMs,\n lastAtMs: nowMs,\n reason,\n ...(stream ? { stream } : {})\n }\n}\n\n/**\n * ์ฝ๊ธฐ๊ฐ ์ฑ๊ณตํ๋ค โ ๋จ์ ๊ธฐ๋ก์ ์ง์ด๋ค.\n *\n * **๋น ์ฝ๊ธฐ๋ ์ฑ๊ณต์ด๋ค**: ์๋ณธ์ด ใ์ ๊ฒ์ด ์๋คใ๊ณ ๋ตํ ๊ฒ์ ๋ฟ์๋ค๋ ๋ป์ด๋ค. ๊ทธ ๋์ ๊ฐ๊ฒ ๋๋ฉด\n * ์กฐ์ฉํ ์๋ณธ์ด ๋๊ธด ์๋ณธ์ผ๋ก ๋ณด์ธ๋ค(๊ณ ์น๋ ค๋ ๊ฒ์ ๋ฐ๋ ๋ฐฉํฅ์ผ๋ก ํ๋ฆฐ๋ค).\n */\nexport function clearReadFailure(ledger: IngestLedger): void {\n if (ledger.readFailure) delete ledger.readFailure\n}\n\n/**\n * ์ปค์ ์ ์ฒด๋ฅผ ์ฅ๋ถ์ ์ ๋๋ค โ **๋ฟ์ง ๋ชปํ ๊ฒ๊ณผ ๊ฐ๋ฅธ๋ค.**\n *\n * `recordReadFailure` ์ ๊ฐ์ ๋ชจ์์ด์ง๋ง **๋ค๋ฅธ ์นธ**์ด๋ค. ํ ์ฃผ๊ธฐ๊ฐ ๋ ์ด์ ๋ก ์คํจํ ์๋ ์์ผ๋ฏ๋ก\n * (๋จผ์ ๋ฟ์์ผ ์ฝ๋๋ค) ๋์ด ๋์์ ์์ง ์๋๋ค โ ๊ทธ๋์ ํ๋ฉด์ ๋ ์ค ํ๋๋ง ๋ณด๊ฒ ๋๊ณ , ๊ทธ ํ๋๊ฐ\n * ์กฐ์น๋ฅผ ์ ํ๋ค.\n */\nexport function recordCursorStall(ledger: IngestLedger, reason: string, nowMs: number, stream?: string): void {\n const prev = ledger.cursorStall\n ledger.cursorStall = {\n consecutive: (prev?.consecutive ?? 0) + 1,\n sinceMs: prev?.sinceMs ?? nowMs,\n lastAtMs: nowMs,\n reason,\n ...(stream ? { stream } : {})\n }\n}\n\n/** ์ฐฝ์ ๋๊ฒผ์ผ๋ฉด ์ง์ด๋ค โ ํ๋ฆฐ ์ ์ฒด๊ฐ ํ๋ฉด์ ๋จ์ ์์ผ๋ฉด ๊ทธ๊ฒ๋ ๊ฑฐ์ง์ด๋ค. */\nexport function clearCursorStall(ledger: IngestLedger): void {\n if (ledger.cursorStall) delete ledger.cursorStall\n}\n\n/** ์ฐฝ ๊ธธ์ด โ 10๋ถ. ๋ถํ ๊ณ๊ธฐํ(10์ด)๊ณผ ๋ค๋ฅธ ๊ฐ์ด๋ผ ์ด๋ฆ์ ๋ฐ๋ก ๋๋ค(๊ฐ์ ์ด๋ฆ์ด๋ฉด ์์ธ๋ค). */\nexport const INGEST_WINDOW_MS = 600_000\n\n/**\n * ์ด๋งํผ ์๋ฌด๊ฒ๋ ์ค์ง ์์ผ๋ฉด ใ์ ์
์์ใ์ด๋ผ ๋งํ๋ค.\n *\n * ์ฐฝ ํ๋์ ๊ฐ๊ฒ ๋๋ค โ ํ ์ฐฝ์ ํต์งธ๋ก ๋น์ด ๊ฒ์ ์ค์ ๋ก ใ๊ทธ ๊ตฌ๊ฐ์ ์๋ฌด๊ฒ๋ ์ค์ง ์์๋คใ์ด๊ณ , ์ถ์ด์\n * ๊ทธ ์๋ฆฌ๋ ๋น๊ฒ ๋๋ค. ๊ทธ๋ฆผ๊ณผ ์์ฝ์ด ๊ฐ์ ๋ง์ ํ๊ฒ ํ๋ ค๋ฉด ๊ฐ์ ๊ธธ์ด์ฌ์ผ ํ๋ค.\n */\nexport const STALE_AFTER_MS = INGEST_WINDOW_MS\n\n/** ์ถ์ด ๋ณด๊ด ์ฐฝ ์ โ 36์ฐฝ ร 10๋ถ = 6์๊ฐ. ใ๊ณ ์น ๊ฒ์ด ๋จนํ๋ใ๋ฅผ ๋ณด๊ธฐ์ ์ถฉ๋ถํ๊ณ ๋ฉ๋ชจ๋ฆฌ๋ ์ซ์ ๋ทร36 ์ด๋ค. */\nexport const TREND_LIMIT = 36\n\n/**\n * ์ฌ์ ์ข
๋ฅ ์ํ.\n *\n * **์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋์์ด ์๋๋ค.** ์ฌ์ ๋ฌธ๊ตฌ์ ๋ ์ฝ๋๋ง๋ค ๋ค๋ฅธ ๊ฐ์ด ์์ด๋ ์ปค๋ฅํฐ๊ฐ ํ๋๋ง ์์ด๋\n * (`unknown bizStep \"PUTAWAY_X17\"`, `โฆX18`, โฆ) ํค๊ฐ ๋ฌดํํ ๋์ด๋๋ค. ์ด๋น 1๋ง ๊ฑด ๊ท๋ชจ์์ ์ด๊ฒ์\n * ๋ฏธ๋ฏธํ ์ค๋ฒํค๋๊ฐ ์๋๋ผ ๋์๋ค.\n *\n * ๋์น๋ฉด `OTHER_REASON` ํ ์นธ์ ๋ชจ์ผ๊ณ **๋ช ์ข
์ ์ ์๋์ง ํจ๊ป ๋ธ๋ค**(์กฐ์ฉํ ์๋ฅด์ง ์๋๋ค).\n * 30์ข
์ด๋ฉด ๊ณ ์น ๊ณณ์ ์ฐพ๊ธฐ์ ์ถฉ๋ถํ๋ค โ ๋ชฉ๋ก์ ํ๋ ์ผ์ด ์๋๋ผ ๋งคํ ๋ช ์ค์ ๊ณ ์น๋ ์ผ์ด๋ค.\n */\nexport const REASON_LIMIT = 30\n\n/** ์ํ์ ๋๊ธด ์ฌ์ ๋ค์ด ๋ชจ์ด๋ ์นธ. */\nexport const OTHER_REASON = '(other reasons)'\n\n/**\n * ํ๋ณธ ์ํ โ **์ฌ์ ๋ง๋ค ํ ๊ฑด**๋ง ๋ ๋ค.\n *\n * ๊ฐ์ ์ฌ์ 20๊ฑด๋ณด๋ค **์๋ก ๋ค๋ฅธ ์ฌ์ 1๊ฑด์ฉ**์ด ๋งคํ์ ๊ณ ์น๋ ๋ฐ ์ ์ฉํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ๊ท์น์ด ์ฑ๋ฅ์\n * ์งํจ๋ค: ๊ทธ ์ฌ์ ์ ํ๋ณธ์ด ์ด๋ฏธ ์์ผ๋ฉด `JSON.stringify` ๋ฅผ **์์ ํ์ง ์๋๋ค.** ์ค์ธก(๋ ์ฝ๋ 241๋ฐ์ดํธ)\n * ์ผ๋ก ๊ฑด๋น 0.24ยตs ์ธ๋ฐ, ์ด๋น 1๋ง ๊ฑด์ด ์ ๋ถ ๊ฑฐ๋ถ๋๋ฉด 9,980๊ฑด์ ๋ง๋ค์๋ง์ ๋ฒ๋ ค์ง๋ ๋ฌธ์์ด์ด์๋ค โ\n * CPU ๋ ๊ฐ๋น๋์ง๋ง GC ์๋ฐ์ด ์ด๋ฒคํธ ๋ฃจํ๋ก ๋์์จ๋ค.\n */\nexport const SAMPLE_LIMIT = REASON_LIMIT\n\n/** ํ๋ณธ ํ๋์ ์ง๋ ฌํ ์ํ(๋ฌธ์). */\nexport const RECORD_MAX = 2000\n\n/**\n * ๋งคํ์ด ๋ง๊ณ ์๋ค๊ณ ๋ณผ ํต๊ณผ์จ ๋ฌธํฑ.\n *\n * ๊ฐ๊ณผ ํจ๊ป ๋ด๋ณด๋ธ๋ค โ ํ๋ฉด์ด ใ95% ๋ฏธ๋ง์ด๋ผ ๋งคํ ๋ฌธ์ ๋ก ๋ดค๋คใ๋ฅผ ๋งํ ์ ์๊ฒ. ์จ๊ธด ๋ฌธํฑ์ ์ฌ๋์ด\n * ํ์ ์ ๋ฏฟ์ง ๋ชปํ๋ค.\n */\nexport const HEALTHY_ACCEPTED_RATIO = 0.95\n\nexport function newIngestLedger(): IngestLedger {\n return {\n window: { startMs: -1, endMs: -1, offered: 0, rejected: 0, undelivered: 0, rows: 0, flushes: 0 },\n trend: [],\n trendDropped: 0,\n offered: 0,\n rejected: 0,\n undelivered: 0,\n rows: 0,\n flushes: 0,\n lastWriteAtMs: -1,\n lastUndeliveredAtMs: -1,\n byReason: {},\n reasonsCapped: false,\n sampledReasons: new Set<string>(),\n samples: [],\n sampleDropped: 0,\n lastAtMs: -1\n }\n}\n\n/**\n * ์ฐฝ์ด ๋ค ์ฐผ์ผ๋ฉด ๋ซ์ ์ถ์ด์ ๋ฃ๊ณ ์๋ก ์ฐ๋ค. **๋ซํ ์ฐฝ๋ง ใ์ต๊ทผใ์ผ๋ก ์ฝ๋๋ค.**\n *\n * โโ ์์์ด ๋ถ๋ ์ ์ผํ ์๋ฆฌ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ๋ซํ ์ฐฝ ํ๋๊ฐ ์์์ ๋จ์๋ค(์ซ์ ๋ท + ๊ตฌ๊ฐ). `onClosed` ๋ฅผ ๋ฐ๋ ์ด์ ๋ **์ด ํจ์๊ฐ ์ฐฝ์ด ๋ซํ๋\n * ์ ์ผํ ์ง์ **์ด๊ธฐ ๋๋ฌธ์ด๋ค โ ์ฌ๊ธฐ ํ ๊ณณ์ ๋ถ์ด๋ฉด ๊ธฐ๋ก ๊ฒฝ๋ก๊ฐ ๊ฐ๋ฆฌ์ง ์๋๋ค.\n *\n * ์ ๊ฑด๋ง๋ค๊ฐ ์๋๋ผ ์ฐฝ๋ง๋ค์ธ๊ฐ: ๊ฑฐ๋ถ๋ง๋ค ํ์ ์ฐ๋ฉด ์ด๋น 1๋ง ํ์ด๊ณ ๊ทธ ๋ถํ๊ฐ ์ด๋ฒคํธ ๋ฃจํ๋ก ๋์์จ๋ค.\n * ์ฐฝ๋ง๋ค๋ฉด ํธ์ 1,000๊ฐ์ ํ๋ฃจ 14.4๋ง ํ(์ฝ 14MB)์ด๋ค.\n *\n * `onClosed` ๋ **์ค๋ฅ๋ฅผ ๋ด์ง ์์์ผ ํ๋ค**(ํธ์ถ๋ถ๊ฐ ๊ฐ์ผ๋ค) โ ์์์ด ์คํจํด๋ ์ฅ๋ถ๋ ๊ณ์ ๊ตด๋ฌ์ผ ํ๋ค.\n * ์์์ ์งํค๋ ๊ฒ๊ณผ ๊ด์ธก์ ์งํค๋ ๊ฒ์ ๋ค๋ฅธ ์ผ์ด๊ณ , ๋ค์ฃ๊ฒ์ด ์์ฃ๊ฒ ๋๋ฌธ์ ๋ฉ์ถ๋ฉด ์ ๋๋ค.\n */\nexport function rollIngestWindow(\n ledger: IngestLedger,\n nowMs: number,\n windowMs = INGEST_WINDOW_MS,\n onClosed?: (closed: IngestWindow) => void\n): void {\n if (ledger.window.startMs < 0) {\n ledger.window.startMs = nowMs\n return\n }\n if (nowMs - ledger.window.startMs < windowMs) return\n\n const closed: IngestWindow = { ...ledger.window, endMs: nowMs }\n ledger.trend.push(closed)\n ledger.window = { startMs: nowMs, endMs: -1, offered: 0, rejected: 0, undelivered: 0, rows: 0, flushes: 0 }\n\n if (ledger.trend.length > TREND_LIMIT) {\n const drop = ledger.trend.length - TREND_LIMIT\n ledger.trend.splice(0, drop)\n ledger.trendDropped += drop\n }\n\n /* ์์์ ๊ด์ธก์ ๋ง์ง ์๋๋ค โ ํฐ์ ธ๋ ์ฅ๋ถ๋ ์ด๋ฏธ ๊ฐฑ์ ๋๋ค. */\n if (onClosed) {\n try {\n onClosed(closed)\n } catch {\n /* ํธ์ถ๋ถ๊ฐ ์๋ฆฐ๋ค. ์ฌ๊ธฐ์ ์ผํค๋ ๊ฒ์ **์ฅ๋ถ์ ์งํ**์ ์งํค๊ธฐ ์ํด์๋ค. */\n }\n }\n}\n\n/** ์ฌ์ ๋ฌถ์์ ํค. ์ฌ์ ๊ฐ ์ฌ๋ฟ์ด๋ฉด ํ ์ค๋ก ์๊ณ , ์์ผ๋ฉด ์ง์ด๋ด์ง ์๊ณ `unknown`. */\nexport function reasonKey(errors: string[] | undefined): string {\n const list = (errors ?? []).map(e => String(e).trim()).filter(Boolean)\n return list.length ? list.join(' ยท ') : 'unknown'\n}\n\nfunction safeJson(v: unknown): string {\n try {\n const s = JSON.stringify(v)\n return s === undefined ? String(v) : s\n } catch {\n return '(serialization failed)' /* ์ํ ์ฐธ์กฐ ๋ฑ โ ๋ชจ์์ ๋ชป ๋ณด์ฌ ์ฃผ๋ ๊ฒ๋ ์ฌ์ค์ด๋ค */\n }\n}\n\n/**\n * ํ ๋ฒ์ ์ธ์ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ์ ๋๋ค.\n *\n * `offered` ๋ฅผ ํจ๊ป ๋ฐ๋ ์ด์ : ํต๊ณผ์จ์ **์๋ก ๋ค๋ฅธ ๋ ๊ณ์๊ธฐ**์์ ๋๋ ๊ณ์ฐํ๋ฉด ๋ถ๋ชจ์ ๋ถ์๊ฐ ๋ค๋ฅธ\n * ๊ฒ์ ์ธ๊ฒ ๋๋ค. ๋์ ํ์๋ฆฌ์์ ๋ณธ ์๋ฅผ ๊ทธ๋๋ก ์ ๋๋ค.\n */\nexport function recordIngest(\n ledger: IngestLedger,\n offered: number,\n rejected: { record?: unknown; errors?: string[] }[] | undefined,\n nowMs: number,\n onClosed?: (closed: IngestWindow) => void,\n /** ๋งคํ์ ํต๊ณผํ์ง๋ง ํธ์์ ๋ฟ์ง ๋ชปํ ์ โ ใํต๊ณผใ๋ก ์ธ๋ฉด ํ๋ฉด์ด ๊ฑฐ์ง์ ๋งํ๋ค. */\n undelivered = 0\n): void {\n if (!Number.isFinite(offered) || offered < 0) return\n\n rollIngestWindow(ledger, nowMs, INGEST_WINDOW_MS, onClosed)\n\n ledger.offered += offered\n ledger.window.offered += offered\n ledger.lastAtMs = nowMs\n\n if (Number.isFinite(undelivered) && undelivered > 0) {\n ledger.undelivered += undelivered\n ledger.window.undelivered += undelivered\n ledger.lastUndeliveredAtMs = nowMs\n }\n\n const items = rejected ?? []\n if (!items.length) return\n\n ledger.rejected += items.length\n ledger.window.rejected += items.length\n\n for (const it of items) {\n const raw = reasonKey(it?.errors)\n const known = raw in ledger.byReason\n\n /* ์ฌ์ ์ข
๋ฅ ์ํ โ ๋์น๋ฉด ํ ์นธ์ผ๋ก ์ ๊ณ , **๋ฟ์๋ค๋ ์ฌ์ค**์ ํ์ํ๋ค. */\n let key = raw\n if (!known && Object.keys(ledger.byReason).length >= REASON_LIMIT) {\n key = OTHER_REASON\n ledger.reasonsCapped = true\n }\n\n const seen = ledger.byReason[key]\n ledger.byReason[key] = { count: (seen?.count ?? 0) + 1, lastAtMs: nowMs }\n\n /*\n * **ํ๋ณธ์ ์ฌ์ ๋ง๋ค ํ๋.** ์ด๋ฏธ ๊ทธ ์ฌ์ ์ ํ๋ณธ์ด ์์ผ๋ฉด ์ง๋ ฌํ๋ฅผ ์์ ํ์ง ์๋๋ค โ ์ด๋น 1๋ง ๊ฑด์ด\n * ์ ๋ถ ๊ฑฐ๋ถ๋ ๋ ๋ง๋ค์๋ง์ ๋ฒ๋ ค์ง๋ ๋ฌธ์์ด์ ๋ง๋ค์ง ์๊ธฐ ์ํด์๋ค(์ค์ธก: ๊ฑด๋น 0.24ยตs, GC ์๋ฐ).\n */\n if (ledger.sampledReasons.has(key)) {\n ledger.sampleDropped += 1\n continue\n }\n\n const text = safeJson(it?.record)\n const truncated = text.length > RECORD_MAX\n ledger.samples.push({\n atMs: nowMs,\n errors: key === OTHER_REASON ? [OTHER_REASON] : it?.errors?.length ? [...it.errors] : ['unknown'],\n record: truncated ? text.slice(0, RECORD_MAX) : text,\n ...(truncated ? { recordTruncated: true } : {})\n })\n\n ledger.sampledReasons.add(key)\n\n if (ledger.samples.length > SAMPLE_LIMIT) {\n const gone = ledger.samples.splice(0, ledger.samples.length - SAMPLE_LIMIT)\n /* ๋ฐ๋ ค๋ ํ๋ณธ์ ์ฌ์ ๋ ์์ธ์์๋ ๋นผ์ผ ๋ค์์ ๋ค์ ๋ฐ ์ ์๋ค(์ ๋นผ๋ฉด ๊ทธ ์ฌ์ ๋ ์์ํ ํ๋ณธ ์์). */\n for (const g of gone) ledger.sampledReasons.delete(reasonKey(g.errors))\n ledger.sampleDropped += gone.length\n }\n }\n}\n\n/**\n * ์ ๋์ **์ ์ ๊ฒ**์ ๊ธฐ๋กํ๋ค โ ์ฐฝ์ ๋๊ธธ ๋๊ฐ ๋์์ผ๋ฉด ๋๊ธฐ๊ณ , ํยท์๋ณต์ ๋ํ๋ค.\n *\n * โโ ์ ์ ์
๊ณผ ๊ฐ์ ์ฐฝ์ธ๊ฐ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์ ์ฅ๋ถ๋ฅผ ๋ง๋ค์ง ์๋๋ค. ์ด ์ฐฝ์ ใ๋ซํ ์ฐฝ๋ง ์ต๊ทผใยทใ0 ๊ณผ ์์์ ๊ฐ๋ฅธ๋คใยทใ์๋ฆฐ ๊ฒ์ ์ธ์ด ๋๋ฌ๋ธ๋คใ๋ฅผ\n * ์ด๋ฏธ ์งํค๊ณ , ๋ซํ ๋ ์์๊น์ง ๋๋ค. ๊ฐ์ ๊ท์จ์ ๋ ๋ฒ ๋ง๋ค๋ฉด ํ์ชฝ๋ง ๊ณ ์ณ์ง๋ค.\n *\n * โโ ์ ์
์ด ์์ด๋ ์ฐฝ์ ๋์ด๊ฐ๋ค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์๋ฎฌ ํธ์์ ๋ฐ๋ ๊ฒ ์์ด ์๊ธฐ๊ฐ ๋ธ ์ฌ์ค์ ์ ๋๋ค. ์ฐฝ์ด **์ ์
์์๋ง** ๋์ด๊ฐ๋ค๋ฉด ๊ทธ ํธ์์ ์ถ์ด์\n * ์์ํ ๋ํ๋์ง ์๋๋ค โ ๊ทธ๋์ ์ฐ๊ธฐ๋ ์ฐฝ์ ๋๊ธด๋ค.\n */\nexport function recordJournalWrite(\n ledger: IngestLedger,\n rows: number,\n nowMs: number,\n onClosed?: (closed: IngestWindow) => void\n): void {\n if (!Number.isFinite(rows) || rows <= 0) return\n rollIngestWindow(ledger, nowMs, INGEST_WINDOW_MS, onClosed)\n ledger.rows += rows\n ledger.flushes += 1\n ledger.window.rows += rows\n ledger.window.flushes += 1\n /*\n * **`lastAtMs` ๋ ๊ฑด๋๋ฆฌ์ง ์๋๋ค.** ๊ทธ ๊ฐ์ ใ๋ง์ง๋ง ์ ์
ใ์ด๊ณ , ๋๊ธด ํผ๋๋ฅผ ๊ฐ๋ ค๋ด๋ ๊ทผ๊ฑฐ๋ค. ์ฐ๊ธฐ๋ก\n * ๊ฐฑ์ ํ๋ฉด ๋ผ์ด๋ธ ํธ์์ ์ ์
์ด ๋๊ฒจ๋ ํฑ์ด ๋ง๋ ๋ธํ๋ฅผ ๊ณ์ ์ ์ผ๋ฏ๋ก **์์ํ ใ๋ฐฉ๊ธ ๋ฐ์๋คใ**๊ฐ ๋๊ณ ,\n * ใ์ค๋ ๋๊ธด ํผ๋์ ์ ์ฐฝ์ผ๋ก ์ด๋ก์ ๋ด์ง ์๋๋คใ๊ฐ ์กฐ์ฉํ ๋ฌด๋ ฅํด์ง๋ค. ์ถ์ ๋ฐ๋ก ๋ ๋ค.\n */\n ledger.lastWriteAtMs = nowMs\n}\n\n/**\n * ํ๋ ํ์ .\n *\n * `not-applicable` ๊ณผ `not-connected` ๋ฅผ ์์ง ์๊ณ , ์ฌ์ง ์์ ๊ฒ์ ์ ์ยท๋น์ ์์ผ๋ก ์ฑ์ฐ์ง ์๋๋ค\n * (`unknown`). ์๋ฎฌ ํธ์์ ใ๋๊ธฐํ ์ ๋จใ์ด๋ผ ๋งํ๋ฉด ๊ฑฐ์ง ๊ฒฝ๋ณด์ด๊ณ , **๊ฑฐ์ง ๊ฒฝ๋ณด๋ ์ฐธ ๊ฒฝ๋ณด๋ฅผ ์ฃฝ์ธ๋ค.**\n */\nexport type SyncVerdict =\n | 'syncing' /** ์ ์
์ด ์๊ณ ํต๊ณผ์จ์ด ๋ฌธํฑ ์ด์ */\n | 'mapping-blocked' /** ์ ์
์ ์๋๋ฐ ๊ฑฐ๋ถ๊ฐ ๋ฌธํฑ์ ๋๋๋ค โ ์ฌ์ ๋ฅผ ๋ณด๊ณ ๋งคํ์ ๊ณ ์น๋ค */\n /**\n * ๋ค์ด์ค๋๋ฐ **์ปค๋์ด ๋ฐ์ง ์๋๋ค** โ ์ฌ์ค์ด ์ฌ๋ผ์ง๊ณ ์๋ค.\n *\n * โโ ์ด๋ฆ์ด ์ฌ์ค๋ณด๋ค ์ข๋ค (2026-08-20์ ๋๋ฌ๋ฌ๋ค) โโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ๊ด์ธกํ ๊ฒ์ ใ์ปค๋์ด ๋ฐ์ง ์์๋คใ(`ingestLive` ๊ฐ 0)์ด๊ณ , **๋ฉ์ถ ๊ฒ์ ๊ทธ ์์ธ ์ค ํ๋์ผ ๋ฟ**์ด๋ค.\n * ๋ค๋ฅธ ์์ธ์ด ์ค์ ๋ก ์์๋ค: ๋ฏธ๋ฌ๋ก ์ ์ธ๋ ํธ์์ ์ฌ๋์ด ํ๋ฉด์์ ์์ํ๋ฉด ์๋ฎฌ ๊ตฌ๋์ผ๋ก ๋ด๊ณ , ๊ทธ\n * ํธ์์ **๋๊ณ ์์ผ๋ฉด์** ์ ์
์ ํ ๊ฑด๋ ๋ฐ์ง ๋ชปํ๋ค. ๊ทธ๋ ํ๋ฉด์ ํ์ชฝ์ ใrunningใ, ๋ค๋ฅธ ์ชฝ์\n * ใ๋ฉ์ถฐใ๋ผ๊ณ ์ ์๊ณ ์ฌ๋์ ใ์์ ๋ฒํผ์ ๋๋ฅด๋ฉด ๋๊ฒ ๋คใ๋ผ๋ ์๋ฑํ ์ฒ๋ฐฉ์ผ๋ก ๊ฐ๋ค.\n *\n * ๊ทธ๋์ **ํ๋ฉด ๋ฌธ๊ตฌ๋ ๊ด์ธก ๊ทธ๋๋ก** ์ ๋๋ค(ใํธ์์ ๋ฟ์ง ์๊ณ ๋ฒ๋ ค์ง๋ ์คใ). ์ด ํค ์ด๋ฆ์ ์๋ฒยทํ๋ฉดยท\n * ์ํ์ ๊ฑธ์น ๊ณ์ฝ ๋ฌธ์์ด์ด๋ผ ๊ทธ๋๋ก ๋์ง๋ง, ์ด๋ฆ์ ์์ธ์ผ๋ก ์ฝ์ง ์๋๋ค.\n */\n | 'twin-not-running'\n | 'no-traffic' /** ํผ๋๋ ๋ถ์๋๋ฐ ์ ์๊ฐ 0 โ ์์ฒยท๋ง์ ๋ณธ๋ค */\n | 'not-connected' /** ํผ๋ ์์ฒด๊ฐ ์๋ค โ ๊ฒฐ์ ํ๋ค */\n | 'not-applicable' /** ์๋ณธ์ด ๋จน์ด์ง ์๋ ํธ์(์๋ฎฌ)ยท๋ฉ์ถ ํธ์ โ ๋ฌผ์ ๋์์ด ์๋๋ค */\n | 'unknown' /** ํ ๋ฒ๋ ๋ฐ์ง ์์๊ฑฐ๋ ์ฐฝ์ด ์์ง ๋ซํ์ง ์์๋ค โ ๊ธฐ๋ค๋ฆฐ๋ค */\n\nexport function syncVerdictOf(args: {\n /** `live-feed-registry.liveFeedStateOf` ์ ๋ต์ ๊ทธ๋๋ก ๋ฐ๋๋ค โ ํ์ ์ดํ๋ฅผ ๋ ๋ฒ ๋ง๋ค์ง ์๋๋ค. */\n feedState: 'attached' | 'detached' | 'not-applicable'\n /** ๋ง์ง๋ง์ผ๋ก **๋ซํ** ์ฐฝ. ์์ผ๋ฉด `null`. */\n recent: { offered: number; rejected: number } | null\n /** ๋ง์ง๋ง์ผ๋ก ๋ฌด์์ด๋ ๋ฐ์ ์๊ฐ. ํ ๋ฒ๋ ์์ผ๋ฉด `-1` โ 0 ์ด ์๋๋ค(0 ์ 1970๋
์ด๋ค). */\n lastAtMs?: number\n /** ์ง๊ธ. `lastAtMs` ๋ฅผ ๊ฒฌ์ค ๋๋ง ์ด๋ค. */\n nowMs?: number\n /** ๋ง์ง๋ง์ผ๋ก **๋ฒ๋ ค์ง** ์๊ฐ. ํ ๋ฒ๋ ์์ผ๋ฉด `-1`. */\n lastUndeliveredAtMs?: number\n threshold?: number\n}): SyncVerdict {\n /*\n * โโ ๋ฒ๋ ค์ง๊ณ ์๋ ๊ฒ์ด ๊ฐ์ฅ ๋จผ์ ๋ค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ํธ์์ด ๋ฉ์ถ๋ฉด ํผ๋๋ ๋จ์ ๊ณ์ ๋ ์ฝ๋๋ฅผ ๋๋ฅด๊ณ , ์ปค๋์ ๊ทธ๊ฒ์ ์กฐ์ฉํ ๋ฒ๋ฆฐ๋ค. ๊ทธ ์ํ๋ฅผ ใํด๋น ์์ใ\n * ์ด๋ผ ๋ถ๋ฅด๋ฉด **์ฌ์ค์ด ์ฌ๋ผ์ง๋ ๋์ ํ๋ฉด์ด ์์ฌ์ํจ๋ค** โ ์ค์ ๋ก ๊ทธ๋ ๊ฒ ๋ด๋ค(๋ฉ์ถ ํธ์ ์์ ใ150\n * ํต๊ณผ ยท 100%ใ). ๊ทธ๋์ ์๋ฎฌยท๋ฉ์ถค ํ์ ๋ณด๋ค ๋จผ์ ๋ณธ๋ค.\n *\n * ์๋ฎฌ ํธ์์๋ ์ด ๊ฐ์ด ์์ง ์๋๋ค(๋จน์ด๋ ํผ๋๊ฐ ์์ผ๋ฏ๋ก ๋ฏธ์ ๋ฌ๋ ์๋ค). ๊ทธ๋์ ์ด ์์๊ฐ ์๋ฎฌ์\n * ๊ฑฐ์ง ๊ฒฝ๋ณด๋ฅผ ์ฃผ์ง ์๋๋ค.\n */\n if (\n typeof args.lastUndeliveredAtMs === 'number' &&\n args.lastUndeliveredAtMs >= 0 &&\n typeof args.nowMs === 'number' &&\n args.nowMs - args.lastUndeliveredAtMs <= STALE_AFTER_MS\n ) {\n return 'twin-not-running'\n }\n\n if (args.feedState === 'not-applicable') return 'not-applicable'\n if (args.feedState === 'detached') return 'not-connected'\n\n /*\n * โโ ๋๊ธด ํผ๋๊ฐ ์ด๋ก์ผ๋ก ๋จ์ง ์๊ฒ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์ฐฝ์ **๋ค์ ์ ์
์ด ์์ ๋** ๋ซํ๋ค. ๊ทธ๋์ ์ ์
์ด ๋ฉ์ถ๋ฉด ์ฐฝ๋ ๋ฉ์ถ๊ณ , ใ์ต๊ทผ ์ฐฝใ์ ๋ฉ์ถ๊ธฐ ์ง์ ์\n * ๊ฑด๊ฐํ๋ ์ฐฝ์ผ๋ก ๋จ๋๋ค. ๊ทธ ์ฐฝ๋ง ๋ณด๊ณ ํ์ ํ๋ฉด **์ด์ ์ฃฝ์ ํผ๋๊ฐ ์ค๋๋ ใ๋๊ธฐํ ์คใ**์ด๋ค. ์ด\n * ๊ธฐ๋ฅ์ด ์๋ ์ด์ ๊ฐ ๋ฐ๋ก ๊ทธ ์ํ๋ฅผ ๋๋ฌ๋ด๋ ๊ฒ์ด๋ฏ๋ก, ๊ทธ๋ ์ด๋ก์ ๋ด๋ฉด ๋ชฉ์ ์ ๋์น๋ค.\n *\n * ๊ทธ๋์ ์ฐฝ๊ณผ ๋ณ๊ฐ๋ก **์ง๊ธ๊น์ง์ ์นจ๋ฌต**์ ๋จผ์ ๋ณธ๋ค. ํ ์ฐฝ์ ํต์งธ๋ก ์๋ฌด๊ฒ๋ ๋ฐ์ง ์์์ผ๋ฉด ๊ทธ๊ฒ์\n * ใ์ ์
์์ใ์ด๋ค โ ์ค์ ๋ก ๊ทธ ๊ตฌ๊ฐ์ ์ฐฝ์ ๋น์ด ์๊ฒ ๋๋ค.\n *\n * ์ด ํ๋จ์ ์๋ฒ์ ๋๋ ์ด์ : ์๋น์ฒ๊ฐ ์ฌ๋ฟ(๋ชฉ๋กยท์ฐ๊ฒฐ ์์ธยท์์ผ๋ก ์๊ธธ ๊ฒ)์ด๊ณ , ํ๋ฉด๋ง๋ค ๋ค์\n * ํ๋จํ๋ฉด ๊ท์น์ด ๊ฐ๋ผ์ ธ ์ด๋ค ํ๋ฉด์ ์ด๋ก, ์ด๋ค ํ๋ฉด์ ๊ฒฝ๊ณ ๋ฅผ ๋งํ๋ค.\n *\n * ํ๊ณ โ ํ ์ฐฝ(10๋ถ)๋ณด๋ค **๋๋ฆฌ๊ฒ ๊ธท๋ ์์ฒ**์ ๊ธท๋ ์ฌ์ด์ ใ์ ์
์์ใ์ผ๋ก ๋ณด์ธ๋ค. ์ฅ๋ถ๋ ์์ฒ์\n * ์ฃผ๊ธฐ๋ฅผ ๋ชจ๋ฅด๋ฏ๋ก ์ด๋ณด๋ค ์ ํํ ๋ตํ ์ ์๋ค. ์ฃผ๊ธฐ๋ฅผ ์๊ฒ ๋๋ฉด ๊ทธ ๊ฐ์ผ๋ก ๊ฒฌ์ฃผ๋ ๊ฒ์ด ๋ง๋ค.\n */\n if (typeof args.lastAtMs === 'number' && typeof args.nowMs === 'number') {\n if (args.lastAtMs < 0) return 'unknown' /* ๋ถ์์ง๋ง ํ ๋ฒ๋ ๋ฐ์ง ์์๋ค โ ๊ธฐ๋ค๋ฆฐ๋ค */\n if (args.nowMs - args.lastAtMs > STALE_AFTER_MS) return 'no-traffic'\n }\n\n if (!args.recent) return 'unknown'\n if (args.recent.offered <= 0) return 'no-traffic'\n\n const ratio = (args.recent.offered - args.recent.rejected) / args.recent.offered\n return ratio >= (args.threshold ?? HEALTHY_ACCEPTED_RATIO) ? 'syncing' : 'mapping-blocked'\n}\n\nexport interface IngestWindowView {\n from: string\n to: string\n offered: number\n /** **ํธ์์ ๋ฟ์** ์. ์ ์ โ ๊ฑฐ๋ถ โ ๋ฏธ์ ๋ฌ. */\n accepted: number\n /** ๋งคํ์ด ๊ฑฐ๋ถํ ์ โ ์ฒ๋ฐฉ์ ๋งคํ์ ๊ณ ์น๋ ๊ฒ. */\n rejected: number\n /** ๋งคํ์ ํต๊ณผํ์ผ๋ ํธ์์ ๋ฟ์ง ๋ชปํ ์ โ ์ฒ๋ฐฉ์ ํธ์์ ์ธ์ฐ๋ ๊ฒ. */\n undelivered: number\n /** ํต๊ณผ์จ(0~1). ์ ์๊ฐ ์์ผ๋ฉด `null` โ **1 ๋ก ์ฑ์ฐ๋ฉด ใ์ ๋ถ ํต๊ณผใ๋ก ์ฝํ๋ค.** */\n acceptedRatio: number | null\n /** ์ด ์ฐฝ์ ์ ํ ํ. */\n rows: number\n /** ๊ทธ๊ฒ์ ์ ๊ธฐ ์ํด DB ๋ฅผ ๋๋๋ฆฐ ํ์ โ ํ๋น ์๋ณต์ด ์ค์๋์ง ๋ณด๋ ๊ฐ. */\n flushes: number\n}\n\nexport interface IngestHealthView {\n verdict: SyncVerdict\n /** ํ์ ์ ์ด ๋ฌธํฑ โ ํ๋ฉด์ด ์ ๊ทธ ํ์ ์ธ์ง ๋งํ ์ ์๊ฒ ํจ๊ป ๋ธ๋ค. */\n threshold: number\n /** ๋ง์ง๋ง์ผ๋ก ๋ซํ ์ฐฝ. ์ฐฝ์ด ํ ๋ฒ๋ ๋ซํ์ง ์์์ผ๋ฉด `null`. */\n recent: IngestWindowView | null\n /** ๋ซํ ์ฐฝ๋ค, ์ค๋๋ ๊ฒ๋ถํฐ. */\n trend: IngestWindowView[]\n /** ์ถ์ด ์ํ์์ ๋ฐ๋ ค๋ ์ฐฝ ์. */\n trendDropped: number\n /** ๋์ (๊ธฐ๋ ์ดํ). */\n total: {\n offered: number\n accepted: number\n rejected: number\n undelivered: number\n acceptedRatio: number | null\n /** ์ ๋์ ์ ํ ํ๊ณผ ๊ทธ๊ฒ์ ์ํด DB ๋ฅผ ๋๋๋ฆฐ ํ์ โ ๊ธฐ๋ ์ดํ ๋์ . */\n rows: number\n flushes: number\n }\n /** ์ฌ์ ๋ณ ๋์ , ๋ง์ ๊ฒ๋ถํฐ. `lastAt` ์ด ๋ฉ์ถ ์ฌ์ ๋ ์ด๋ฏธ ๊ณ ์ณ์ง ๊ฒ์ด๋ค. */\n reasons: { reason: string; count: number; lastAt: string }[]\n /** ์ฌ์ ์ข
๋ฅ๊ฐ ์ํ์ ๋ฟ์ ์ผ๋ถ๊ฐ `(other reasons)` ๋ก ์ ํ๋. */\n reasonsCapped: boolean\n samples: RejectSample[]\n sampleDropped: number\n /** ๋ง์ง๋ง์ผ๋ก ๋ฌด์์ด๋ ๋ฐ์ ์๊ฐ. ํ ๋ฒ๋ ์์ผ๋ฉด `null`. */\n lastAt: string | null\n /** ๋ง์ง๋ง์ผ๋ก ์ ๋์ ์ ์ ์๊ฐ. ํ ๋ฒ๋ ์์ผ๋ฉด `null` โ ๋ฐ์ ์ ์๋ ํธ์๋ ์ด ๊ฐ์ ์์ ์ ์๋ค. */\n lastWriteAt: string | null\n /**\n * **์๋ณธ์ ๋ฟ์ง ๋ชปํ๊ณ ์๋ค** โ ์์ผ๋ฉด ๋ฟ๊ณ ์๋ค๋ ๋ป์ด๋ค(ยง`IngestLedger.readFailure`).\n *\n * ์ปค์ ์ ์ฒด(`cursorStall`)์ **์์ด์ง ์๋๋ค**: ์ด์ชฝ์ ๊ธฐ๋ค๋ฆฌ๋ฉด ํ๋ฆฌ๊ณ ๊ทธ์ชฝ์ ๊ธฐ๋ค๋ ค๋ ์ ํ๋ฆฐ๋ค.\n *\n * ใ์ ์
์์ใ๊ณผ **๋ค๋ฅธ ํ์ **์ด๋ค: ์ ์
์์์ ์๋ณธ์ด ์กฐ์ฉํ ๊ฒ์ผ ์ ์๊ณ , ์ด๊ฒ์ ์ฐ๋ฆฌ๊ฐ ๋ฌป์ง๋\n * ๋ชปํ ๊ฒ์ด๋ค. ํ๋ฉด์ ๋ ๋ฌธ์ฅ์ ๋ค๋ฅด๊ฒ ๋งํด์ผ ํ๋ค โ ์ค ์๋ณธ์ด ๋๊ฒผ์ ๋ ์ฌ์ฉ์๊ฐ ์์ธ์ ์ฐพ์ ์\n * ์๋์ง๊ฐ ๊ทธ ์ฐจ์ด๋ค.\n */\n readFailure?: {\n consecutive: number\n /** ์ด ๋จ์ ์ด ์์๋ ์๊ฐ โ ใ20๋ถ์งธใ๋ฅผ ๋งํ ์ ์๊ฒ. */\n since: string\n lastAt: string\n reason: string\n stream?: string\n }\n}\n\nfunction toWindowView(w: IngestWindow, fallbackEndMs: number): IngestWindowView {\n /* ใํต๊ณผใ๋ **ํธ์์ ๋ฟ์** ๊ฒ๋ง์ด๋ค. ๋ฒ๋ ค์ง ๊ฒ์ ํต๊ณผ๋ก ์ธ๋ฉด ํ๋ฉด์ด ์์ฌ์ํจ๋ค. */\n const accepted = w.offered - w.rejected - w.undelivered\n return {\n from: new Date(w.startMs).toISOString(),\n to: new Date(w.endMs >= 0 ? w.endMs : fallbackEndMs).toISOString(),\n offered: w.offered,\n accepted,\n rejected: w.rejected,\n undelivered: w.undelivered,\n acceptedRatio: w.offered > 0 ? round4(accepted / w.offered) : null,\n rows: w.rows,\n flushes: w.flushes\n }\n}\n\n/**\n * ์ฝ๊ธฐ์ฉ ์์ฝ.\n *\n * ์ฅ๋ถ๊ฐ ์์ด๋(ํ ๋ฒ๋ ๋ฐ์ง ์์ ํธ์) **ํ์ ์ ๋ธ๋ค** โ ํผ๋ ์ฌ์ค๋ง์ผ๋ก ๋ตํ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค\n * (`not-applicable`ยท`not-connected`). ๊ทธ ๊ฒฝ์ฐ ์์น๋ ๋น์ด๋ค: ์๋ ๊ฐ์ 0 ์ผ๋ก ์ฑ์ฐ์ง ์๋๋ค.\n *\n * `nowMs` ๋ฅผ ๋ฐ๋ ์ด์ : ๋๊ธด ํผ๋๋ฅผ ๊ฐ๋ ค๋ด๋ ค๋ฉด ใ๋ง์ง๋ง ์ ์
์ด ์ผ๋ง๋ ์ ์ธ๊ฐใ๋ฅผ ๋ด์ผ ํ๊ณ , ๊ทธ ํ๋จ์\n * ํ๋ฉด์ด ์๋๋ผ ์ฌ๊ธฐ์ ํ๋ค(์๋น์ฒ๋ง๋ค ๋ค์ ํ๋จํ๋ฉด ๊ท์น์ด ๊ฐ๋ผ์ง๋ค). ์ํ์ด ์๊ฐ์ ๊ณ ์ ํ ์ ์๋๋ก\n * ์ธ์๋ก ๋ฐ๋๋ค.\n */\nexport function ingestHealth(\n ledger: IngestLedger | undefined,\n feedState: 'attached' | 'detached' | 'not-applicable',\n threshold = HEALTHY_ACCEPTED_RATIO,\n nowMs: number = Date.now()\n): IngestHealthView {\n const recentRaw = ledger?.trend.length ? ledger.trend[ledger.trend.length - 1] : null\n /* ์ด๋ฆฐ ์ฐฝ์ ๋ ์๊ฐ ๋์ฒด๊ฐ โ ์ ์
์ด ์๋ ์ฅ๋ถ์์ `-1` ์ ์๊ฐ์ผ๋ก ์ฝ์ผ๋ฉด 1969๋
์ด ํ๋ฉด์ ๋ฌ๋ค. */\n const lastAnyMs = Math.max(ledger?.lastAtMs ?? -1, ledger?.lastWriteAtMs ?? -1)\n const verdict = syncVerdictOf({\n feedState,\n recent: recentRaw,\n lastAtMs: ledger?.lastAtMs ?? -1,\n lastUndeliveredAtMs: ledger?.lastUndeliveredAtMs ?? -1,\n nowMs,\n threshold\n })\n\n /*\n * **์ ์
์ด ์์ด๋ ใ๋น ์ฅ๋ถใ๊ฐ ์๋๋ค.** ์๋ฎฌ ํธ์์ ๋ฐ๋ ๊ฒ ์์ด ์ ๋๋ค. ์ ์
์๊ฐ๋ง ๋ณด๊ณ ๋น์๋ค๊ณ \n * ํ๋จํ๋ฉด ๊ทธ ํธ์์ ์ฐฝ์ ๋ง๋ค์ด์ ธ ์๋๋ฐ ํ๋ฉด์๋ ์๋ฌด ์ถ์ด๋ ๋์ค์ง ์๋๋ค(์ด ์ถ์ ๋ฃ์ ์ด์ ๊ฐ ๊ทธ๊ฒ์ด๋ค).\n */\n if (!ledger || (ledger.lastAtMs < 0 && ledger.lastWriteAtMs < 0)) {\n return {\n verdict,\n threshold,\n recent: null,\n trend: [],\n trendDropped: 0,\n total: { offered: 0, accepted: 0, rejected: 0, undelivered: 0, acceptedRatio: null, rows: 0, flushes: 0 },\n reasons: [],\n reasonsCapped: false,\n samples: [],\n sampleDropped: 0,\n lastAt: null,\n lastWriteAt: null,\n /*\n * **์ด ์งง์ ๋ต์๋ ๋จ์ ์ ์ค์ด์ผ ํ๋ค** โ ์ด ์๋ฆฌ๊ฐ ๋ฐ๋ก ๊ทธ ํธ์์ ๋ชจ์ต์ด๋ค.\n *\n * ๋ฐ์ ๊ฒ๋ ์ ์ ๊ฒ๋ ์๋ ์ฅ๋ถ๋ ใ์์ง ์๋ฌด ์ผ๋ ์๋คใ๋ก ์ฝํ๋๋ฐ, ์๋ณธ์ ๋ฟ์ง ๋ชปํ๋ ํธ์์ด\n * ์ ํํ ๊ทธ ๋ชจ์ต์ด๋ค(์ฝ์ง ๋ชปํ๋ฉด ๋ฐ์ ๊ฒ๋ ์ ์ ๊ฒ๋ ์๋ค). ์ฌ๊ธฐ์ ๋จ์ด๋จ๋ฆฌ๋ฉด **๊ฐ์ฅ ํ์ํ\n * ์๊ฐ์** ๊ทธ ์ฌ์ค์ด ์ฌ๋ผ์ง๋ค โ ์ค์ธก์ผ๋ก ์๋ณธ์ด ๋๊ธด ํธ์์ด ์ด ๊ฒฝ๋ก๋ก ๋ตํ๊ณ ์์๋ค.\n */\n ...(ledger?.readFailure\n ? {\n readFailure: {\n consecutive: ledger.readFailure.consecutive,\n since: new Date(ledger.readFailure.sinceMs).toISOString(),\n lastAt: new Date(ledger.readFailure.lastAtMs).toISOString(),\n reason: ledger.readFailure.reason,\n ...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {})\n }\n }\n : {}),\n /* ์ปค์ ์ ์ฒด๋ **์ด ๊ฐ๋์์** ๋ด๋ณด๋ธ๋ค โ ์ ์
์ด ์๋ ์ฅ๋ถ์์๋ ์ ์ฒด๋ ์ค์ฌํ๋ค(์ฝ์์ผ๋ ๋ชป\n ๋๊ฒผ์ผ๋ฉด ์ ์
์ด 0์ด๋ค). ์ฌ๊ธฐ์ ๋จ์ด๋จ๋ฆฌ๋ฉด ๋ฐ๋ก ๊ทธ ์ํฉ์์ ์กฐ์ฉํด์ง๋ค. */\n ...(ledger?.cursorStall\n ? {\n cursorStall: {\n consecutive: ledger.cursorStall.consecutive,\n since: new Date(ledger.cursorStall.sinceMs).toISOString(),\n lastAt: new Date(ledger.cursorStall.lastAtMs).toISOString(),\n reason: ledger.cursorStall.reason,\n ...(ledger.cursorStall.stream ? { stream: ledger.cursorStall.stream } : {})\n }\n }\n : {})\n }\n }\n\n /* ใํต๊ณผใ๋ ํธ์์ ๋ฟ์ ๊ฒ๋ง์ด๋ค โ ์ฐฝ ๋ทฐ์ ๊ฐ์ ๊ท์น. */\n const accepted = ledger.offered - ledger.rejected - ledger.undelivered\n return {\n verdict,\n threshold,\n recent: recentRaw ? toWindowView(recentRaw, lastAnyMs) : null,\n trend: ledger.trend.map(w => toWindowView(w, lastAnyMs)),\n trendDropped: ledger.trendDropped,\n total: {\n offered: ledger.offered,\n accepted,\n rejected: ledger.rejected,\n undelivered: ledger.undelivered,\n acceptedRatio: ledger.offered > 0 ? round4(accepted / ledger.offered) : null,\n rows: ledger.rows,\n flushes: ledger.flushes\n },\n reasons: Object.entries(ledger.byReason)\n .map(([reason, v]) => ({ reason, count: v.count, lastAt: new Date(v.lastAtMs).toISOString() }))\n .sort((a, b) => b.count - a.count || a.reason.localeCompare(b.reason)),\n reasonsCapped: ledger.reasonsCapped,\n samples: [...ledger.samples],\n sampleDropped: ledger.sampleDropped,\n /* ใ๋ฐ์ ์ ์์ใ๊ณผ ใ๋ฐฉ๊ธ ๋ฐ์ใ์ ๊ฐ๋ฅธ๋ค โ ์ ๊ธฐ๋ง ํ๋ ํธ์์ ์ ์
์๊ฐ์ **์๋ค**. */\n lastAt: ledger.lastAtMs >= 0 ? new Date(ledger.lastAtMs).toISOString() : null,\n lastWriteAt: ledger.lastWriteAtMs >= 0 ? new Date(ledger.lastWriteAtMs).toISOString() : null,\n /* ๋ฟ์ง ๋ชปํ๊ณ ์์ผ๋ฉด ๊ทธ ์ฌ์ค์ ๋ธ๋ค โ ์์ผ๋ฉด ํ๋๋ฅผ ๋ง๋ค์ง ์๋๋ค(๋น ๊ฐ์ด ใ๋ฟ๋๋คใ๋ก ์ฝํ์ง ์๊ฒ). */\n ...(ledger.readFailure\n ? {\n readFailure: {\n consecutive: ledger.readFailure.consecutive,\n since: new Date(ledger.readFailure.sinceMs).toISOString(),\n lastAt: new Date(ledger.readFailure.lastAtMs).toISOString(),\n reason: ledger.readFailure.reason,\n ...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {})\n }\n }\n : {}),\n ...(ledger.cursorStall\n ? {\n cursorStall: {\n consecutive: ledger.cursorStall.consecutive,\n since: new Date(ledger.cursorStall.sinceMs).toISOString(),\n lastAt: new Date(ledger.cursorStall.lastAtMs).toISOString(),\n reason: ledger.cursorStall.reason,\n ...(ledger.cursorStall.stream ? { stream: ledger.cursorStall.stream } : {})\n }\n }\n : {})\n }\n}\n\n/** ๋น์จ์ ์๋ฆฟ์๋ฅผ ๋๋ํ ์ค๋ค โ 0.999 ๊ฐ 1 ๋ก ๋ฐ์ฌ๋ฆผ๋๋ฉด ใ์ ๋ถ ํต๊ณผใ๋ก ์ฝํ๋ค. */\nconst round4 = (v: number) => Math.round(v * 10000) / 10000\n"]}
|
|
1
|
+
{"version":3,"file":"ingest-health.js","sourceRoot":"","sources":["../../server/engine/ingest-health.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * ๋๊ธฐํ ๊ฑด๊ฐ โ **์ด ํธ์์ด ํ์ฅ๊ณผ ๋ง์ถฐ์ง๊ณ ์๋.** ์์(import ์์).\n *\n * โโ ํ ์ง๋ฌธ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ํ๋ฉด์์ ๊ฐ์ด ๋ณํ์ง ์์ ๋ ์์ธ์ด ๋ท์ธ๋ฐ, ์ง๊ธ๊น์ง **๋ท์ด ๋๊ฐ์ด ๋ณด์๋ค.**\n * โ ํผ๋๊ฐ ๋ถ์ง ์์๋ค โก ๋ถ์๋๋ฐ ์๋ฌด๊ฒ๋ ์ค์ง ์๋๋ค\n * โข ์ค๋๋ฐ ์ ๋ถ ๊ฑฐ๋ถ๋๋ค โฃ ์ ์์ธ๋ฐ ํ์ฅ์ด ๋ค์ด์จ ๊ฒ์ด ์๋ค\n * โข์ ํนํ ๋์๋ค โ ์ปค๋ฅํฐ์ ๋งคํ์ด ํ ๊ธ์ ํ๋ฆฌ๋ฉด ํธ์์ ใ๋น ๊ณต์ฅใ์ด ๋๊ณ , ๊ทธ ์ฌ์ค์ด ์๋ฒ ๋ก๊ทธ\n * ํ ์ค์๋ง ๋จ์๋ค. ํ์ฅ์ ๋๊ฐ ์ฌ๋์ ๋ก๊ทธ๋ฅผ ๋ค์ ธ์ผ ํ๋ค.\n *\n * โโ ์ ์ ๋๋ก๋ ๋ตํ ์ ์๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * **๊ฑฐ๋ถ๋ ๊ฒ์ ์ ๋์ ์๋ค** โ ๊ฑฐ๋ถ์ ๋ป์ด ๊ทธ๊ฒ์ด๋ค. ์ ๋์ ๊ณ์ฐํ๋ฉด ํต๊ณผํ ์ชฝ๋ง ๋์จ๋ค. ๊ฑฐ๋ถ์ ์ถ์ด๋\n * ์ธ๋ ์๋ฆฌ๋ฅผ ๋ฐ๋ก ๋์ด์ผ ๋์จ๋ค. ์ด ์ฅ๋ถ๊ฐ ๊ทธ ์๋ฆฌ๋ค.\n *\n * โโ ์ ๊ฑด๋ง๋ค ์ ์ฅํ์ง ์๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ๋ผ์ด๋ธ ๊ณ์ธก์ ์ด๋น ์ฌ๋ฌ ๊ฑด์ด๋ค. ๊ฑฐ๋ถ๋ง๋ค ํ์ ์ฐ๋ฉด ๊ทธ ์์ฒด๊ฐ ๋ถํ๊ฐ ๋๋ค(`reference-live.ts` ๊ฐ\n * ์ด๋ฏธ ๊ทธ๋ ๊ฒ ์ ์ด ๋์๋ค). ๊ทธ๋ฆฌ๊ณ ์ด ํจํค์ง๋ **`integration-base` ๋ฅผ ์์ง ์๋๋ค**(์ด์์ฑ ๊ท์ฝ) โ\n * ์๋๋ฆฌ์ค ๊ฒฝ๋ก๊ฐ ์ฐ๋ dead-letter ๋ฅผ ์ฌ๊ธฐ์ ๋ถ๋ฅผ ์ ์๋ค. ๊ทธ๋์ **์ง๊ณํ๋ค.**\n *\n * โโ ํต๊ณผ์ ๊ฑฐ๋ถ๋ฅผ ํจ๊ป ์ผ๋ค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ๊ฑฐ๋ถ๋ง ๊ทธ๋ฆฌ๋ฉด ใ์ ์
์์ใ๊ณผ ใ์ ์ใ์ด **๋ ๋ค ๊ฑฐ๋ถ 0** ์ผ๋ก ๊ฐ์ ๋ณด์ธ๋ค. ์ ์ ์๊ฐ ์์ด์ผ ๊ฐ๋ฆฐ๋ค.\n *\n * โโ ์งํค๋ ๊ท์จ ๋ท โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * โ **๋ซํ ์ฐฝ๋ง ใ์ต๊ทผใ์ด๋ค** โ ์ฑ์ฐ๋ ์ค์ธ ์ฐฝ์ ๊ณผ์ ์ง๊ณ๋ค(๋ถํ ๊ณ๊ธฐํ์์ ๊ฒช์๋ค).\n * โก **0 ๊ณผ ใ์์ใ์ ๊ฐ๋ฅธ๋ค** โ ์ ๋ฐ์ ๊ฒ์ `null`, ๋ฐ์์ง๋ง ๊ฑฐ๋ถ 0 ์ `0`.\n * โข **์๋ฆฌ์ง ์๊ณ ์๋ฅด์ง ์๋๋ค** โ ํ๋ณธยท์ถ์ด ์ํ์์ ๋ฐ๋ ค๋ ์๋ฅผ ํจ๊ป ๋ธ๋ค.\n * โฃ **ํต๊ณผ์จ์ 1 ์ ํจ๋ถ๋ก ์ฐ์ง ์๋๋ค** โ 1,000๊ฑด ์ค 1๊ฑด ๊ฑฐ๋ถ๋ 0.999 ๋ค.\n */\n\n/** ์ถ์ด ์ฐฝ ํ๋ โ ์ ์ยทํต๊ณผยท๊ฑฐ๋ถยท๋ฏธ์ ๋ฌ, ๊ทธ๋ฆฌ๊ณ **์ ํ ๊ฒ**์ ํจ๊ป ๋ ๋ค. */\nexport interface IngestWindow {\n /** ์ฐฝ์ด ์ด๋ฆฐ ์๊ฐ(ms). */\n startMs: number\n /** ์ฐฝ์ด ๋ซํ ์๊ฐ(ms). ์์ง ์ฑ์ฐ๋ ์ค์ด๋ฉด `-1`. */\n endMs: number\n /** ์ด ์ฐฝ์ ์ ์๋ ๋ ์ฝ๋ ์(๊ฑฐ๋ถ ์ฌ๋ถ ๋ฌด๊ด). */\n offered: number\n /** ๊ทธ์ค **๋งคํ์ด ๊ฑฐ๋ถํ** ์ โ ์ฒ๋ฐฉ์ ๋งคํ์ ๊ณ ์น๋ ๊ฒ์ด๋ค. */\n rejected: number\n /**\n * ๋งคํ์ ํต๊ณผํ์ง๋ง **ํธ์์ ๋ฟ์ง ๋ชปํ** ์ โ ์ฒ๋ฐฉ์ ํธ์์ ์ธ์ฐ๋ ๊ฒ์ด๋ค.\n *\n * โโ ์ ๊ฑฐ๋ถ์ ๋ฐ๋ก ์ธ๋ (2026-08-20์ ๊ฒช์๋ค) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ํธ์์ด ๋ผ์ด๋ธ๋ก ๋์ง ์์ผ๋ฉด ์ปค๋์ด ๋ ์ฝ๋๋ฅผ **์๋ฆฌ์ง ์๊ณ ๋ฒ๋ฆฐ๋ค**. ๊ทธ๋ฐ๋ฐ ์ฅ๋ถ๋ ๊ทธ๊ฒ์ ใํต๊ณผใ๋ก ์
๋ค.\n * ํ๋ฉด์ด ใ150 ๋ค์ด์ด ยท 150 ํต๊ณผ ยท 100%ใ๋ผ๊ณ ๋งํ๋ ๋์ 150๊ฑด์ ๋ฐ๋ฅ์ ๋ฒ๋ ค์ง๊ณ ์์๋ค. ์ด ๊ธฐ๋ฅ์ด\n * ๋ง์ผ๋ ค๋ ๋ฐ๋ก ๊ทธ๊ฒ์ ์ด ๊ธฐ๋ฅ์ด ์ ์ง๋ฅธ ์
์ด๋ค.\n *\n * ๊ฑฐ๋ถ์ ํฉ์น๋ ๊ฒ๋ ๋ต์ด ์๋๋ค โ ๊ฑฐ๋ถ๋ ใ๋งคํ์ ๊ณ ์ณ๋ผใ๋ ๋ง์ด๊ณ , ์ฌ๊ธฐ์ ํ์ํ ๋ง์ ใํธ์์ด ์\n * ๋๊ณ ์๋คใ๋ค. **์ฒ๋ฐฉ์ด ๋ค๋ฅด๋ฉด ๋ค๋ฅธ ์๋ก ์ผ๋ค.**\n */\n undelivered: number\n /**\n * ์ด ์ฐฝ์ **์ ๋์ ์ ํ ํ** ์ โ ใ๋ฌด์์ด ๋จ์๋ใ.\n *\n * ์ ์
๊ณผ ๋ค๋ฅธ ์ถ์ด๋ค: ์๋ฎฌ ํธ์์ ๋ฐ๋ ๊ฒ ์์ด ์๊ธฐ๊ฐ ๋ธ ์ฌ์ค์ ์ ๋๋ค(๊ทธ๋์ `offered` ๋ 0 ์ด๊ณ \n * `rows` ๋ 0 ์ด ์๋๋ค). ์ด ์นธ์ด ์์ผ๋ฉด ๊ทธ ํธ์์ ํ๋์ ์ด๋ ์ถ์ด์๋ ๋ํ๋์ง ์๋๋ค.\n */\n rows: number\n /**\n * ๊ทธ๊ฒ์ ์ ๊ธฐ ์ํด **DB ๋ฅผ ๋๋๋ฆฐ ํ์**(flush) โ ใ์ฐ๋ฆฌ๊ฐ ๋ช ๋ฒ ๊ฐ๋ใ.\n *\n * ํ ์์ ๋ฐ๋ก ์ธ๋ ์ด์ : 2026-08-20 ์ ๊ณ ์น ๊ฒ์ด ๋ฐ๋ก ์ด ๊ฐ์ด๋ค(ํ๋ง๋ค ํ ๋ฒ โ ์ฐฝ๋น ํ ๋ฒ). ํ๋ง\n * ์ธ๋ฉด ๊ทธ ๊ฐ์ ๋, ๋๋์๊ฐ๋ ๊ฒ๋ ๋ณด์ด์ง ์๋๋ค.\n */\n flushes: number\n}\n\n/** ๊ฑฐ๋ถ ํ๋ณธ ํ๋ โ ๋งคํ์ ๊ณ ์น๋ ค๋ฉด ์ค์ ๋ชจ์์ ๋ด์ผ ํ๋ค. */\nexport interface RejectSample {\n atMs: number\n /** ์ปค๋์ด ๋ธ ์ฌ์ . ์ฐ๋ฆฌ๊ฐ ๋ค์ ์ฐ์ง ์๊ณ ๊ทธ๋๋ก ์ฎ๊ธด๋ค. */\n errors: string[]\n /** ๋งํ ๋ ์ฝ๋์ ์ง๋ ฌํ. ๊ธธ๋ฉด ์๋ฅด๊ณ , ์๋๋ค๊ณ ํ์ํ๋ค. */\n record: string\n recordTruncated?: boolean\n}\n\nexport interface IngestLedger {\n /** ์ง๊ธ ์ฑ์ฐ๋ ์ค์ธ ์ฐฝ. `startMs < 0` ์ด๋ฉด ์์ง ์๋ฌด๊ฒ๋ ๋ฐ์ง ์์๋ค. */\n window: IngestWindow\n /** ๋ซํ ์ฐฝ๋ค โ ์ค๋๋ ๊ฒ์ด ์. ์ํ์ ๋์ผ๋ฉด ์์์ ๋ฐ๋ ค๋๋ค. */\n trend: IngestWindow[]\n /** ์ถ์ด์์ ๋ฐ๋ ค๋ ์ฐฝ ์. */\n trendDropped: number\n /** ๋์ ์ ์ยท๊ฑฐ๋ถยท๋ฏธ์ ๋ฌ. */\n offered: number\n rejected: number\n undelivered: number\n /** ๋์ โ ์ ํ ํ๊ณผ ๋๋๋ฆฐ ํ์. */\n rows: number\n flushes: number\n /**\n * ๋ง์ง๋ง์ผ๋ก **์ ์** ์๊ฐ. ํ ๋ฒ๋ ์์ผ๋ฉด `-1`.\n *\n * ์ ์
์๊ฐ(`lastAtMs`)๊ณผ ๊ฐ๋ผ ๋๋ ์ด์ ๋ ์ `recordJournalWrite` ์ฃผ์์ ์๋ค โ ์์ผ๋ฉด ๋๊ธด ํผ๋๊ฐ\n * ์ด๋ก์ผ๋ก ๋ณด์ธ๋ค.\n */\n lastWriteAtMs: number\n /**\n * ๋ง์ง๋ง์ผ๋ก **๋ฒ๋ ค์ง** ์๊ฐ(ms). ํ ๋ฒ๋ ์์ผ๋ฉด `-1`.\n *\n * ์ฐฝ๊ณผ ๋ฐ๋ก ๋๋ค: ๋ฏธ์ ๋ฌ์ ์ฐฝ์ด ๋ซํ๊ธฐ ์ ์ ์์์ผ ํ๋ค(๊ทธ ์ฌ์ด์๋ ์ฌ์ค์ ๊ณ์ ์ฌ๋ผ์ง๊ณ ์๋ค).\n */\n lastUndeliveredAtMs: number\n /** ์ฌ์ ๋ณ ๋์ ๊ฑด์์ **๋ง์ง๋ง์ผ๋ก ๊ทธ ์ฌ์ ๊ฐ ๋ ์๊ฐ** โ ๊ณ ์น ์ฌ์ ๋ ์๊ฐ์ด ๋ฉ์ถ๋ค. */\n /**\n * **์ด๋ค ๊ธธ๋ก ๋ค์ด์๋** โ ๊ฒฝ๋ก๋ง๋ค ๊ฑด์์ ๋ง์ง๋ง ์๊ฐ.\n *\n * โโ ์ ํ์ํ๊ฐ (2026-08-26) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ํธ์์ด ๊ฐ์ ๋ฐ๊ณ ์๋ค๋ ๊ฒ์ ๊ณ๊ธฐ๊ฐ ๋งํด ์ฃผ๋๋ฐ, **๋ฌด์์ ํตํด ๋ฐ๋์ง๋ ์๋ฌด๋ ๋งํ์ง ์์๋ค.**\n * ์ปค๋ฅํฐ๊ฐ ๋ฌผ์ด์ ๋ฐ๋์ง, ์ฐ๊ฒฐ๋ ์์คํ
์ด ๋ฐ์ด ์ฃผ๋์ง, ์๋๋ฆฌ์ค๊ฐ ๋ฃ๋์ง, ๋ถํ ๋๊ตฌ๊ฐ ๋ฃ๋์ง โ\n * ํ๋ฉด์์ ๊ตฌ๋ณํ ์ ์์๋ค. ๊ทธ ๊ตฌ๋ณ์ด ์์ผ๋ฉด ใํด๋ง์ ์นํ
์ผ๋ก ๋ฐ๊ฟจ๋คใ๋ฅผ ํ์ธํ ๋ฐฉ๋ฒ๋ ์๋ค.\n */\n bySource: Record<string, { count: number; lastAtMs: number }>\n /**\n * **๊ฐ์ ์ฌ์ค์ด ๋ ๋ฒ ์์ ๋ฒ๋ฆฐ ์** โ ์๋ฆฌ์ง ์๊ณ ๋ฒ๋ฆฌ์ง ์๋๋ค.\n *\n * ์ด ์๊ฐ ํฌ๋ฉด ๋ณด๋ด๋ ์ชฝ์ด ๋ํ์ด ๋ณด๋ด๊ณ ์๋ค๋ ๋ป์ด๊ณ , ๊ทธ๊ฒ์ ๊ณ ์น ์ผ์ด๋ค(ํ์๊ด ์ปค๋ฅํฐ๊ฐ ํ ์ฃผ๊ธฐ์\n * 76๊ฑด์ ๋ํ์ด ๋ณด๋ด๋ ๊ฒ์ ์ด ์๋ก ๋ณผ ์ ์์์ด์ผ ํ๋ค).\n */\n duplicates: number\n lastDuplicateAtMs: number\n byReason: Record<string, { count: number; lastAtMs: number }>\n /**\n * ์ฌ์ ์ข
๋ฅ๊ฐ ์ํ์ ๋ฟ์๋.\n *\n * **๋ชจ์ ์ข
๋ฅ ์๋ ์ธ์ง ์๋๋ค** โ ๊ทธ๊ฒ์ ์ธ๋ ค๋ฉด ์ด๋ฏธ ๋ณธ ์ฌ์ ๋ฅผ ๋ชจ๋ ๊ธฐ์ตํด์ผ ํ๊ณ , ๊ทธ ์งํฉ์ด\n * ๋ฐ๋ก ์ด ์ํ์ผ๋ก ๋ง์ผ๋ ค๋ ๋ฌดํํ ์งํฉ์ด๋ค. ๋ชจ์ **๊ฑด์**๋ `byReason[OTHER_REASON].count` ๊ฐ ๋ตํ๋ค.\n */\n reasonsCapped: boolean\n /** ํ๋ณธ์ ์ด๋ฏธ ๋ฌ ์ฌ์ ๋ค โ ๊ฐ์ ์ฌ์ ๋ฅผ ๋ค์ ์ง๋ ฌํํ์ง ์๊ธฐ ์ํ ์์ธ(O(1) ์กฐํ). */\n sampledReasons: Set<string>\n /** ์ต๊ทผ ๊ฑฐ๋ถ ํ๋ณธ. */\n samples: RejectSample[]\n /** ํ๋ณธ์์ ๋ฐ๋ ค๋ ๊ฑฐ๋ถ ๊ฑด์. */\n sampleDropped: number\n /** ๋ง์ง๋ง์ผ๋ก ๋ฌด์์ด๋ ๋ฐ์ ์๊ฐ(ms). **ํ ๋ฒ๋ ์์ผ๋ฉด `-1`** โ 0 ์ผ๋ก ๋๋ฉด ์๊ฐ 0 ๊ณผ ๊ตฌ๋ณ๋์ง ์๋๋ค. */\n lastAtMs: number\n /**\n * **์๋ณธ์ ๋ฟ์ง ๋ชปํ ์ฌ์ค** (2026-08-23) โ ใ๋ฐ์ ๊ฒ์ด ์๋คใ์ **๋ค๋ฅธ ์ฌ์ค**์ด๋ค.\n *\n * โโ ๋ฌด์์ด ์๋ฌด ์ ํธ๋ ๋ด์ง ์์๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์ค ์๋ณธ์ด ๋๊ฒผ์ ๋(์ ์ ์๊ฐ ์ด๊ณผ) ํธ์์ **์กฐํ ๊ฐ๋ฅํ ์ํ ์ด๋์๋** ๊ทธ ์ฌ์ค์ด ์์๋ค.\n * `recordIngest` ๋ `onRecords` ๊ฐ ๋ถ๋ฆด ๋๋ง ๋๋ฌํ๊ณ , ์ฝ๊ธฐ๊ฐ ์คํจํ๋ฉด ๊ทธ ๋ฌธ์ ์ค์ง ์๋๋ค.\n * `TwinReference.lastError` ๋ ๋ง์คํฐ ๋๊ธฐยท์ ์ ์ํ์๋ง ์ ํ๋ค.\n *\n * ๊ทธ๋์ ํ๋ฉด์ด ๋ณผ ์ ์๋ ๊ฒ์ ใ์ ์ฌ์ค์ด ์๋คใ๋ฟ์ด์๊ณ , ๊ทธ๊ฒ์ **ใ์ฐ๊ฒฐ๋ ์์คํ
์์ ๋ค์ด์จ ๊ฒ์ด ์๋คใ์ ๊ตฌ๋ณ๋์ง\n * ์๋๋ค.** ์ค์ฆ ๋ฐ๋ชจ ์ค์ ์๋ณธ์ด ๋๊ธฐ๋ฉด ์ฌ์ฉ์๊ฐ ์์ธ์ ์ฐพ์ ์ ์๋ค.\n *\n * โโ ์ ใ๋ช ๋ฒใ๊ณผ ใ์ธ์ ๋ถํฐใ๋ฅผ ํจ๊ป ๋๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ํ ๋ฒ ์คํจํ ๊ฒ๊ณผ 20๋ถ์งธ ๋ชป ์ฝ๋ ๊ฒ์ ๋ค๋ฅธ ์ฌ์ค์ด๋ค. ๊ทธ ๊ตฌ๋ณ์ด ์์ผ๋ฉด ํ๋ฉด์ด ์๊ฐ์ ์คํจ์ ๋๋ผ๊ฑฐ๋\n * ๊ณ์๋ ๋จ์ ์ ๋์๋กญ์ง ์๊ฒ ๋งํ๋ค. ๊ทธ๋์ **์ฐ์ ์คํจ ์**์ **์ฒ์ ์คํจํ ์๊ฐ**์ ํจ๊ป ๋ ๋ค.\n *\n * ์ฑ๊ณตํ๋ฉด ์ง์ด๋ค โ ๊ณ ์ณ์ง ๋จ์ ์ด ํ๋ฉด์ ๋จ์ ์์ผ๋ฉด ๊ทธ๊ฒ๋ ๊ฑฐ์ง์ด๋ค.\n */\n /**\n * ๋ง์ง๋ง์ผ๋ก ๋๊ฒผ๋ค๊ฐ ๋์์จ ๊ฒ โ ์์ผ๋ฉด ๋๊ธด ์ ์ด ์๊ฑฐ๋ ์์ง ๋์์ค์ง ์์ ๊ฒ์ด๋ค.\n *\n * ์คํจ ๊ธฐ๋ก(`readFailure`)์ ๋์์ค๋ฉด ์ง์์ง๋ค. ๊ทธ๊ฒ๋ง ์ง์ฐ๋ฉด ใ๋๊ธด ์ ์ด ์์๋คใ๊ฐ ํ๋ฉด์์\n * ์ฌ๋ผ์ง๋ฏ๋ก, ๋์์จ ์ฌ์ค์ ๋ฐ๋ก ๋จ๊ธด๋ค.\n */\n lastRecovery?: { atMs: number; afterFailures: number; downMs: number }\n readFailure?: {\n /** ์ฐ์ ์คํจ ์ โ ์ฑ๊ณต ํ ๋ฒ์ 0 ์ผ๋ก ๋์๊ฐ๋ค. */\n consecutive: number\n /** ์ด ๋จ์ ์ด **์ฒ์** ์์๋ ์๊ฐ(ms). ์ฐ์์ด ๋๊ธฐ๋ฉด ๋ค์ ์ ํด์ง๋ค. */\n sinceMs: number\n /** ๋ง์ง๋ง ์คํจ ์๊ฐ(ms). */\n lastAtMs: number\n /** ๋ง์ง๋ง ์คํจ์ ์ฌ์ โ ์ฌ๋์ด ์ฝ๋ ํ ์ค(์๋ณธ์ด ์ค ๋ง ๊ทธ๋๋ก). */\n reason: string\n /** ์ด๋ ํ๋ฆ์์ ๋ฌ๋(์ด๋ํฐ๊ฐ ๋งํด ์ฃผ๋ฉด). ์๋ณธ๋ง๋ค ํ๋ฆ์ด ๋ค๋ฅด๋ฏ๋ก ์ด๋ ค ์๋ค. */\n stream?: string\n /** ๋ค์์ ๋ค์ ๋ฌผ์ ๋๊น์ง ๋จ์ ์๊ฐ(ms) โ ์ปค๋ฅํฐ๊ฐ ๋ฌผ๋ฌ์ฐ์ ๋๋ง ์๋ค. */\n nextRetryMs?: number\n }\n /**\n * **์ฝ์๋๋ฐ ์ฐฝ์ ๋๊ธธ ์ ์๋ค** (2026-08-24) โ ์์ **๋ค๋ฅธ ์ฌ์ค**์ด๋ค.\n *\n * โโ ์ ๊ฐ๋๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์ด ์นธ์ ๋ง๋ค๊ธฐ ์ ์๋ ๋ ์ฌ์ค์ด ๊ฐ์ ์ด๋ฆ์ผ๋ก ๋๊ฐ๋ค.\n *\n * readFailure ์๋ณธ์ ๋ฟ์ง ๋ชปํ๋ค โ **๊ธฐ๋ค๋ฆฌ๋ฉด ํ๋ฆฐ๋ค**\n * cursorStall ์ฝ์๋๋ฐ ์ปค์๊ฐ ๋ชป ๋์ด๊ฐ๋ค โ **๊ธฐ๋ค๋ ค๋ ์ ํ๋ฆฐ๋ค**\n *\n * ๋์งธ๋ ์ฝ๊ธฐ๊ฐ ์ฑ๊ณตํ ์คํจ๋ค: ํ ์๊ฐ์ ํ ํ์ด์ง๋ณด๋ค ๋ง์ ํ์ด ๋ชฐ๋ ค ์ปค์๋ฅผ ๊ทธ ์๊ฐ ๋ฐ์ผ๋ก ์ฎ๊ธธ ์\n * ์๋ค. ํ๋ฉด์ด ใ์๋ณธ์ ๋ฟ์ง ๋ชปํ๋คใ๊ณ ๋งํ๋ฉด ์ฌ๋์ ์๋ณธ์ ์์ฌํ๊ณ ๊ธฐ๋ค๋ฆฌ๋๋ฐ, ํ์ํ ์กฐ์น๋\n * ํ์ด์ง๋ฅผ ํค์ฐ๊ฑฐ๋ ๊ฐ์ ์๊ฐ ์์์ ์์๋ฅผ ์ ํ๋ ๊ฒ์ด๋ค. **์กฐ์น๊ฐ ๋ฐ๋์ธ ๋ ์ฌ์ค์ ํ ์ด๋ฆ์ผ๋ก\n * ๋ถ๋ฅด๋ฉด ๊ทธ ์ด๋ฆ์ ์ ๋ณด๊ฐ ์๋๋ผ ์คํด๋ค.**\n *\n * ๋ชจ์์ ์์ ๊ฐ๊ฒ ๋๋ค โ ใ๋ช ๋ฒใ๊ณผ ใ์ธ์ ๋ถํฐใ๊ฐ ์ฌ๊ธฐ์๋ ๊ฐ์ ๊ฐ์ ํ๋ค(ํ ๋ฒ์ ๋ฐ๋ฆผ๊ณผ ์ฌํ์งธ\n * ๋ชป ๋์ด๊ฐ๋ ๊ฒ์ ๋ค๋ฅด๋ค). ๋์ด๊ฐ๋ฉด ์ง์ด๋ค.\n */\n /**\n * **์๋ณธ์ด ๋งํ๋๋ฐ ํธ์์ ์ธ์ฐ์ง ์์ ๊ฒ** โ ์ด์ ๋ณ๋ก ์ผ๋ค.\n *\n * โโ ์ ์ด ์๋ฆฌ๊ฐ ํ์ํ๊ฐ (2026-08-24) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์ปค๋ฅํฐ๊ฐ ์๋ณธ์ ์ฌ์ค ์ผ๋ถ๋ฅผ **์ผ๋ถ๋ฌ ๋ฐ์ง ์๋ ์ผ์ด ์ ์์ด๋ค**: ์
์๊ฐ ๋ง์ง ์๊ฑฐ๋, ๋ฐ์ผ๋ฉด ์ํ๊ฐ\n * ๊ฑฐ์ง์ด ๋๊ฑฐ๋, ์ปค๋ ์ดํ๋ก ์ฎ๊ธธ ์ ์๋ค. ๊ทธ๋ ์ปค๋ฅํฐ๋ ๊ฒฝ๊ณ ๋ฅผ ๋ธ๋ค โ **๊ทธ๋ฐ๋ฐ ๊ทธ ๊ฒฝ๊ณ ๊ฐ ํ๋ก๋น์ ๋\n * ํ๋ฉด์์ ํ ๋ฒ ์ค์ณ ์ง๋๊ฐ ๋ฟ์ด์๋ค.** ๊ทธ ๋ค๋ก๋ ์ด๋์์๋ ๋ณผ ์ ์์๋ค.\n *\n * ๊ทธ๋์ ์ฌ์ฉ์๊ฐ ใ์๋ณธ๋ณด๋ค ๊ณํ์ด ์ ๋คใ๋ฅผ ๋ฌผ์ผ๋ฉด **๋ต์ด ์ด๋์๋ ์๋ค.** ๊ทธ ์ฌ์ค์ ํ ๋ฒ์\n * ์ฌ๊ฑด์ด ์๋๋ผ **์ํ์ ์ฑ์ง**์ด๋ค โ ์ธ์ฐ์ง ์์ ๊ฒ์ ์ง๊ธ๋ ํธ์์ ์๋ค.\n *\n * โโ `unhandled` ์ ํ์ ๋ค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * `unhandled` ๋ฆฌ๋์๊ฐ **๋ฐ์๋๋ฐ** ๋ด์ ์๋ฆฌ๋ฅผ ๋ชฐ๋๋ค\n * ์ฌ๊ธฐ ์ปค๋ฅํฐ๊ฐ **๋ณด์ง๋ง ์ผ๋ถ๋ฌ ๋ณด๋ด์ง ์์๋ค** โ ์ด์ ์ ํจ๊ป\n *\n * ๋ ๋ค ใ์ฌ์ค์ด ์ค๋ฅ ์์ด ์ฌ๋ผ์ง์ง ์๊ฒใ ์ธ๋ ๊ฒ์ด๊ณ , ์ด์ ๊ฐ ๋ค๋ฅด๋ฏ๋ก ์๋ฆฌ๋ ๋ค๋ฅด๋ค.\n *\n * ์ด์ ๋ฅผ **๋ฌธ์์ด๋ก ๋ฐ๋๋ค**: ๋ฌด์์ ์ ์ ๋ฐ๋์ง๋ ์๋ณธ๋ง๋ค ๋ค๋ฅด๊ณ , ๊ณ์ฝ์ด ๊ทธ ๋ชฉ๋ก์ ๋ซ์ผ๋ฉด ์ ์๋ณธ์\n * ๋ถ์ผ ๋๋ง๋ค ๊ณ์ฝ์ ๊ณ ์น๊ฒ ๋๋ค(ํ๋ฆ ์ด์ ์ ๊ฐ์ ๊ท์จ).\n */\n withheld?: { reason: string; count: number; lastAtMs: number }[]\n cursorStall?: {\n /** ์ฐ์ ์ ์ฒด ์ โ ๋์ด๊ฐ๋ฉด 0 ์ผ๋ก ๋์๊ฐ๋ค. */\n consecutive: number\n /** ์ด ์ ์ฒด๊ฐ **์ฒ์** ์์๋ ์๊ฐ(ms). */\n sinceMs: number\n /** ๋ง์ง๋ง ์ ์ฒด ์๊ฐ(ms). */\n lastAtMs: number\n /** ์ฌ์ โ ์ฌ๋์ด ์ฝ๋ ํ ์ค(์ด๋ ์๊ฐ์์ ๋งํ๋๊น์ง ์ด๋ํฐ๊ฐ ๋งํด ์ฃผ๋ฉด ์ข๋ค). */\n reason: string\n /** ์ด๋ ํ๋ฆ์ธ๊ฐ. ๋ฐ๋๊ฐ ๋์ ํ๋ ์๋ณธ๋ง๋ค ๋ค๋ฅด๋ฏ๋ก ์ด ์ด๋ฆ์ด ์กฐ์น์ ์ ๋ฐ์ด๋ค. */\n stream?: string\n }\n}\n\n/**\n * ์ฝ๊ธฐ ์คํจ๋ฅผ ์ฅ๋ถ์ ์ ๋๋ค โ **๋ฐ์ ๊ฒ์ด ์๋ ๊ฒ๊ณผ ๊ฐ๋ฅธ๋ค.**\n *\n * ์ฐ์ ์คํจ์ ์์ ์๊ฐ์ ์งํค๋ ๊ฒ์ด ์ด ํจ์์ ์์ ์ด๋ค: ๋งค๋ฒ ์๋ก ์ ์ผ๋ฉด ใ20๋ถ์งธ ๋ชป ์ฝ๋๋คใ๋ฅผ\n * ๋งํ ์ ์๊ณ , ํ๋ฉด์ ๋ ใ๋ฐฉ๊ธ ์คํจํ๋คใ๋ง ๋ณด๊ฒ ๋๋ค.\n */\nexport function recordReadFailure(\n ledger: IngestLedger,\n reason: string,\n nowMs: number,\n stream?: string,\n /**\n * ๋ค์์ ๋ค์ ๋ฌผ์ ๋๊น์ง ๋จ์ ์๊ฐ(ms) โ ์ปค๋ฅํฐ๊ฐ ๋ฌผ๋ฌ์ฐ์ผ๋ฉด ๊ทธ ๊ฐ์ ์ค๋ค (2026-08-27).\n *\n * ์ด๊ฒ์ด ์์ผ๋ฉด ํ๋ฉด์ด ใ๋ฟ์ง ๋ชปํ๊ณ ์๋คใ๊น์ง๋ง ๋งํ๊ณ , ์ฌ๋์ **์ธ์ ๋ค์ ์๋ํ๋์ง** ์ ์\n * ์๋ค. ๊ทธ๋ฌ๋ฉด ๊ธฐ๋ค๋ ค์ผ ํ๋์ง ์์ ์จ์ผ ํ๋์ง ํ๋จํ์ง ๋ชปํ๋ค.\n *\n * **์ฐ๋ฌ์ ํ์์ ์์ ์๊ฐ์ ์ปค๋ฅํฐ๊ฐ ๋ณด๋ด์ง ์๋๋ค** โ ์ด ํจ์๊ฐ ์ด๋ฏธ ์ผ๋ค. ๋ ๊ณณ์์ ์ธ๋ฉด\n * ๊ฐ๋ผ์ง๊ณ , ๊ฐ๋ผ์ง๋ฉด ์ด๋ ์ชฝ์ด ์ฌ์ค์ธ์ง ์ ์ ์๋ค.\n */\n nextRetryMs?: number\n): void {\n const prev = ledger.readFailure\n ledger.readFailure = {\n consecutive: (prev?.consecutive ?? 0) + 1,\n sinceMs: prev?.sinceMs ?? nowMs,\n lastAtMs: nowMs,\n reason,\n ...(stream ? { stream } : {}),\n ...(Number.isFinite(nextRetryMs) && (nextRetryMs as number) > 0 ? { nextRetryMs: nextRetryMs as number } : {})\n }\n}\n\n/**\n * **๋๊ฒผ๋ค๊ฐ ๋์์๋ค** โ ๊ทธ ์ฌ์ค์ ๋จ๊ธด๋ค (2026-08-27).\n *\n * ์คํจ ๊ธฐ๋ก๋ง ์ง์ฐ๋ฉด ใ๋๊ธด ์ ์ด ์์๋คใ๊ฐ ํ๋ฉด์์ ์ฌ๋ผ์ง๋ค. ๊ทธ๋ฌ๋ฉด ๋ฐค์ ๋ ์๊ฐ ๋๊ฒผ๋ ์ฐ๊ฒฐ๊ณผ ํ\n * ๋ฒ๋ ๋๊ธฐ์ง ์์ ์ฐ๊ฒฐ์ด ์์นจ์ ๋๊ฐ์ด ๋ณด์ธ๋ค. ๋ช ๋ฒ ์คํจํ ๋ค์ ๋์์๋์ง, ์ผ๋ง๋ ๋๊ฒผ๋์ง๋ฅผ ํจ๊ป\n * ๋จ๊ธด๋ค.\n */\nexport function recordRecovered(ledger: IngestLedger, afterFailures: number, downMs: number, nowMs: number): void {\n if (ledger.readFailure) delete ledger.readFailure\n ledger.lastRecovery = { atMs: nowMs, afterFailures, downMs }\n}\n\n/**\n * ์ฝ๊ธฐ๊ฐ ์ฑ๊ณตํ๋ค โ ๋จ์ ๊ธฐ๋ก์ ์ง์ด๋ค.\n *\n * **๋น ์ฝ๊ธฐ๋ ์ฑ๊ณต์ด๋ค**: ์๋ณธ์ด ใ์ ๊ฒ์ด ์๋คใ๊ณ ๋ตํ ๊ฒ์ ๋ฟ์๋ค๋ ๋ป์ด๋ค. ๊ทธ ๋์ ๊ฐ๊ฒ ๋๋ฉด\n * ๋ค์ด์จ ๊ฒ์ด ์๋ ์ฐ๊ฒฐ์ด ๋๊ธด ์๋ณธ์ผ๋ก ๋ณด์ธ๋ค(๊ณ ์น๋ ค๋ ๊ฒ์ ๋ฐ๋ ๋ฐฉํฅ์ผ๋ก ํ๋ฆฐ๋ค).\n */\nexport function clearReadFailure(ledger: IngestLedger): void {\n if (ledger.readFailure) delete ledger.readFailure\n}\n\n/**\n * ์ปค์ ์ ์ฒด๋ฅผ ์ฅ๋ถ์ ์ ๋๋ค โ **๋ฟ์ง ๋ชปํ ๊ฒ๊ณผ ๊ฐ๋ฅธ๋ค.**\n *\n * `recordReadFailure` ์ ๊ฐ์ ๋ชจ์์ด์ง๋ง **๋ค๋ฅธ ์นธ**์ด๋ค. ํ ์ฃผ๊ธฐ๊ฐ ๋ ์ด์ ๋ก ์คํจํ ์๋ ์์ผ๋ฏ๋ก\n * (๋จผ์ ๋ฟ์์ผ ์ฝ๋๋ค) ๋์ด ๋์์ ์์ง ์๋๋ค โ ๊ทธ๋์ ํ๋ฉด์ ๋ ์ค ํ๋๋ง ๋ณด๊ฒ ๋๊ณ , ๊ทธ ํ๋๊ฐ\n * ์กฐ์น๋ฅผ ์ ํ๋ค.\n */\nexport function recordCursorStall(ledger: IngestLedger, reason: string, nowMs: number, stream?: string): void {\n const prev = ledger.cursorStall\n ledger.cursorStall = {\n consecutive: (prev?.consecutive ?? 0) + 1,\n sinceMs: prev?.sinceMs ?? nowMs,\n lastAtMs: nowMs,\n reason,\n ...(stream ? { stream } : {})\n }\n}\n\n/**\n * **์ธ์ฐ์ง ์์ ๊ฒ์ ์ ๋๋ค** โ ์ด์ ๋ณ ๋์ .\n *\n * ์ฃผ๊ธฐ๋ง๋ค ๋ค์ ์๋ ค๋ ์๋๋ฌ์์ง์ง ์๊ฒ **์ด์ ๋ก ๋ฌถ์ด ์ผ๋ค**(์ค์ด ๋์ง ์๋๋ค). ๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง ์๊ฐ์\n * ํจ๊ป ๋ ๋ค โ ใ์ง๊ธ๋ ๊ทธ๋ฐ๊ฐใ์ ใํ๋ ๊ทธ๋ฌ๋ใ๋ ๋ค๋ฅธ ์ฌ์ค์ด๊ณ , ์๊ฐ ์์ด๋ ๊ตฌ๋ณํ ์ ์๋ค.\n *\n * ์ด์ ๊ฐ ๊ฐ๊ณ ์๊ฐ ๋ฌ๋ผ์ง๋ฉด **๋ง์ง๋ง ์๋ก ๋ฎ๋๋ค**: ์ด๊ฒ์ ๋์ ์ฌ๊ฑด์ด ์๋๋ผ **์ง๊ธ ์ธ์ฐ์ง ์์ ๊ฒ์\n * ์**๋ค. ์ฃผ๊ธฐ๋ง๋ค 8๊ฑด์ด๋ฉด 8์ด๊ณ , ๋ํด์ 800์ด ๋๋ฉด ๊ฑฐ์ง์ด๋ค.\n */\n/**\n * ์ด๋ค ๊ธธ๋ก ๋ช ๊ฑด์ด ๋ค์ด์๋ โ ๊ฒฝ๋ก ์ด๋ฆ์ ๋ถ๋ฅด๋ ์ชฝ์ด ์ ํ๋ค.\n *\n * ์ด๋ฆ์ ์์ ๋ฌธ์์ด๋ก ๋๋ ์ด์ : ๊ธธ์ด ๋์ด๋๋ค(์ง๊ธ์ ๋ฌผ์ด๋ณด๊ธฐยท์๋๋ฆฌ์คยท๋ถํ ๋๊ตฌ, ๋ค์์ ์นํ
).\n * ์ด๊ฑฐ๋ก ๋ชป ๋ฐ์ผ๋ฉด ์ ๊ธธ์ด ์๊ธธ ๋ ์ด ํ์ผ์ ํจ๊ป ๊ณ ์ณ์ผ ํ๊ณ , ์์ผ๋ฉด ๊ทธ ๊ธธ์ด ํต๊ณ์์ ์ฌ๋ผ์ง๋ค.\n */\nexport function recordIngestSource(ledger: IngestLedger, source: string, count: number, nowMs: number): void {\n const key = String(source ?? '').trim() || 'unknown'\n if (count <= 0) return\n const cur = (ledger.bySource[key] ??= { count: 0, lastAtMs: -1 })\n cur.count += count\n cur.lastAtMs = nowMs\n}\n\n/** ๊ฐ์ ์ฌ์ค์ด ๋ ๋ฒ ์์ ๋ฒ๋ฆฐ ์ โ ์๋ฆฌ์ง ์๊ณ ๋ฒ๋ฆฌ์ง ์๋๋ค. */\nexport function recordDuplicates(ledger: IngestLedger, count: number, nowMs: number): void {\n if (count <= 0) return\n ledger.duplicates += count\n ledger.lastDuplicateAtMs = nowMs\n}\n\nexport function recordWithheld(ledger: IngestLedger, reason: string, count: number, nowMs: number): void {\n if (!reason || !(count > 0)) return\n const list = (ledger.withheld ??= [])\n const at = list.find(w => w.reason === reason)\n if (at) {\n at.count = count\n at.lastAtMs = nowMs\n return\n }\n list.push({ reason, count, lastAtMs: nowMs })\n}\n\n/** ์ฐฝ์ ๋๊ฒผ์ผ๋ฉด ์ง์ด๋ค โ ํ๋ฆฐ ์ ์ฒด๊ฐ ํ๋ฉด์ ๋จ์ ์์ผ๋ฉด ๊ทธ๊ฒ๋ ๊ฑฐ์ง์ด๋ค. */\nexport function clearCursorStall(ledger: IngestLedger): void {\n if (ledger.cursorStall) delete ledger.cursorStall\n}\n\n/** ์ฐฝ ๊ธธ์ด โ 10๋ถ. ๋ถํ ๊ณ๊ธฐํ(10์ด)๊ณผ ๋ค๋ฅธ ๊ฐ์ด๋ผ ์ด๋ฆ์ ๋ฐ๋ก ๋๋ค(๊ฐ์ ์ด๋ฆ์ด๋ฉด ์์ธ๋ค). */\nexport const INGEST_WINDOW_MS = 600_000\n\n/**\n * ์ด๋งํผ ์๋ฌด๊ฒ๋ ์ค์ง ์์ผ๋ฉด ใ์ ์
์์ใ์ด๋ผ ๋งํ๋ค.\n *\n * ์ฐฝ ํ๋์ ๊ฐ๊ฒ ๋๋ค โ ํ ์ฐฝ์ ํต์งธ๋ก ๋น์ด ๊ฒ์ ์ค์ ๋ก ใ๊ทธ ๊ตฌ๊ฐ์ ์๋ฌด๊ฒ๋ ์ค์ง ์์๋คใ์ด๊ณ , ์ถ์ด์\n * ๊ทธ ์๋ฆฌ๋ ๋น๊ฒ ๋๋ค. ๊ทธ๋ฆผ๊ณผ ์์ฝ์ด ๊ฐ์ ๋ง์ ํ๊ฒ ํ๋ ค๋ฉด ๊ฐ์ ๊ธธ์ด์ฌ์ผ ํ๋ค.\n */\nexport const STALE_AFTER_MS = INGEST_WINDOW_MS\n\n/** ์ถ์ด ๋ณด๊ด ์ฐฝ ์ โ 36์ฐฝ ร 10๋ถ = 6์๊ฐ. ใ๊ณ ์น ๊ฒ์ด ๋จนํ๋ใ๋ฅผ ๋ณด๊ธฐ์ ์ถฉ๋ถํ๊ณ ๋ฉ๋ชจ๋ฆฌ๋ ์ซ์ ๋ทร36 ์ด๋ค. */\nexport const TREND_LIMIT = 36\n\n/**\n * ์ฌ์ ์ข
๋ฅ ์ํ.\n *\n * **์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋์์ด ์๋๋ค.** ์ฌ์ ๋ฌธ๊ตฌ์ ๋ ์ฝ๋๋ง๋ค ๋ค๋ฅธ ๊ฐ์ด ์์ด๋ ์ปค๋ฅํฐ๊ฐ ํ๋๋ง ์์ด๋\n * (`unknown bizStep \"PUTAWAY_X17\"`, `โฆX18`, โฆ) ํค๊ฐ ๋ฌดํํ ๋์ด๋๋ค. ์ด๋น 1๋ง ๊ฑด ๊ท๋ชจ์์ ์ด๊ฒ์\n * ๋ฏธ๋ฏธํ ์ค๋ฒํค๋๊ฐ ์๋๋ผ ๋์๋ค.\n *\n * ๋์น๋ฉด `OTHER_REASON` ํ ์นธ์ ๋ชจ์ผ๊ณ **๋ช ์ข
์ ๋ชจ์๋์ง ํจ๊ป ๋ธ๋ค**(์๋ฆฌ์ง ์๊ณ ์๋ฅด์ง ์๋๋ค).\n * 30์ข
์ด๋ฉด ๊ณ ์น ๊ณณ์ ์ฐพ๊ธฐ์ ์ถฉ๋ถํ๋ค โ ๋ชฉ๋ก์ ํ๋ ์ผ์ด ์๋๋ผ ๋งคํ ๋ช ์ค์ ๊ณ ์น๋ ์ผ์ด๋ค.\n */\nexport const REASON_LIMIT = 30\n\n/** ์ํ์ ๋๊ธด ์ฌ์ ๋ค์ด ๋ชจ์ด๋ ์นธ. */\nexport const OTHER_REASON = '(other reasons)'\n\n/**\n * ํ๋ณธ ์ํ โ **์ฌ์ ๋ง๋ค ํ ๊ฑด**๋ง ๋ ๋ค.\n *\n * ๊ฐ์ ์ฌ์ 20๊ฑด๋ณด๋ค **์๋ก ๋ค๋ฅธ ์ฌ์ 1๊ฑด์ฉ**์ด ๋งคํ์ ๊ณ ์น๋ ๋ฐ ์ ์ฉํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ๊ท์น์ด ์ฑ๋ฅ์\n * ์งํจ๋ค: ๊ทธ ์ฌ์ ์ ํ๋ณธ์ด ์ด๋ฏธ ์์ผ๋ฉด `JSON.stringify` ๋ฅผ **์์ ํ์ง ์๋๋ค.** ์ค์ธก(๋ ์ฝ๋ 241๋ฐ์ดํธ)\n * ์ผ๋ก ๊ฑด๋น 0.24ยตs ์ธ๋ฐ, ์ด๋น 1๋ง ๊ฑด์ด ์ ๋ถ ๊ฑฐ๋ถ๋๋ฉด 9,980๊ฑด์ ๋ง๋ค์๋ง์ ๋ฒ๋ ค์ง๋ ๋ฌธ์์ด์ด์๋ค โ\n * CPU ๋ ๊ฐ๋น๋์ง๋ง GC ์๋ฐ์ด ์ด๋ฒคํธ ๋ฃจํ๋ก ๋์์จ๋ค.\n */\nexport const SAMPLE_LIMIT = REASON_LIMIT\n\n/** ํ๋ณธ ํ๋์ ์ง๋ ฌํ ์ํ(๋ฌธ์). */\nexport const RECORD_MAX = 2000\n\n/**\n * ๋งคํ์ด ๋ง๊ณ ์๋ค๊ณ ๋ณผ ํต๊ณผ์จ ๋ฌธํฑ.\n *\n * ๊ฐ๊ณผ ํจ๊ป ๋ด๋ณด๋ธ๋ค โ ํ๋ฉด์ด ใ95% ๋ฏธ๋ง์ด๋ผ ๋งคํ ๋ฌธ์ ๋ก ๋ดค๋คใ๋ฅผ ๋งํ ์ ์๊ฒ. ์จ๊ธด ๋ฌธํฑ์ ์ฌ๋์ด\n * ํ์ ์ ๋ฏฟ์ง ๋ชปํ๋ค.\n */\nexport const HEALTHY_ACCEPTED_RATIO = 0.95\n\nexport function newIngestLedger(): IngestLedger {\n return {\n window: { startMs: -1, endMs: -1, offered: 0, rejected: 0, undelivered: 0, rows: 0, flushes: 0 },\n trend: [],\n trendDropped: 0,\n offered: 0,\n rejected: 0,\n undelivered: 0,\n rows: 0,\n flushes: 0,\n lastWriteAtMs: -1,\n lastUndeliveredAtMs: -1,\n bySource: {},\n duplicates: 0,\n lastDuplicateAtMs: -1,\n byReason: {},\n reasonsCapped: false,\n sampledReasons: new Set<string>(),\n samples: [],\n sampleDropped: 0,\n lastAtMs: -1\n }\n}\n\n/**\n * ์ฐฝ์ด ๋ค ์ฐผ์ผ๋ฉด ๋ซ์ ์ถ์ด์ ๋ฃ๊ณ ์๋ก ์ฐ๋ค. **๋ซํ ์ฐฝ๋ง ใ์ต๊ทผใ์ผ๋ก ์ฝ๋๋ค.**\n *\n * โโ ์์์ด ๋ถ๋ ์ ์ผํ ์๋ฆฌ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ๋ซํ ์ฐฝ ํ๋๊ฐ ์์์ ๋จ์๋ค(์ซ์ ๋ท + ๊ตฌ๊ฐ). `onClosed` ๋ฅผ ๋ฐ๋ ์ด์ ๋ **์ด ํจ์๊ฐ ์ฐฝ์ด ๋ซํ๋\n * ์ ์ผํ ์ง์ **์ด๊ธฐ ๋๋ฌธ์ด๋ค โ ์ฌ๊ธฐ ํ ๊ณณ์ ๋ถ์ด๋ฉด ๊ธฐ๋ก ๊ฒฝ๋ก๊ฐ ๊ฐ๋ฆฌ์ง ์๋๋ค.\n *\n * ์ ๊ฑด๋ง๋ค๊ฐ ์๋๋ผ ์ฐฝ๋ง๋ค์ธ๊ฐ: ๊ฑฐ๋ถ๋ง๋ค ํ์ ์ฐ๋ฉด ์ด๋น 1๋ง ํ์ด๊ณ ๊ทธ ๋ถํ๊ฐ ์ด๋ฒคํธ ๋ฃจํ๋ก ๋์์จ๋ค.\n * ์ฐฝ๋ง๋ค๋ฉด ํธ์ 1,000๊ฐ์ ํ๋ฃจ 14.4๋ง ํ(์ฝ 14MB)์ด๋ค.\n *\n * `onClosed` ๋ **์ค๋ฅ๋ฅผ ๋ด์ง ์์์ผ ํ๋ค**(ํธ์ถ๋ถ๊ฐ ๊ฐ์ผ๋ค) โ ์์์ด ์คํจํด๋ ์ฅ๋ถ๋ ๊ณ์ ๊ตด๋ฌ์ผ ํ๋ค.\n * ์์์ ์งํค๋ ๊ฒ๊ณผ ๊ด์ธก์ ์งํค๋ ๊ฒ์ ๋ค๋ฅธ ์ผ์ด๊ณ , ๋ค์ฃ๊ฒ์ด ์์ฃ๊ฒ ๋๋ฌธ์ ๋ฉ์ถ๋ฉด ์ ๋๋ค.\n */\nexport function rollIngestWindow(\n ledger: IngestLedger,\n nowMs: number,\n windowMs = INGEST_WINDOW_MS,\n onClosed?: (closed: IngestWindow) => void\n): void {\n if (ledger.window.startMs < 0) {\n ledger.window.startMs = nowMs\n return\n }\n if (nowMs - ledger.window.startMs < windowMs) return\n\n const closed: IngestWindow = { ...ledger.window, endMs: nowMs }\n ledger.trend.push(closed)\n ledger.window = { startMs: nowMs, endMs: -1, offered: 0, rejected: 0, undelivered: 0, rows: 0, flushes: 0 }\n\n if (ledger.trend.length > TREND_LIMIT) {\n const drop = ledger.trend.length - TREND_LIMIT\n ledger.trend.splice(0, drop)\n ledger.trendDropped += drop\n }\n\n /* ์์์ ๊ด์ธก์ ๋ง์ง ์๋๋ค โ ํฐ์ ธ๋ ์ฅ๋ถ๋ ์ด๋ฏธ ๊ฐฑ์ ๋๋ค. */\n if (onClosed) {\n try {\n onClosed(closed)\n } catch {\n /* ํธ์ถ๋ถ๊ฐ ์๋ฆฐ๋ค. ์ฌ๊ธฐ์ ์ผํค๋ ๊ฒ์ **์ฅ๋ถ์ ์งํ**์ ์งํค๊ธฐ ์ํด์๋ค. */\n }\n }\n}\n\n/** ์ฌ์ ๋ฌถ์์ ํค. ์ฌ์ ๊ฐ ์ฌ๋ฟ์ด๋ฉด ํ ์ค๋ก ์๊ณ , ์์ผ๋ฉด ์ง์ด๋ด์ง ์๊ณ `unknown`. */\nexport function reasonKey(errors: string[] | undefined): string {\n const list = (errors ?? []).map(e => String(e).trim()).filter(Boolean)\n return list.length ? list.join(' ยท ') : 'unknown'\n}\n\nfunction safeJson(v: unknown): string {\n try {\n const s = JSON.stringify(v)\n return s === undefined ? String(v) : s\n } catch {\n return '(serialization failed)' /* ์ํ ์ฐธ์กฐ ๋ฑ โ ๋ชจ์์ ๋ชป ๋ณด์ฌ ์ฃผ๋ ๊ฒ๋ ์ฌ์ค์ด๋ค */\n }\n}\n\n/**\n * ํ ๋ฒ์ ์ธ์ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ์ ๋๋ค.\n *\n * `offered` ๋ฅผ ํจ๊ป ๋ฐ๋ ์ด์ : ํต๊ณผ์จ์ **์๋ก ๋ค๋ฅธ ๋ ๊ณ์๊ธฐ**์์ ๋๋ ๊ณ์ฐํ๋ฉด ๋ถ๋ชจ์ ๋ถ์๊ฐ ๋ค๋ฅธ\n * ๊ฒ์ ์ธ๊ฒ ๋๋ค. ๋์ ํ์๋ฆฌ์์ ๋ณธ ์๋ฅผ ๊ทธ๋๋ก ์ ๋๋ค.\n */\nexport function recordIngest(\n ledger: IngestLedger,\n offered: number,\n rejected: { record?: unknown; errors?: string[] }[] | undefined,\n nowMs: number,\n onClosed?: (closed: IngestWindow) => void,\n /** ๋งคํ์ ํต๊ณผํ์ง๋ง ํธ์์ ๋ฟ์ง ๋ชปํ ์ โ ใํต๊ณผใ๋ก ์ธ๋ฉด ํ๋ฉด์ด ๊ฑฐ์ง์ ๋งํ๋ค. */\n undelivered = 0\n): void {\n if (!Number.isFinite(offered) || offered < 0) return\n\n rollIngestWindow(ledger, nowMs, INGEST_WINDOW_MS, onClosed)\n\n ledger.offered += offered\n ledger.window.offered += offered\n ledger.lastAtMs = nowMs\n\n if (Number.isFinite(undelivered) && undelivered > 0) {\n ledger.undelivered += undelivered\n ledger.window.undelivered += undelivered\n ledger.lastUndeliveredAtMs = nowMs\n }\n\n const items = rejected ?? []\n if (!items.length) return\n\n ledger.rejected += items.length\n ledger.window.rejected += items.length\n\n for (const it of items) {\n const raw = reasonKey(it?.errors)\n const known = raw in ledger.byReason\n\n /* ์ฌ์ ์ข
๋ฅ ์ํ โ ๋์น๋ฉด ํ ์นธ์ผ๋ก ๋ชจ์ผ๊ณ , **๋ฟ์๋ค๋ ์ฌ์ค**์ ํ์ํ๋ค. */\n let key = raw\n if (!known && Object.keys(ledger.byReason).length >= REASON_LIMIT) {\n key = OTHER_REASON\n ledger.reasonsCapped = true\n }\n\n const seen = ledger.byReason[key]\n ledger.byReason[key] = { count: (seen?.count ?? 0) + 1, lastAtMs: nowMs }\n\n /*\n * **ํ๋ณธ์ ์ฌ์ ๋ง๋ค ํ๋.** ์ด๋ฏธ ๊ทธ ์ฌ์ ์ ํ๋ณธ์ด ์์ผ๋ฉด ์ง๋ ฌํ๋ฅผ ์์ ํ์ง ์๋๋ค โ ์ด๋น 1๋ง ๊ฑด์ด\n * ์ ๋ถ ๊ฑฐ๋ถ๋ ๋ ๋ง๋ค์๋ง์ ๋ฒ๋ ค์ง๋ ๋ฌธ์์ด์ ๋ง๋ค์ง ์๊ธฐ ์ํด์๋ค(์ค์ธก: ๊ฑด๋น 0.24ยตs, GC ์๋ฐ).\n */\n if (ledger.sampledReasons.has(key)) {\n ledger.sampleDropped += 1\n continue\n }\n\n const text = safeJson(it?.record)\n const truncated = text.length > RECORD_MAX\n ledger.samples.push({\n atMs: nowMs,\n errors: key === OTHER_REASON ? [OTHER_REASON] : it?.errors?.length ? [...it.errors] : ['unknown'],\n record: truncated ? text.slice(0, RECORD_MAX) : text,\n ...(truncated ? { recordTruncated: true } : {})\n })\n\n ledger.sampledReasons.add(key)\n\n if (ledger.samples.length > SAMPLE_LIMIT) {\n const gone = ledger.samples.splice(0, ledger.samples.length - SAMPLE_LIMIT)\n /* ๋ฐ๋ ค๋ ํ๋ณธ์ ์ฌ์ ๋ ์์ธ์์๋ ๋นผ์ผ ๋ค์์ ๋ค์ ๋ฐ ์ ์๋ค(์ ๋นผ๋ฉด ๊ทธ ์ฌ์ ๋ ์์ํ ํ๋ณธ ์์). */\n for (const g of gone) ledger.sampledReasons.delete(reasonKey(g.errors))\n ledger.sampleDropped += gone.length\n }\n }\n}\n\n/**\n * ์ ๋์ **์ ์ ๊ฒ**์ ๊ธฐ๋กํ๋ค โ ์ฐฝ์ ๋๊ธธ ๋๊ฐ ๋์์ผ๋ฉด ๋๊ธฐ๊ณ , ํยท์๋ณต์ ๋ํ๋ค.\n *\n * โโ ์ ์ ์
๊ณผ ๊ฐ์ ์ฐฝ์ธ๊ฐ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์ ์ฅ๋ถ๋ฅผ ๋ง๋ค์ง ์๋๋ค. ์ด ์ฐฝ์ ใ๋ซํ ์ฐฝ๋ง ์ต๊ทผใยทใ0 ๊ณผ ์์์ ๊ฐ๋ฅธ๋คใยทใ์๋ฆฐ ๊ฒ์ ์ธ์ด ๋๋ฌ๋ธ๋คใ๋ฅผ\n * ์ด๋ฏธ ์งํค๊ณ , ๋ซํ ๋ ์์๊น์ง ๋๋ค. ๊ฐ์ ๊ท์จ์ ๋ ๋ฒ ๋ง๋ค๋ฉด ํ์ชฝ๋ง ๊ณ ์ณ์ง๋ค.\n *\n * โโ ์ ์
์ด ์์ด๋ ์ฐฝ์ ๋์ด๊ฐ๋ค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์๋ฎฌ ํธ์์ ๋ฐ๋ ๊ฒ ์์ด ์๊ธฐ๊ฐ ๋ธ ์ฌ์ค์ ์ ๋๋ค. ์ฐฝ์ด **์ ์
์์๋ง** ๋์ด๊ฐ๋ค๋ฉด ๊ทธ ํธ์์ ์ถ์ด์\n * ์์ํ ๋ํ๋์ง ์๋๋ค โ ๊ทธ๋์ ์ฐ๊ธฐ๋ ์ฐฝ์ ๋๊ธด๋ค.\n */\nexport function recordJournalWrite(\n ledger: IngestLedger,\n rows: number,\n nowMs: number,\n onClosed?: (closed: IngestWindow) => void\n): void {\n if (!Number.isFinite(rows) || rows <= 0) return\n rollIngestWindow(ledger, nowMs, INGEST_WINDOW_MS, onClosed)\n ledger.rows += rows\n ledger.flushes += 1\n ledger.window.rows += rows\n ledger.window.flushes += 1\n /*\n * **`lastAtMs` ๋ ๊ฑด๋๋ฆฌ์ง ์๋๋ค.** ๊ทธ ๊ฐ์ ใ๋ง์ง๋ง ์ ์
ใ์ด๊ณ , ๋๊ธด ํผ๋๋ฅผ ๊ฐ๋ ค๋ด๋ ๊ทผ๊ฑฐ๋ค. ์ฐ๊ธฐ๋ก\n * ๊ฐฑ์ ํ๋ฉด ๋ผ์ด๋ธ ํธ์์ ์ ์
์ด ๋๊ฒจ๋ ํฑ์ด ๋ง๋ ๋ธํ๋ฅผ ๊ณ์ ์ ์ผ๋ฏ๋ก **์์ํ ใ๋ฐฉ๊ธ ๋ฐ์๋คใ**๊ฐ ๋๊ณ ,\n * ใ์ค๋ ๋๊ธด ํผ๋์ ์ ์ฐฝ์ผ๋ก ์ด๋ก์ ๋ด์ง ์๋๋คใ๊ฐ ์ค๋ฅ ํ๋ ์์ด ๋ฌด๋ ฅํด์ง๋ค. ์ถ์ ๋ฐ๋ก ๋ ๋ค.\n */\n ledger.lastWriteAtMs = nowMs\n}\n\n/**\n * ํ๋ ํ์ .\n *\n * `not-applicable` ๊ณผ `not-connected` ๋ฅผ ์์ง ์๊ณ , ์ฌ์ง ์์ ๊ฒ์ ์ ์ยท๋น์ ์์ผ๋ก ์ฑ์ฐ์ง ์๋๋ค\n * (`unknown`). ์๋ฎฌ ํธ์์ ใ๋๊ธฐํ ์ ๋จใ์ด๋ผ ๋งํ๋ฉด ๊ฑฐ์ง ๊ฒฝ๋ณด์ด๊ณ , **๊ฑฐ์ง ๊ฒฝ๋ณด๋ ์ฐธ ๊ฒฝ๋ณด๋ฅผ ์ฃฝ์ธ๋ค.**\n */\nexport type SyncVerdict =\n | 'syncing' /** ์ ์
์ด ์๊ณ ํต๊ณผ์จ์ด ๋ฌธํฑ ์ด์ */\n | 'mapping-blocked' /** ์ ์
์ ์๋๋ฐ ๊ฑฐ๋ถ๊ฐ ๋ฌธํฑ์ ๋๋๋ค โ ์ฌ์ ๋ฅผ ๋ณด๊ณ ๋งคํ์ ๊ณ ์น๋ค */\n /**\n * ๋ค์ด์ค๋๋ฐ **์ปค๋์ด ๋ฐ์ง ์๋๋ค** โ ์ฌ์ค์ด ์ฌ๋ผ์ง๊ณ ์๋ค.\n *\n * โโ ์ด๋ฆ์ด ์ฌ์ค๋ณด๋ค ์ข๋ค (2026-08-20์ ๋๋ฌ๋ฌ๋ค) โโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ๊ด์ธกํ ๊ฒ์ ใ์ปค๋์ด ๋ฐ์ง ์์๋คใ(`ingestLive` ๊ฐ 0)์ด๊ณ , **๋ฉ์ถ ๊ฒ์ ๊ทธ ์์ธ ์ค ํ๋์ผ ๋ฟ**์ด๋ค.\n * ๋ค๋ฅธ ์์ธ์ด ์ค์ ๋ก ์์๋ค: ๋ฏธ๋ฌ๋ก ์ ์ธ๋ ํธ์์ ์ฌ๋์ด ํ๋ฉด์์ ์์ํ๋ฉด ์๋ฎฌ ๊ตฌ๋์ผ๋ก ๋ด๊ณ , ๊ทธ\n * ํธ์์ **๋๊ณ ์์ผ๋ฉด์** ์ ์
์ ํ ๊ฑด๋ ๋ฐ์ง ๋ชปํ๋ค. ๊ทธ๋ ํ๋ฉด์ ํ์ชฝ์ ใrunningใ, ๋ค๋ฅธ ์ชฝ์\n * ใ๋ฉ์ถฐใ๋ผ๊ณ ์ ์๊ณ ์ฌ๋์ ใ์์ ๋ฒํผ์ ๋๋ฅด๋ฉด ๋๊ฒ ๋คใ๋ผ๋ ์๋ฑํ ์ฒ๋ฐฉ์ผ๋ก ๊ฐ๋ค.\n *\n * ๊ทธ๋์ **ํ๋ฉด ๋ฌธ๊ตฌ๋ ๊ด์ธก ๊ทธ๋๋ก** ์ ๋๋ค(ใํธ์์ ๋ฟ์ง ์๊ณ ๋ฒ๋ ค์ง๋ ์คใ). ์ด ํค ์ด๋ฆ์ ์๋ฒยทํ๋ฉดยท\n * ์ํ์ ๊ฑธ์น ๊ณ์ฝ ๋ฌธ์์ด์ด๋ผ ๊ทธ๋๋ก ๋์ง๋ง, ์ด๋ฆ์ ์์ธ์ผ๋ก ์ฝ์ง ์๋๋ค.\n */\n | 'twin-not-running'\n | 'no-traffic' /** ํผ๋๋ ๋ถ์๋๋ฐ ์ ์๊ฐ 0 โ ์์ฒยท๋ง์ ๋ณธ๋ค */\n | 'not-connected' /** ํผ๋ ์์ฒด๊ฐ ์๋ค โ ๊ฒฐ์ ํ๋ค */\n | 'not-applicable' /** ์๋ณธ์ด ๋จน์ด์ง ์๋ ํธ์(์๋ฎฌ)ยท๋ฉ์ถ ํธ์ โ ๋ฌผ์ ๋์์ด ์๋๋ค */\n | 'unknown' /** ํ ๋ฒ๋ ๋ฐ์ง ์์๊ฑฐ๋ ์ฐฝ์ด ์์ง ๋ซํ์ง ์์๋ค โ ๊ธฐ๋ค๋ฆฐ๋ค */\n\nexport function syncVerdictOf(args: {\n /** `live-feed-registry.liveFeedStateOf` ์ ๋ต์ ๊ทธ๋๋ก ๋ฐ๋๋ค โ ํ์ ์ดํ๋ฅผ ๋ ๋ฒ ๋ง๋ค์ง ์๋๋ค. */\n feedState: 'attached' | 'detached' | 'not-applicable'\n /** ๋ง์ง๋ง์ผ๋ก **๋ซํ** ์ฐฝ. ์์ผ๋ฉด `null`. */\n recent: { offered: number; rejected: number } | null\n /** ๋ง์ง๋ง์ผ๋ก ๋ฌด์์ด๋ ๋ฐ์ ์๊ฐ. ํ ๋ฒ๋ ์์ผ๋ฉด `-1` โ 0 ์ด ์๋๋ค(0 ์ 1970๋
์ด๋ค). */\n lastAtMs?: number\n /** ์ง๊ธ. `lastAtMs` ๋ฅผ ๊ฒฌ์ค ๋๋ง ์ด๋ค. */\n nowMs?: number\n /** ๋ง์ง๋ง์ผ๋ก **๋ฒ๋ ค์ง** ์๊ฐ. ํ ๋ฒ๋ ์์ผ๋ฉด `-1`. */\n lastUndeliveredAtMs?: number\n /**\n * ์ง๊ธ๊น์ง ์ ์๋ ๋์ ์ โ **ใ๋ฐ๊ณ ์๋ ์คใ๊ณผ ใ์ค๋ ๊ฒ์ด ์๋คใ๋ฅผ ๊ฐ๋ฅด๋ ์ฌ์ค**์ด๋ค.\n *\n * ๋ฟ์ ์๊ฐ(`lastAtMs`)์ผ๋ก๋ ๊ฐ๋ฅผ ์ ์๋ค: ๋น ์ฝ๊ธฐ๋ ๋ฟ์ ๊ฒ์ด๋ฏ๋ก ๊ทธ ์๊ฐ์ด ์ ๋ค. ์ฐฝ์ด ์์ง ๋ซํ์ง\n * ์์์ ๋ ์ด ์๊ฐ 0 ์ด๋ฉด ์ค๋ ๊ฒ์ด ์๋ ๊ฒ์ด๊ณ , 0 ์ด ์๋๋ฉด ๋ฐ๊ณ ์๋ ์ค์ด๋ค.\n */\n offeredTotal?: number\n threshold?: number\n}): SyncVerdict {\n /*\n * โโ ๋ฒ๋ ค์ง๊ณ ์๋ ๊ฒ์ด ๊ฐ์ฅ ๋จผ์ ๋ค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ํธ์์ด ๋ฉ์ถ๋ฉด ํผ๋๋ ๋จ์ ๊ณ์ ๋ ์ฝ๋๋ฅผ ๋๋ฅด๊ณ , ์ปค๋์ ๊ทธ๊ฒ์ ์๋ฆฌ์ง ์๊ณ ๋ฒ๋ฆฐ๋ค. ๊ทธ ์ํ๋ฅผ ใํด๋น ์์ใ\n * ์ด๋ผ ๋ถ๋ฅด๋ฉด **์ฌ์ค์ด ์ฌ๋ผ์ง๋ ๋์ ํ๋ฉด์ด ์์ฌ์ํจ๋ค** โ ์ค์ ๋ก ๊ทธ๋ ๊ฒ ๋ด๋ค(๋ฉ์ถ ํธ์ ์์ ใ150\n * ํต๊ณผ ยท 100%ใ). ๊ทธ๋์ ์๋ฎฌยท๋ฉ์ถค ํ์ ๋ณด๋ค ๋จผ์ ๋ณธ๋ค.\n *\n * ์๋ฎฌ ํธ์์๋ ์ด ๊ฐ์ด ์์ง ์๋๋ค(๋จน์ด๋ ํผ๋๊ฐ ์์ผ๋ฏ๋ก ๋ฏธ์ ๋ฌ๋ ์๋ค). ๊ทธ๋์ ์ด ์์๊ฐ ์๋ฎฌ์\n * ๊ฑฐ์ง ๊ฒฝ๋ณด๋ฅผ ์ฃผ์ง ์๋๋ค.\n */\n if (\n typeof args.lastUndeliveredAtMs === 'number' &&\n args.lastUndeliveredAtMs >= 0 &&\n typeof args.nowMs === 'number' &&\n args.nowMs - args.lastUndeliveredAtMs <= STALE_AFTER_MS\n ) {\n return 'twin-not-running'\n }\n\n if (args.feedState === 'not-applicable') return 'not-applicable'\n if (args.feedState === 'detached') return 'not-connected'\n\n /*\n * โโ ๋๊ธด ํผ๋๊ฐ ์ด๋ก์ผ๋ก ๋จ์ง ์๊ฒ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * ์ฐฝ์ **๋ค์ ์ ์
์ด ์์ ๋** ๋ซํ๋ค. ๊ทธ๋์ ์ ์
์ด ๋ฉ์ถ๋ฉด ์ฐฝ๋ ๋ฉ์ถ๊ณ , ใ์ต๊ทผ ์ฐฝใ์ ๋ฉ์ถ๊ธฐ ์ง์ ์\n * ๊ฑด๊ฐํ๋ ์ฐฝ์ผ๋ก ๋จ๋๋ค. ๊ทธ ์ฐฝ๋ง ๋ณด๊ณ ํ์ ํ๋ฉด **์ด์ ์ฃฝ์ ํผ๋๊ฐ ์ค๋๋ ใ๋๊ธฐํ ์คใ**์ด๋ค. ์ด\n * ๊ธฐ๋ฅ์ด ์๋ ์ด์ ๊ฐ ๋ฐ๋ก ๊ทธ ์ํ๋ฅผ ๋๋ฌ๋ด๋ ๊ฒ์ด๋ฏ๋ก, ๊ทธ๋ ์ด๋ก์ ๋ด๋ฉด ๋ชฉ์ ์ ๋์น๋ค.\n *\n * ๊ทธ๋์ ์ฐฝ๊ณผ ๋ณ๊ฐ๋ก **์ง๊ธ๊น์ง์ ์นจ๋ฌต**์ ๋จผ์ ๋ณธ๋ค. ํ ์ฐฝ์ ํต์งธ๋ก ์๋ฌด๊ฒ๋ ๋ฐ์ง ์์์ผ๋ฉด ๊ทธ๊ฒ์\n * ใ์ ์
์์ใ์ด๋ค โ ์ค์ ๋ก ๊ทธ ๊ตฌ๊ฐ์ ์ฐฝ์ ๋น์ด ์๊ฒ ๋๋ค.\n *\n * ์ด ํ๋จ์ ์๋ฒ์ ๋๋ ์ด์ : ์๋น์ฒ๊ฐ ์ฌ๋ฟ(๋ชฉ๋กยท์ฐ๊ฒฐ ์์ธยท์์ผ๋ก ์๊ธธ ๊ฒ)์ด๊ณ , ํ๋ฉด๋ง๋ค ๋ค์\n * ํ๋จํ๋ฉด ๊ท์น์ด ๊ฐ๋ผ์ ธ ์ด๋ค ํ๋ฉด์ ์ด๋ก, ์ด๋ค ํ๋ฉด์ ๊ฒฝ๊ณ ๋ฅผ ๋งํ๋ค.\n *\n * ํ๊ณ โ ํ ์ฐฝ(10๋ถ)๋ณด๋ค **๋๋ฆฌ๊ฒ ๊ธท๋ ์์ฒ**์ ๊ธท๋ ์ฌ์ด์ ใ์ ์
์์ใ์ผ๋ก ๋ณด์ธ๋ค. ์ฅ๋ถ๋ ์์ฒ์\n * ์ฃผ๊ธฐ๋ฅผ ๋ชจ๋ฅด๋ฏ๋ก ์ด๋ณด๋ค ์ ํํ ๋ตํ ์ ์๋ค. ์ฃผ๊ธฐ๋ฅผ ์๊ฒ ๋๋ฉด ๊ทธ ๊ฐ์ผ๋ก ๊ฒฌ์ฃผ๋ ๊ฒ์ด ๋ง๋ค.\n */\n if (typeof args.lastAtMs === 'number' && typeof args.nowMs === 'number') {\n if (args.lastAtMs < 0) return 'unknown' /* ๋ถ์์ง๋ง ํ ๋ฒ๋ ๋ฐ์ง ์์๋ค โ ๊ธฐ๋ค๋ฆฐ๋ค */\n if (args.nowMs - args.lastAtMs > STALE_AFTER_MS) return 'no-traffic'\n }\n\n /*\n * โโ **๋ฟ์๋๋ฐ ์ค๋ ๊ฒ์ด ์๋ค** ๋ฅผ ใ๋ชจ๋ฅธ๋คใ๋ก ๋ตํ์ง ์๋๋ค (2026-08-28) โโโโ\n *\n * ์ฐฝ์ **๋ค์ ์ ์
์ด ์์ ๋** ๋ซํ๋ค. ๊ทธ๋์ ์ค๋ ๊ฒ์ด ํ๋๋ ์๋ ํธ์์ ์ฐฝ์ด ์์ํ ๋ซํ์ง ์๊ณ ,\n * ์ด ์๋ฆฌ๊ฐ `unknown` ์ ๋๋ค โ ๋ถ์ด ์๊ณ 37์ด๋ง๋ค ์ฑ๊ณต์ ์ผ๋ก ์ฝ๋ ํธ์์ด ํ๋ฉด์์ ใ๋ชจ๋ฅธ๋คใ์๋ค.\n *\n * ๊ทธ๊ฒ์ด ๋๋ฌ๋ ๊ณ๊ธฐ: ์ปค๋ฅํฐ๊ฐ ์ฌ๊ธฐ๋๋ง๋ค ์ฌ๊ณ 2,665๊ฑด์ ๋ค์ ๋งํ๋ ๊ฒ์ ์์ด๋ค. ๊ทธ๋ฌ์ ์ ์ ์ํ์\n * ์ ์
์ด 0 ์ด ๋์๊ณ , **๊ฑด๊ฐ ์ ํธ๊ฐ ๊ทธ ์์์ ํ๊ณ ์์๋ค**๋ ๊ฒ์ด ๋ณด์๋ค.\n *\n * โโ ๊ฐ๋ฅด๋ ์ฌ์ค์ **๋ฐ์ ๊ฒ์ด ์๋**๋ค (์ฒซ ํ์ ๊ณ ์นจ) โโโโโโโโโโโโโโโโโโโโโ\n * ์ฒ์์๋ ๋ฟ์ ์๊ฐ์ผ๋ก ๊ฐ๋๋ค. ๊ทธ๊ฒ์ด ํ๋ ธ๋ค โ **๋น ์ฝ๊ธฐ๋ ๋ฟ์ ๊ฒ**์ด๋ผ ๊ทธ ์๊ฐ์ ์ธ์ ๋ ์ ๋ค.\n * ๊ทธ๋์ ์ฐฝ์ ์ฑ์ฐ๋ ์ค์ธ ํธ์(์ ์ 200๊ฑด)๊น์ง ใ์ค๋ ๊ฒ์ด ์๋คใ๋ก ๋ตํ๊ฒ ๋๊ณ , ์ํ์ด ๊ทธ๊ฒ์ ์ก์๋ค.\n * ๋ฐ๊ณ ์๋ ์ค์ธ๋ฐ ์ค๋ ๊ฒ์ด ์๋ค๊ณ ๋งํ๋ ๊ฒ์ **์๋ ๊ฒ๊ณผ ๋ชป ๋ณธ ๊ฒ์ ๋ค์ง๋ ๊ฒ**์ด๋ค.\n *\n * ๋ฟ์๊ณ ยท ์ ์๊ฐ 0 ์ค๋ ๊ฒ์ด ์๋ค `no-traffic`\n * ๋ฟ์๊ณ ยท ์ ์๊ฐ ์๋ค ๋ฐ๋ ์ค์ด๊ณ ํ์ ํ ์ฐฝ์ด ์์ง ์๋ค `unknown`\n * ํ ๋ฒ๋ ๋ฟ์ง ์์๋ค `unknown`(์ `lastAtMs < 0` ๊ฐ๋)\n */\n if (!args.recent) {\n const touched = typeof args.lastAtMs === 'number' && args.lastAtMs >= 0\n const nothingOffered = (args.offeredTotal ?? 0) <= 0\n return touched && nothingOffered ? 'no-traffic' : 'unknown'\n }\n if (args.recent.offered <= 0) return 'no-traffic'\n\n const ratio = (args.recent.offered - args.recent.rejected) / args.recent.offered\n return ratio >= (args.threshold ?? HEALTHY_ACCEPTED_RATIO) ? 'syncing' : 'mapping-blocked'\n}\n\nexport interface IngestWindowView {\n from: string\n to: string\n offered: number\n /** **ํธ์์ ๋ฟ์** ์. ์ ์ โ ๊ฑฐ๋ถ โ ๋ฏธ์ ๋ฌ. */\n accepted: number\n /** ๋งคํ์ด ๊ฑฐ๋ถํ ์ โ ์ฒ๋ฐฉ์ ๋งคํ์ ๊ณ ์น๋ ๊ฒ. */\n rejected: number\n /** ๋งคํ์ ํต๊ณผํ์ผ๋ ํธ์์ ๋ฟ์ง ๋ชปํ ์ โ ์ฒ๋ฐฉ์ ํธ์์ ์ธ์ฐ๋ ๊ฒ. */\n undelivered: number\n /** ํต๊ณผ์จ(0~1). ์ ์๊ฐ ์์ผ๋ฉด `null` โ **1 ๋ก ์ฑ์ฐ๋ฉด ใ์ ๋ถ ํต๊ณผใ๋ก ์ฝํ๋ค.** */\n acceptedRatio: number | null\n /** ์ด ์ฐฝ์ ์ ํ ํ. */\n rows: number\n /** ๊ทธ๊ฒ์ ์ ๊ธฐ ์ํด DB ๋ฅผ ๋๋๋ฆฐ ํ์ โ ํ๋น ์๋ณต์ด ์ค์๋์ง ๋ณด๋ ๊ฐ. */\n flushes: number\n}\n\nexport interface IngestHealthView {\n verdict: SyncVerdict\n /** ํ์ ์ ์ด ๋ฌธํฑ โ ํ๋ฉด์ด ์ ๊ทธ ํ์ ์ธ์ง ๋งํ ์ ์๊ฒ ํจ๊ป ๋ธ๋ค. */\n threshold: number\n /** ๋ง์ง๋ง์ผ๋ก ๋ซํ ์ฐฝ. ์ฐฝ์ด ํ ๋ฒ๋ ๋ซํ์ง ์์์ผ๋ฉด `null`. */\n recent: IngestWindowView | null\n /** ๋ซํ ์ฐฝ๋ค, ์ค๋๋ ๊ฒ๋ถํฐ. */\n trend: IngestWindowView[]\n /** ์ถ์ด ์ํ์์ ๋ฐ๋ ค๋ ์ฐฝ ์. */\n trendDropped: number\n /** ๋์ (๊ธฐ๋ ์ดํ). */\n total: {\n offered: number\n accepted: number\n rejected: number\n undelivered: number\n acceptedRatio: number | null\n /** ์ ๋์ ์ ํ ํ๊ณผ ๊ทธ๊ฒ์ ์ํด DB ๋ฅผ ๋๋๋ฆฐ ํ์ โ ๊ธฐ๋ ์ดํ ๋์ . */\n rows: number\n flushes: number\n }\n /** ์ฌ์ ๋ณ ๋์ , ๋ง์ ๊ฒ๋ถํฐ. `lastAt` ์ด ๋ฉ์ถ ์ฌ์ ๋ ์ด๋ฏธ ๊ณ ์ณ์ง ๊ฒ์ด๋ค. */\n reasons: { reason: string; count: number; lastAt: string }[]\n /** ์ฌ์ ์ข
๋ฅ๊ฐ ์ํ์ ๋ฟ์ ์ผ๋ถ๊ฐ `(other reasons)` ๋ก ์ ํ๋. */\n reasonsCapped: boolean\n samples: RejectSample[]\n sampleDropped: number\n /** ๋ง์ง๋ง์ผ๋ก ๋ฌด์์ด๋ ๋ฐ์ ์๊ฐ. ํ ๋ฒ๋ ์์ผ๋ฉด `null`. */\n lastAt: string | null\n /** ๋ง์ง๋ง์ผ๋ก ์ ๋์ ์ ์ ์๊ฐ. ํ ๋ฒ๋ ์์ผ๋ฉด `null` โ ๋ฐ์ ์ ์๋ ํธ์๋ ์ด ๊ฐ์ ์์ ์ ์๋ค. */\n lastWriteAt: string | null\n /**\n * **์๋ณธ์ ๋ฟ์ง ๋ชปํ๊ณ ์๋ค** โ ์์ผ๋ฉด ๋ฟ๊ณ ์๋ค๋ ๋ป์ด๋ค(ยง`IngestLedger.readFailure`).\n *\n * ์ปค์ ์ ์ฒด(`cursorStall`)์ **์์ด์ง ์๋๋ค**: ์ด์ชฝ์ ๊ธฐ๋ค๋ฆฌ๋ฉด ํ๋ฆฌ๊ณ ๊ทธ์ชฝ์ ๊ธฐ๋ค๋ ค๋ ์ ํ๋ฆฐ๋ค.\n *\n * ใ์ ์
์์ใ๊ณผ **๋ค๋ฅธ ํ์ **์ด๋ค: ์ ์
์์์ ์ฐ๊ฒฐ๋ ์์คํ
์์ ๋ค์ด์จ ๊ฒ์ด ์๋ ๊ฒ์ผ ์ ์๊ณ , ์ด๊ฒ์ ์ฐ๋ฆฌ๊ฐ ๋ฌป์ง๋\n * ๋ชปํ ๊ฒ์ด๋ค. ํ๋ฉด์ ๋ ๋ฌธ์ฅ์ ๋ค๋ฅด๊ฒ ๋งํด์ผ ํ๋ค โ ์ค ์๋ณธ์ด ๋๊ฒผ์ ๋ ์ฌ์ฉ์๊ฐ ์์ธ์ ์ฐพ์ ์\n * ์๋์ง๊ฐ ๊ทธ ์ฐจ์ด๋ค.\n */\n readFailure?: {\n consecutive: number\n /** ์ด ๋จ์ ์ด ์์๋ ์๊ฐ โ ใ20๋ถ์งธใ๋ฅผ ๋งํ ์ ์๊ฒ. */\n since: string\n lastAt: string\n reason: string\n stream?: string\n /** ๋ค์์ ๋ค์ ๋ฌผ์ ๋๊น์ง ๋จ์ ์๊ฐ(ms) โ ์ปค๋ฅํฐ๊ฐ ๋ฌผ๋ฌ์ฐ์ ๋๋ง ์๋ค. */\n nextRetryMs?: number\n }\n /**\n * ๋ง์ง๋ง์ผ๋ก ๋๊ฒผ๋ค๊ฐ ๋์์จ ๊ฒ โ ์์ผ๋ฉด ๋๊ธด ์ ์ด ์๊ฑฐ๋ ์์ง ๋์์ค์ง ์์ ๊ฒ์ด๋ค (2026-08-27).\n *\n * `readFailure` ๋ ๋์์ค๋ฉด ์ฌ๋ผ์ง๋ค. ์ด ์นธ์ด ์์ผ๋ฉด ๋ฐค์ ๋๊ฒผ๋ ์ฐ๊ฒฐ๊ณผ ํ ๋ฒ๋ ๋๊ธฐ์ง ์์ ์ฐ๊ฒฐ์ด\n * ์์นจ์ ๋๊ฐ์ด ๋ณด์ธ๋ค.\n */\n lastRecovery?: { at: string; afterFailures: number; downMs: number }\n}\n\nfunction toWindowView(w: IngestWindow, fallbackEndMs: number): IngestWindowView {\n /* ใํต๊ณผใ๋ **ํธ์์ ๋ฟ์** ๊ฒ๋ง์ด๋ค. ๋ฒ๋ ค์ง ๊ฒ์ ํต๊ณผ๋ก ์ธ๋ฉด ํ๋ฉด์ด ์์ฌ์ํจ๋ค. */\n const accepted = w.offered - w.rejected - w.undelivered\n return {\n from: new Date(w.startMs).toISOString(),\n to: new Date(w.endMs >= 0 ? w.endMs : fallbackEndMs).toISOString(),\n offered: w.offered,\n accepted,\n rejected: w.rejected,\n undelivered: w.undelivered,\n acceptedRatio: w.offered > 0 ? round4(accepted / w.offered) : null,\n rows: w.rows,\n flushes: w.flushes\n }\n}\n\n/**\n * ์ฝ๊ธฐ์ฉ ์์ฝ.\n *\n * ์ฅ๋ถ๊ฐ ์์ด๋(ํ ๋ฒ๋ ๋ฐ์ง ์์ ํธ์) **ํ์ ์ ๋ธ๋ค** โ ํผ๋ ์ฌ์ค๋ง์ผ๋ก ๋ตํ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค\n * (`not-applicable`ยท`not-connected`). ๊ทธ ๊ฒฝ์ฐ ์์น๋ ๋น์ด๋ค: ์๋ ๊ฐ์ 0 ์ผ๋ก ์ฑ์ฐ์ง ์๋๋ค.\n *\n * `nowMs` ๋ฅผ ๋ฐ๋ ์ด์ : ๋๊ธด ํผ๋๋ฅผ ๊ฐ๋ ค๋ด๋ ค๋ฉด ใ๋ง์ง๋ง ์ ์
์ด ์ผ๋ง๋ ์ ์ธ๊ฐใ๋ฅผ ๋ด์ผ ํ๊ณ , ๊ทธ ํ๋จ์\n * ํ๋ฉด์ด ์๋๋ผ ์ฌ๊ธฐ์ ํ๋ค(์๋น์ฒ๋ง๋ค ๋ค์ ํ๋จํ๋ฉด ๊ท์น์ด ๊ฐ๋ผ์ง๋ค). ์ํ์ด ์๊ฐ์ ๊ณ ์ ํ ์ ์๋๋ก\n * ์ธ์๋ก ๋ฐ๋๋ค.\n */\nexport function ingestHealth(\n ledger: IngestLedger | undefined,\n feedState: 'attached' | 'detached' | 'not-applicable',\n threshold = HEALTHY_ACCEPTED_RATIO,\n nowMs: number = Date.now()\n): IngestHealthView {\n const recentRaw = ledger?.trend.length ? ledger.trend[ledger.trend.length - 1] : null\n /* ์ด๋ฆฐ ์ฐฝ์ ๋ ์๊ฐ ๋์ฒด๊ฐ โ ์ ์
์ด ์๋ ์ฅ๋ถ์์ `-1` ์ ์๊ฐ์ผ๋ก ์ฝ์ผ๋ฉด 1969๋
์ด ํ๋ฉด์ ๋ฌ๋ค. */\n const lastAnyMs = Math.max(ledger?.lastAtMs ?? -1, ledger?.lastWriteAtMs ?? -1)\n const verdict = syncVerdictOf({\n feedState,\n recent: recentRaw,\n lastAtMs: ledger?.lastAtMs ?? -1,\n lastUndeliveredAtMs: ledger?.lastUndeliveredAtMs ?? -1,\n /* ์ฐฝ์ด ๋ซํ์ง ์์์ ๋ ใ๋ฐ๋ ์คใ๊ณผ ใ์ค๋ ๊ฒ์ด ์๋คใ๋ฅผ ๊ฐ๋ฅด๋ ์ฌ์ค. */\n offeredTotal: ledger?.offered ?? 0,\n nowMs,\n threshold\n })\n\n /*\n * **์ ์
์ด ์์ด๋ ใ๋น ์ฅ๋ถใ๊ฐ ์๋๋ค.** ์๋ฎฌ ํธ์์ ๋ฐ๋ ๊ฒ ์์ด ์ ๋๋ค. ์ ์
์๊ฐ๋ง ๋ณด๊ณ ๋น์๋ค๊ณ \n * ํ๋จํ๋ฉด ๊ทธ ํธ์์ ์ฐฝ์ ๋ง๋ค์ด์ ธ ์๋๋ฐ ํ๋ฉด์๋ ์๋ฌด ์ถ์ด๋ ๋์ค์ง ์๋๋ค(์ด ์ถ์ ๋ฃ์ ์ด์ ๊ฐ ๊ทธ๊ฒ์ด๋ค).\n */\n if (!ledger || (ledger.lastAtMs < 0 && ledger.lastWriteAtMs < 0)) {\n return {\n verdict,\n threshold,\n recent: null,\n trend: [],\n trendDropped: 0,\n total: { offered: 0, accepted: 0, rejected: 0, undelivered: 0, acceptedRatio: null, rows: 0, flushes: 0 },\n reasons: [],\n reasonsCapped: false,\n samples: [],\n sampleDropped: 0,\n lastAt: null,\n lastWriteAt: null,\n /*\n * **์ด ์งง์ ๋ต์๋ ๋จ์ ์ ์ค์ด์ผ ํ๋ค** โ ์ด ์๋ฆฌ๊ฐ ๋ฐ๋ก ๊ทธ ํธ์์ ๋ชจ์ต์ด๋ค.\n *\n * ๋ฐ์ ๊ฒ๋ ์ ์ ๊ฒ๋ ์๋ ์ฅ๋ถ๋ ใ์์ง ์๋ฌด ์ผ๋ ์๋คใ๋ก ์ฝํ๋๋ฐ, ์๋ณธ์ ๋ฟ์ง ๋ชปํ๋ ํธ์์ด\n * ์ ํํ ๊ทธ ๋ชจ์ต์ด๋ค(์ฝ์ง ๋ชปํ๋ฉด ๋ฐ์ ๊ฒ๋ ์ ์ ๊ฒ๋ ์๋ค). ์ฌ๊ธฐ์ ๋จ์ด๋จ๋ฆฌ๋ฉด **๊ฐ์ฅ ํ์ํ\n * ์๊ฐ์** ๊ทธ ์ฌ์ค์ด ์ฌ๋ผ์ง๋ค โ ์ค์ธก์ผ๋ก ์๋ณธ์ด ๋๊ธด ํธ์์ด ์ด ๊ฒฝ๋ก๋ก ๋ตํ๊ณ ์์๋ค.\n */\n ...(ledger?.readFailure\n ? {\n readFailure: {\n consecutive: ledger.readFailure.consecutive,\n since: new Date(ledger.readFailure.sinceMs).toISOString(),\n lastAt: new Date(ledger.readFailure.lastAtMs).toISOString(),\n reason: ledger.readFailure.reason,\n ...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {}),\n ...(ledger.readFailure.nextRetryMs ? { nextRetryMs: ledger.readFailure.nextRetryMs } : {})\n }\n }\n : {}),\n ...(ledger?.lastRecovery\n ? {\n lastRecovery: {\n at: new Date(ledger.lastRecovery.atMs).toISOString(),\n afterFailures: ledger.lastRecovery.afterFailures,\n downMs: ledger.lastRecovery.downMs\n }\n }\n : {}),\n /* ์ปค์ ์ ์ฒด๋ **์ด ๊ฐ๋์์** ๋ด๋ณด๋ธ๋ค โ ์ ์
์ด ์๋ ์ฅ๋ถ์์๋ ์ ์ฒด๋ ์ค์ฌํ๋ค(์ฝ์์ผ๋ ๋ชป\n ๋๊ฒผ์ผ๋ฉด ์ ์
์ด 0์ด๋ค). ์ฌ๊ธฐ์ ๋จ์ด๋จ๋ฆฌ๋ฉด ๋ฐ๋ก ๊ทธ ์ํฉ์์ ๋ค์ด์จ ๊ฒ์ด ์์ด์ง๋ค. */\n ...(ledger?.cursorStall\n ? {\n cursorStall: {\n consecutive: ledger.cursorStall.consecutive,\n since: new Date(ledger.cursorStall.sinceMs).toISOString(),\n lastAt: new Date(ledger.cursorStall.lastAtMs).toISOString(),\n reason: ledger.cursorStall.reason,\n ...(ledger.cursorStall.stream ? { stream: ledger.cursorStall.stream } : {})\n }\n }\n : {}),\n /*\n * **์ธ์ฐ์ง ์์ ๊ฒ๋ ๋ธ๋ค โ ์์ชฝ ๊ฐ๋์์.** ์ ์
์ด ํ ๊ฑด๋ ์๋ ์ฅ๋ถ์์๋ ์ด ์ฌ์ค์ ์ค์ฌํ๋ค\n * (์๋ณธ์ด ๋งํ๋๋ฐ ์ ๋ถ ์ ๋ฐ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค). ์ฌ๊ธฐ์ ๋จ์ด๋จ๋ฆฌ๋ฉด ๋ฐ๋ก ๊ทธ ์ํฉ์์ ๋ค์ด์จ ๊ฒ์ด ์์ด์ง๋ค.\n */\n ...(ledger?.withheld?.length\n ? {\n withheld: ledger.withheld.map(w => ({\n reason: w.reason,\n count: w.count,\n lastAt: new Date(w.lastAtMs).toISOString()\n }))\n }\n : {})\n }\n }\n\n /* ใํต๊ณผใ๋ ํธ์์ ๋ฟ์ ๊ฒ๋ง์ด๋ค โ ์ฐฝ ๋ทฐ์ ๊ฐ์ ๊ท์น. */\n const accepted = ledger.offered - ledger.rejected - ledger.undelivered\n return {\n verdict,\n threshold,\n recent: recentRaw ? toWindowView(recentRaw, lastAnyMs) : null,\n trend: ledger.trend.map(w => toWindowView(w, lastAnyMs)),\n trendDropped: ledger.trendDropped,\n /* ์ธ์ฐ์ง ์์ ๊ฒ โ ์์ชฝ ๊ฐ๋์์ ๊ฐ์ ๋ชจ์์ผ๋ก ๋ธ๋ค(ยง`IngestLedger.withheld`). */\n ...(ledger.withheld?.length\n ? {\n withheld: ledger.withheld.map(w => ({\n reason: w.reason,\n count: w.count,\n lastAt: new Date(w.lastAtMs).toISOString()\n }))\n }\n : {}),\n /*\n * **์ด๋ค ๊ธธ๋ก ๋ค์ด์ค๊ณ ์๋** โ ํ๋ฉด์ด ใ์ด ํธ์์ ๋ฌด์์ ํตํด ๊ฐ์ ๋ฐ๋ใ๋ฅผ ๋งํ ์ ์๊ฒ.\n * ๋น์ด ์์ผ๋ฉด ์นธ์ ๋ง๋ค์ง ์๋๋ค: ์์ง ์๋ฌด๊ฒ๋ ์ ๋ฐ์ ํธ์๊ณผ ใ๊ธธ์ด ์๋คใ๋ฅผ ๊ตฌ๋ณํ๋ค.\n */\n ...(Object.keys(ledger.bySource).length\n ? {\n sources: Object.entries(ledger.bySource)\n .map(([source, v]) => ({ source, count: v.count, lastAt: new Date(v.lastAtMs).toISOString() }))\n .sort((a, b) => b.count - a.count)\n }\n : {}),\n /* ๊ฐ์ ์ฌ์ค์ด ๋ ๋ฒ ์์ ๋ฒ๋ฆฐ ์ โ 0 ์ด๋ฉด ์นธ์ ๋ง๋ค์ง ์๋๋ค(๋ฒ๋ฆฐ ์ ์ด ์๋ค๋ ๋ป์ด๋ค). */\n ...(ledger.duplicates\n ? { duplicates: { count: ledger.duplicates, lastAt: new Date(ledger.lastDuplicateAtMs).toISOString() } }\n : {}),\n total: {\n offered: ledger.offered,\n accepted,\n rejected: ledger.rejected,\n undelivered: ledger.undelivered,\n acceptedRatio: ledger.offered > 0 ? round4(accepted / ledger.offered) : null,\n rows: ledger.rows,\n flushes: ledger.flushes\n },\n reasons: Object.entries(ledger.byReason)\n .map(([reason, v]) => ({ reason, count: v.count, lastAt: new Date(v.lastAtMs).toISOString() }))\n .sort((a, b) => b.count - a.count || a.reason.localeCompare(b.reason)),\n reasonsCapped: ledger.reasonsCapped,\n samples: [...ledger.samples],\n sampleDropped: ledger.sampleDropped,\n /* ใ๋ฐ์ ์ ์์ใ๊ณผ ใ๋ฐฉ๊ธ ๋ฐ์ใ์ ๊ฐ๋ฅธ๋ค โ ์ ๊ธฐ๋ง ํ๋ ํธ์์ ์ ์
์๊ฐ์ **์๋ค**. */\n lastAt: ledger.lastAtMs >= 0 ? new Date(ledger.lastAtMs).toISOString() : null,\n lastWriteAt: ledger.lastWriteAtMs >= 0 ? new Date(ledger.lastWriteAtMs).toISOString() : null,\n /* ๋ฟ์ง ๋ชปํ๊ณ ์์ผ๋ฉด ๊ทธ ์ฌ์ค์ ๋ธ๋ค โ ์์ผ๋ฉด ํ๋๋ฅผ ๋ง๋ค์ง ์๋๋ค(๋น ๊ฐ์ด ใ๋ฟ๋๋คใ๋ก ์ฝํ์ง ์๊ฒ). */\n ...(ledger.readFailure\n ? {\n readFailure: {\n consecutive: ledger.readFailure.consecutive,\n since: new Date(ledger.readFailure.sinceMs).toISOString(),\n lastAt: new Date(ledger.readFailure.lastAtMs).toISOString(),\n reason: ledger.readFailure.reason,\n ...(ledger.readFailure.stream ? { stream: ledger.readFailure.stream } : {}),\n ...(ledger.readFailure.nextRetryMs ? { nextRetryMs: ledger.readFailure.nextRetryMs } : {})\n }\n }\n : {}),\n /* ๋๊ฒผ๋ค๊ฐ ๋์์จ ๊ฒ โ ์ง๊ธ ๋ฟ๊ณ ์์ด๋ ๋จ๊ธด๋ค(๊ทธ๊ฒ์ด ์์ผ๋ฉด ๋ฐค์์ ๋จ์ ์ด ์ฌ๋ผ์ง๋ค). */\n ...(ledger.lastRecovery\n ? {\n lastRecovery: {\n at: new Date(ledger.lastRecovery.atMs).toISOString(),\n afterFailures: ledger.lastRecovery.afterFailures,\n downMs: ledger.lastRecovery.downMs\n }\n }\n : {}),\n ...(ledger.cursorStall\n ? {\n cursorStall: {\n consecutive: ledger.cursorStall.consecutive,\n since: new Date(ledger.cursorStall.sinceMs).toISOString(),\n lastAt: new Date(ledger.cursorStall.lastAtMs).toISOString(),\n reason: ledger.cursorStall.reason,\n ...(ledger.cursorStall.stream ? { stream: ledger.cursorStall.stream } : {})\n }\n }\n : {})\n }\n}\n\n/** ๋น์จ์ ์๋ฆฟ์๋ฅผ ๋๋ํ ์ค๋ค โ 0.999 ๊ฐ 1 ๋ก ๋ฐ์ฌ๋ฆผ๋๋ฉด ใ์ ๋ถ ํต๊ณผใ๋ก ์ฝํ๋ค. */\nconst round4 = (v: number) => Math.round(v * 10000) / 10000\n"]}
|
|
@@ -27,7 +27,7 @@ export interface ProbeResult {
|
|
|
27
27
|
*
|
|
28
28
|
* ์๋ฎฌ๋ ์ด์
ํธ์์ ๋ผ์ด๋ธ ํ๋ก๋ธ๋ฅผ ๋ค์ด๋๋ฉด ๋นจ๊ฐ ์นธ์ด ์๊ธฐ๋๋ฐ ๊ทธ๊ฑด ๊ฒฐํจ์ด ์๋๋ค โ ์๋ฎฌ์ ์์ฒ์์
|
|
29
29
|
* ๋ฐ๋ ๊ฒ์ด ์๋ค. ๋ ํผ๋ฐ์ค ์์ด ํ
ํ๋ฆฟ์ผ๋ก ์ธ์ด ํธ์์๋ ์ฎ๊ฒจ ์จ ๋ง์คํฐ๊ฐ ์์ผ๋ฏ๋ก ใ๋ชป ์ฎ๊ธด ๊ฐใ๋ ์๋ค.
|
|
30
|
-
* ์ด๊ฑธ ํต๊ณผ๋ก
|
|
30
|
+
* ์ด๊ฑธ ํต๊ณผ๋ก ์ฒ๋ฆฌํ๋ฉด ์๋ ๋ฅ๋ ฅ์ ์ฃผ์ฅํ๊ณ , ๋ฏธ์ธก์ ์ผ๋ก ์ฒ๋ฆฌํ๋ฉด ์์ํ ๋ฐฐ์ ์ ๊ธฐ๋ค๋ฆฐ๋ค.
|
|
31
31
|
*/
|
|
32
32
|
applicable?: boolean;
|
|
33
33
|
/** ๋๋ ธ์ ๋์ ํ์ . ๋๋ฆฌ์ง ์์์ผ๋ฉด ๋ฌด์๋ฏธํ๋ค. */
|
|
@@ -43,9 +43,9 @@ export interface ProbeResult {
|
|
|
43
43
|
detail?: string;
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* ํ๋ก๋ธ ๊ฒฐ๊ณผ๋ฅผ **์ฆ๊ฑฐ**๋ก
|
|
46
|
+
* ํ๋ก๋ธ ๊ฒฐ๊ณผ๋ฅผ **์ฆ๊ฑฐ**๋ก ์ฒ๋ฆฌํ๋ค.
|
|
47
47
|
*
|
|
48
|
-
*
|
|
48
|
+
* ๊ณ์ฐ ๊ท์น์ ์ ์: **๋๋ฆฌ์ง ์์ ํ๋ก๋ธ๋ `null`** ๋ก ๊ฐ๋ค. ๊ทธ๋ฌ๋ฉด ํ์ ์ด ๊ทธ ๋จ๊ณ๋ฅผ ๋ฌ์ฑ์ผ๋ก
|
|
49
49
|
* ๋ง๋ค์ง ์๊ณ `unmeasured` ๋ก ๋งํ๋ค โ ์ค์ํธ๋ฅผ ์ ๋ฐ๋ง ๋๋ฆฌ๊ณ ์ด๋ก์ ์ฃผ์ฅํ ๊ธธ์ด ์๋ค.
|
|
50
50
|
*/
|
|
51
51
|
export declare function foldProbeResults(results: readonly ProbeResult[]): StageEvidence;
|