@things-factory/headless-twin 10.1.278 → 10.1.280
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/package.json +21 -7
- package/dist-server/engine/attention-digest.js.map +0 -1
- package/dist-server/engine/canonical-ingest.js.map +0 -1
- package/dist-server/engine/checkpoint-fold.js.map +0 -1
- package/dist-server/engine/command-routing.js.map +0 -1
- package/dist-server/engine/declared-stimulus.js.map +0 -1
- package/dist-server/engine/energy-topology.js.map +0 -1
- package/dist-server/engine/event-time.js.map +0 -1
- package/dist-server/engine/index.js.map +0 -1
- package/dist-server/engine/ingest-dedupe.js.map +0 -1
- package/dist-server/engine/ingest-health.js.map +0 -1
- package/dist-server/engine/integration-coverage.js.map +0 -1
- package/dist-server/engine/integration-probes.js.map +0 -1
- package/dist-server/engine/integration-runner.js.map +0 -1
- package/dist-server/engine/integration-target-profile.js.map +0 -1
- package/dist-server/engine/kpi-baseline.js.map +0 -1
- package/dist-server/engine/kpi-fold.js.map +0 -1
- package/dist-server/engine/kpi-query.js.map +0 -1
- package/dist-server/engine/kpi-target.js.map +0 -1
- package/dist-server/engine/live-attentions.js.map +0 -1
- package/dist-server/engine/live-feed-registry.js.map +0 -1
- package/dist-server/engine/load-meter.js.map +0 -1
- package/dist-server/engine/local-declarations.js.map +0 -1
- package/dist-server/engine/log.js.map +0 -1
- package/dist-server/engine/loop-lag.js.map +0 -1
- package/dist-server/engine/measured-estimator.js.map +0 -1
- package/dist-server/engine/measured-yield.js.map +0 -1
- package/dist-server/engine/model-basis.js.map +0 -1
- package/dist-server/engine/model-gap.js.map +0 -1
- package/dist-server/engine/model-refusal.js.map +0 -1
- package/dist-server/engine/model-vocabulary.js.map +0 -1
- package/dist-server/engine/oee-accumulator.js.map +0 -1
- package/dist-server/engine/operation-basis.js.map +0 -1
- package/dist-server/engine/producer-guard.js.map +0 -1
- package/dist-server/engine/property-effects.js.map +0 -1
- package/dist-server/engine/read-time.js.map +0 -1
- package/dist-server/engine/restart-policy.js.map +0 -1
- package/dist-server/engine/runtime-key.js.map +0 -1
- package/dist-server/engine/spec-coverage.js.map +0 -1
- package/dist-server/engine/stage-path.js.map +0 -1
- package/dist-server/engine/state-axes.js.map +0 -1
- package/dist-server/engine/structure-diff.js.map +0 -1
- package/dist-server/engine/travel-estimator.js.map +0 -1
- package/dist-server/engine/twin-engine.js.map +0 -1
- package/dist-server/engine/twin-state-channel.js.map +0 -1
- package/dist-server/engine/warm-start.js.map +0 -1
- package/dist-server/index.js.map +0 -1
- package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +0 -1
- package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +0 -1
- package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +0 -1
- package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +0 -1
- package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +0 -1
- package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +0 -1
- package/dist-server/migrations/1786600000000-RenameOperatoMesAdapterType.js.map +0 -1
- package/dist-server/migrations/1786700000000-AddDispatchRetryColumns.js.map +0 -1
- package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +0 -1
- package/dist-server/migrations/index.js.map +0 -1
- package/dist-server/routes.js.map +0 -1
- package/dist-server/service/actuation/actuation-advisor.js.map +0 -1
- package/dist-server/service/actuation/actuation-outcome.js.map +0 -1
- package/dist-server/service/actuation/actuation-rule-resolver.js.map +0 -1
- package/dist-server/service/actuation/actuation-rule.js.map +0 -1
- package/dist-server/service/actuation/approval-gateway.js.map +0 -1
- package/dist-server/service/actuation/catch-up-effects.js.map +0 -1
- package/dist-server/service/actuation/command-dispatcher.js.map +0 -1
- package/dist-server/service/actuation/command-store.js.map +0 -1
- package/dist-server/service/actuation/dispatch-after-approval.js.map +0 -1
- package/dist-server/service/actuation/effect-match.js.map +0 -1
- package/dist-server/service/actuation/index.js.map +0 -1
- package/dist-server/service/actuation/retry-plan.js.map +0 -1
- package/dist-server/service/actuation/rule-evaluate.js.map +0 -1
- package/dist-server/service/actuation/rule-loop.js.map +0 -1
- package/dist-server/service/actuation/rule-runner.js.map +0 -1
- package/dist-server/service/actuation/rule-wiring.js.map +0 -1
- package/dist-server/service/actuation/settle-effects.js.map +0 -1
- package/dist-server/service/actuation/sweep-dispatch.js.map +0 -1
- package/dist-server/service/actuation/twin-command-resolver.js.map +0 -1
- package/dist-server/service/actuation/twin-command.js.map +0 -1
- package/dist-server/service/actuation/twin-now.js.map +0 -1
- package/dist-server/service/index.js.map +0 -1
- package/dist-server/service/reference/actuation-routing.js.map +0 -1
- package/dist-server/service/reference/actuation-target.js.map +0 -1
- package/dist-server/service/reference/actuation-verification.js.map +0 -1
- package/dist-server/service/reference/attention-lane.js.map +0 -1
- package/dist-server/service/reference/connection-portability-resolver.js.map +0 -1
- package/dist-server/service/reference/connection-portability.js.map +0 -1
- package/dist-server/service/reference/control-routing.js.map +0 -1
- package/dist-server/service/reference/discovery-result.js.map +0 -1
- package/dist-server/service/reference/fill-cadence.js.map +0 -1
- package/dist-server/service/reference/fill-dedupe.js.map +0 -1
- package/dist-server/service/reference/fill-loop.js.map +0 -1
- package/dist-server/service/reference/fill-span.js.map +0 -1
- package/dist-server/service/reference/hook-contract.js.map +0 -1
- package/dist-server/service/reference/hook-rejected.js.map +0 -1
- package/dist-server/service/reference/hook-store.js.map +0 -1
- package/dist-server/service/reference/index.js.map +0 -1
- package/dist-server/service/reference/ingest-space.js.map +0 -1
- package/dist-server/service/reference/knob-defaults.js.map +0 -1
- package/dist-server/service/reference/live-cadence.js.map +0 -1
- package/dist-server/service/reference/live-feed-lease.js.map +0 -1
- package/dist-server/service/reference/live-ingest.js.map +0 -1
- package/dist-server/service/reference/reference-adapter.js.map +0 -1
- package/dist-server/service/reference/reference-assessment.js.map +0 -1
- package/dist-server/service/reference/reference-fill-run.js.map +0 -1
- package/dist-server/service/reference/reference-fill.js.map +0 -1
- package/dist-server/service/reference/reference-hook.js.map +0 -1
- package/dist-server/service/reference/reference-link-groups.js.map +0 -1
- package/dist-server/service/reference/reference-links.js.map +0 -1
- package/dist-server/service/reference/reference-live.js.map +0 -1
- package/dist-server/service/reference/reference-master.js.map +0 -1
- package/dist-server/service/reference/reference-probe.js.map +0 -1
- package/dist-server/service/reference/reference-progress-channel.js.map +0 -1
- package/dist-server/service/reference/reference-progress-subscription.js.map +0 -1
- package/dist-server/service/reference/reference-progress.js.map +0 -1
- package/dist-server/service/reference/reference-reconciliation-query.js.map +0 -1
- package/dist-server/service/reference/reference-reconciliation-writer.js.map +0 -1
- package/dist-server/service/reference/reference-reconciliation.js.map +0 -1
- package/dist-server/service/reference/reference-registry.js.map +0 -1
- package/dist-server/service/reference/reference-resolver.js.map +0 -1
- package/dist-server/service/reference/template-registry.js.map +0 -1
- package/dist-server/service/reference/twin-reference-reconciliation.js.map +0 -1
- package/dist-server/service/reference/twin-reference.js.map +0 -1
- package/dist-server/service/twin-attention/index.js.map +0 -1
- package/dist-server/service/twin-attention/twin-attention-query.js.map +0 -1
- package/dist-server/service/twin-audit/command-audit.js.map +0 -1
- package/dist-server/service/twin-audit/index.js.map +0 -1
- package/dist-server/service/twin-audit/twin-audit-event.js.map +0 -1
- package/dist-server/service/twin-audit/twin-audit-query.js.map +0 -1
- package/dist-server/service/twin-backfill/backfill-period-facts.js.map +0 -1
- package/dist-server/service/twin-backfill/backfill-shape.js.map +0 -1
- package/dist-server/service/twin-backfill/index.js.map +0 -1
- package/dist-server/service/twin-backfill/twin-backfill-resolver.js.map +0 -1
- package/dist-server/service/twin-control/index.js.map +0 -1
- package/dist-server/service/twin-control/twin-control-mutation.js.map +0 -1
- package/dist-server/service/twin-event/index.js.map +0 -1
- package/dist-server/service/twin-event/journal-count.js.map +0 -1
- package/dist-server/service/twin-event/twin-event-keys.js.map +0 -1
- package/dist-server/service/twin-event/twin-event-type.js.map +0 -1
- package/dist-server/service/twin-event/twin-event.js.map +0 -1
- package/dist-server/service/twin-forecast/forecast-metrics.js.map +0 -1
- package/dist-server/service/twin-forecast/forecast-tuning.js.map +0 -1
- package/dist-server/service/twin-forecast/gap-analytics.js.map +0 -1
- package/dist-server/service/twin-forecast/index.js.map +0 -1
- package/dist-server/service/twin-forecast/twin-forecast-query.js.map +0 -1
- package/dist-server/service/twin-ingest-window/index.js.map +0 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +0 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +0 -1
- package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +0 -1
- package/dist-server/service/twin-instance/index.js.map +0 -1
- package/dist-server/service/twin-instance/twin-instance.js.map +0 -1
- package/dist-server/service/twin-journal/event-type-split-shape.js.map +0 -1
- package/dist-server/service/twin-journal/event-type-split.js.map +0 -1
- package/dist-server/service/twin-journal/index.js.map +0 -1
- package/dist-server/service/twin-journal/journal-order.js.map +0 -1
- package/dist-server/service/twin-journal/twin-journal-query.js.map +0 -1
- package/dist-server/service/twin-lifecycle/domain-catalog.js.map +0 -1
- package/dist-server/service/twin-lifecycle/index.js.map +0 -1
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +0 -1
- package/dist-server/service/twin-metrics/index.js.map +0 -1
- package/dist-server/service/twin-metrics/twin-metrics-query.js.map +0 -1
- package/dist-server/service/twin-model/axis-journal-evidence.js.map +0 -1
- package/dist-server/service/twin-model/choose-recipe.js.map +0 -1
- package/dist-server/service/twin-model/epcis-coverage.js.map +0 -1
- package/dist-server/service/twin-model/external-resolver.js.map +0 -1
- package/dist-server/service/twin-model/iec61850-coverage.js.map +0 -1
- package/dist-server/service/twin-model/index.js.map +0 -1
- package/dist-server/service/twin-model/isa95-coverage.js.map +0 -1
- package/dist-server/service/twin-model/item-ref.js.map +0 -1
- package/dist-server/service/twin-model/name-index.js.map +0 -1
- package/dist-server/service/twin-model/project-structure.js.map +0 -1
- package/dist-server/service/twin-model/standard-coverage.js.map +0 -1
- package/dist-server/service/twin-model/status-tally.js.map +0 -1
- package/dist-server/service/twin-model/twin-equipment.js.map +0 -1
- package/dist-server/service/twin-model/twin-lineage-query.js.map +0 -1
- package/dist-server/service/twin-model/twin-location.js.map +0 -1
- package/dist-server/service/twin-model/twin-model-item-query.js.map +0 -1
- package/dist-server/service/twin-model/twin-model-mutation.js.map +0 -1
- package/dist-server/service/twin-model/twin-model-query.js.map +0 -1
- package/dist-server/service/twin-model/twin-model-tree-query.js.map +0 -1
- package/dist-server/service/twin-model/twin-operation.js.map +0 -1
- package/dist-server/service/twin-readiness/index.js.map +0 -1
- package/dist-server/service/twin-readiness/twin-readiness-query.js.map +0 -1
- package/dist-server/service/twin-space/area-resolver.js.map +0 -1
- package/dist-server/service/twin-space/index.js.map +0 -1
- package/dist-server/service/twin-space/move-space.js.map +0 -1
- package/dist-server/service/twin-space/representation-role.js.map +0 -1
- package/dist-server/service/twin-space/space-integrity.js.map +0 -1
- package/dist-server/service/twin-space/twin-area.js.map +0 -1
- package/dist-server/service/twin-space/twin-space-area.js.map +0 -1
- package/dist-server/service/twin-space/twin-space-representation.js.map +0 -1
- package/dist-server/service/twin-space/twin-space-resolver.js.map +0 -1
- package/dist-server/service/twin-space/twin-space.js.map +0 -1
- package/dist-server/service/twin-state/index.js.map +0 -1
- package/dist-server/service/twin-state/twin-state-subscription.js.map +0 -1
- package/dist-server/service/twin-structure/index.js.map +0 -1
- package/dist-server/service/twin-structure/twin-structure.js.map +0 -1
- package/dist-server/service/twin-subject/event-subjects.js.map +0 -1
- package/dist-server/service/twin-subject/index.js.map +0 -1
- package/dist-server/service/twin-subject/item-resolver.js.map +0 -1
- package/dist-server/service/twin-subject/subject-query-shape.js.map +0 -1
- package/dist-server/service/twin-subject/twin-subject-backfill.js.map +0 -1
- package/dist-server/service/twin-subject/twin-subject-event.js.map +0 -1
- package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +0 -1
- package/dist-server/service/twin-subject/twin-subject-query.js.map +0 -1
- package/dist-server/service/twin-subject/twin-subject-writer.js.map +0 -1
- package/dist-server/service/twin-target/index.js.map +0 -1
- package/dist-server/service/twin-target/twin-target-resolver.js.map +0 -1
- package/dist-server/service/twin-target/twin-target.js.map +0 -1
- package/dist-shared/axis-read.js.map +0 -1
- package/dist-shared/entity-delta.js.map +0 -1
- package/dist-shared/kpi-broadcast.js.map +0 -1
- package/dist-shared/touched-items.js.map +0 -1
- package/dist-shared/twin-level.js.map +0 -1
- package/server/engine/attention-digest.ts +0 -102
- package/server/engine/canonical-ingest.ts +0 -511
- package/server/engine/checkpoint-fold.ts +0 -12
- package/server/engine/command-routing.ts +0 -67
- package/server/engine/declared-stimulus.ts +0 -66
- package/server/engine/energy-topology.ts +0 -189
- package/server/engine/event-time.ts +0 -96
- package/server/engine/index.ts +0 -51
- package/server/engine/ingest-dedupe.ts +0 -24
- package/server/engine/ingest-health.ts +0 -24
- package/server/engine/integration-coverage.ts +0 -147
- package/server/engine/integration-probes.ts +0 -144
- package/server/engine/integration-runner.ts +0 -95
- package/server/engine/integration-target-profile.ts +0 -103
- package/server/engine/kpi-baseline.ts +0 -202
- package/server/engine/kpi-fold.ts +0 -1516
- package/server/engine/kpi-query.ts +0 -1210
- package/server/engine/kpi-target.ts +0 -248
- package/server/engine/live-attentions.ts +0 -30
- package/server/engine/live-feed-registry.ts +0 -59
- package/server/engine/load-meter.ts +0 -393
- package/server/engine/local-declarations.ts +0 -779
- package/server/engine/log.ts +0 -72
- package/server/engine/loop-lag.ts +0 -120
- package/server/engine/measured-estimator.ts +0 -91
- package/server/engine/measured-yield.ts +0 -89
- package/server/engine/model-basis.ts +0 -162
- package/server/engine/model-gap.ts +0 -168
- package/server/engine/model-refusal.ts +0 -31
- package/server/engine/model-vocabulary.ts +0 -82
- package/server/engine/oee-accumulator.ts +0 -195
- package/server/engine/operation-basis.ts +0 -131
- package/server/engine/producer-guard.ts +0 -64
- package/server/engine/property-effects.ts +0 -216
- package/server/engine/read-time.ts +0 -77
- package/server/engine/restart-policy.ts +0 -55
- package/server/engine/runtime-key.ts +0 -58
- package/server/engine/spec-coverage.ts +0 -105
- package/server/engine/stage-path.ts +0 -172
- package/server/engine/state-axes.ts +0 -60
- package/server/engine/structure-diff.ts +0 -88
- package/server/engine/travel-estimator.ts +0 -138
- package/server/engine/twin-engine.ts +0 -4979
- package/server/engine/twin-state-channel.ts +0 -39
- package/server/engine/warm-start.ts +0 -265
- package/server/index.ts +0 -90
- package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +0 -43
- package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +0 -54
- package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +0 -53
- package/server/migrations/1786300000000-IndexEventTypeByTime.ts +0 -48
- package/server/migrations/1786400000000-IndexEventCreatedAt.ts +0 -38
- package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +0 -93
- package/server/migrations/1786600000000-RenameOperatoMesAdapterType.ts +0 -66
- package/server/migrations/1786700000000-AddDispatchRetryColumns.ts +0 -82
- package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +0 -39
- package/server/migrations/index.ts +0 -25
- package/server/routes.ts +0 -75
- package/server/service/actuation/actuation-advisor.ts +0 -131
- package/server/service/actuation/actuation-outcome.ts +0 -97
- package/server/service/actuation/actuation-rule-resolver.ts +0 -147
- package/server/service/actuation/actuation-rule.ts +0 -139
- package/server/service/actuation/approval-gateway.ts +0 -44
- package/server/service/actuation/catch-up-effects.ts +0 -152
- package/server/service/actuation/command-dispatcher.ts +0 -474
- package/server/service/actuation/command-store.ts +0 -236
- package/server/service/actuation/dispatch-after-approval.ts +0 -71
- package/server/service/actuation/effect-match.ts +0 -124
- package/server/service/actuation/index.ts +0 -27
- package/server/service/actuation/retry-plan.ts +0 -145
- package/server/service/actuation/rule-evaluate.ts +0 -352
- package/server/service/actuation/rule-loop.ts +0 -160
- package/server/service/actuation/rule-runner.ts +0 -216
- package/server/service/actuation/rule-wiring.ts +0 -84
- package/server/service/actuation/settle-effects.ts +0 -115
- package/server/service/actuation/sweep-dispatch.ts +0 -179
- package/server/service/actuation/twin-command-resolver.ts +0 -387
- package/server/service/actuation/twin-command.ts +0 -232
- package/server/service/actuation/twin-now.ts +0 -97
- package/server/service/index.ts +0 -100
- package/server/service/reference/actuation-routing.ts +0 -192
- package/server/service/reference/actuation-target.ts +0 -163
- package/server/service/reference/actuation-verification.ts +0 -85
- package/server/service/reference/attention-lane.ts +0 -21
- package/server/service/reference/connection-portability-resolver.ts +0 -171
- package/server/service/reference/connection-portability.ts +0 -329
- package/server/service/reference/control-routing.ts +0 -62
- package/server/service/reference/discovery-result.ts +0 -95
- package/server/service/reference/fill-cadence.ts +0 -29
- package/server/service/reference/fill-dedupe.ts +0 -66
- package/server/service/reference/fill-loop.ts +0 -153
- package/server/service/reference/fill-span.ts +0 -31
- package/server/service/reference/hook-contract.ts +0 -364
- package/server/service/reference/hook-rejected.ts +0 -53
- package/server/service/reference/hook-store.ts +0 -28
- package/server/service/reference/index.ts +0 -18
- package/server/service/reference/ingest-space.ts +0 -104
- package/server/service/reference/knob-defaults.ts +0 -59
- package/server/service/reference/live-cadence.ts +0 -129
- package/server/service/reference/live-feed-lease.ts +0 -56
- package/server/service/reference/live-ingest.ts +0 -94
- package/server/service/reference/reference-adapter.ts +0 -985
- package/server/service/reference/reference-assessment.ts +0 -250
- package/server/service/reference/reference-fill-run.ts +0 -179
- package/server/service/reference/reference-fill.ts +0 -223
- package/server/service/reference/reference-hook.ts +0 -479
- package/server/service/reference/reference-link-groups.ts +0 -21
- package/server/service/reference/reference-links.ts +0 -77
- package/server/service/reference/reference-live.ts +0 -420
- package/server/service/reference/reference-master.ts +0 -999
- package/server/service/reference/reference-probe.ts +0 -264
- package/server/service/reference/reference-progress-channel.ts +0 -26
- package/server/service/reference/reference-progress-subscription.ts +0 -78
- package/server/service/reference/reference-progress.ts +0 -95
- package/server/service/reference/reference-reconciliation-query.ts +0 -28
- package/server/service/reference/reference-reconciliation-writer.ts +0 -38
- package/server/service/reference/reference-reconciliation.ts +0 -55
- package/server/service/reference/reference-registry.ts +0 -17
- package/server/service/reference/reference-resolver.ts +0 -969
- package/server/service/reference/template-registry.ts +0 -85
- package/server/service/reference/twin-reference-reconciliation.ts +0 -27
- package/server/service/reference/twin-reference.ts +0 -190
- package/server/service/twin-attention/index.ts +0 -3
- package/server/service/twin-attention/twin-attention-query.ts +0 -70
- package/server/service/twin-audit/command-audit.ts +0 -114
- package/server/service/twin-audit/index.ts +0 -5
- package/server/service/twin-audit/twin-audit-event.ts +0 -158
- package/server/service/twin-audit/twin-audit-query.ts +0 -72
- package/server/service/twin-backfill/backfill-period-facts.ts +0 -168
- package/server/service/twin-backfill/backfill-shape.ts +0 -86
- package/server/service/twin-backfill/index.ts +0 -3
- package/server/service/twin-backfill/twin-backfill-resolver.ts +0 -35
- package/server/service/twin-control/index.ts +0 -3
- package/server/service/twin-control/twin-control-mutation.ts +0 -150
- package/server/service/twin-event/index.ts +0 -3
- package/server/service/twin-event/journal-count.ts +0 -53
- package/server/service/twin-event/twin-event-keys.ts +0 -215
- package/server/service/twin-event/twin-event-type.ts +0 -68
- package/server/service/twin-event/twin-event.ts +0 -250
- package/server/service/twin-forecast/forecast-metrics.ts +0 -106
- package/server/service/twin-forecast/forecast-tuning.ts +0 -40
- package/server/service/twin-forecast/gap-analytics.ts +0 -139
- package/server/service/twin-forecast/index.ts +0 -3
- package/server/service/twin-forecast/twin-forecast-query.ts +0 -486
- package/server/service/twin-ingest-window/index.ts +0 -7
- package/server/service/twin-ingest-window/twin-ingest-window-query.ts +0 -125
- package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +0 -57
- package/server/service/twin-ingest-window/twin-ingest-window.ts +0 -113
- package/server/service/twin-instance/index.ts +0 -3
- package/server/service/twin-instance/twin-instance.ts +0 -199
- package/server/service/twin-journal/event-type-split-shape.ts +0 -112
- package/server/service/twin-journal/event-type-split.ts +0 -144
- package/server/service/twin-journal/index.ts +0 -3
- package/server/service/twin-journal/journal-order.ts +0 -20
- package/server/service/twin-journal/twin-journal-query.ts +0 -615
- package/server/service/twin-lifecycle/domain-catalog.ts +0 -51
- package/server/service/twin-lifecycle/index.ts +0 -3
- package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +0 -285
- package/server/service/twin-metrics/index.ts +0 -3
- package/server/service/twin-metrics/twin-metrics-query.ts +0 -172
- package/server/service/twin-model/axis-journal-evidence.ts +0 -57
- package/server/service/twin-model/choose-recipe.ts +0 -31
- package/server/service/twin-model/epcis-coverage.ts +0 -251
- package/server/service/twin-model/external-resolver.ts +0 -173
- package/server/service/twin-model/iec61850-coverage.ts +0 -111
- package/server/service/twin-model/index.ts +0 -25
- package/server/service/twin-model/isa95-coverage.ts +0 -320
- package/server/service/twin-model/item-ref.ts +0 -80
- package/server/service/twin-model/name-index.ts +0 -94
- package/server/service/twin-model/project-structure.ts +0 -213
- package/server/service/twin-model/standard-coverage.ts +0 -35
- package/server/service/twin-model/status-tally.ts +0 -37
- package/server/service/twin-model/twin-equipment.ts +0 -191
- package/server/service/twin-model/twin-lineage-query.ts +0 -327
- package/server/service/twin-model/twin-location.ts +0 -147
- package/server/service/twin-model/twin-model-item-query.ts +0 -1029
- package/server/service/twin-model/twin-model-mutation.ts +0 -503
- package/server/service/twin-model/twin-model-query.ts +0 -792
- package/server/service/twin-model/twin-model-tree-query.ts +0 -211
- package/server/service/twin-model/twin-operation.ts +0 -157
- package/server/service/twin-readiness/index.ts +0 -3
- package/server/service/twin-readiness/twin-readiness-query.ts +0 -96
- package/server/service/twin-space/area-resolver.ts +0 -75
- package/server/service/twin-space/index.ts +0 -8
- package/server/service/twin-space/move-space.ts +0 -262
- package/server/service/twin-space/representation-role.ts +0 -15
- package/server/service/twin-space/space-integrity.ts +0 -293
- package/server/service/twin-space/twin-area.ts +0 -63
- package/server/service/twin-space/twin-space-area.ts +0 -66
- package/server/service/twin-space/twin-space-representation.ts +0 -99
- package/server/service/twin-space/twin-space-resolver.ts +0 -582
- package/server/service/twin-space/twin-space.ts +0 -148
- package/server/service/twin-state/index.ts +0 -3
- package/server/service/twin-state/twin-state-subscription.ts +0 -62
- package/server/service/twin-structure/index.ts +0 -3
- package/server/service/twin-structure/twin-structure.ts +0 -96
- package/server/service/twin-subject/event-subjects.ts +0 -162
- package/server/service/twin-subject/index.ts +0 -10
- package/server/service/twin-subject/item-resolver.ts +0 -92
- package/server/service/twin-subject/subject-query-shape.ts +0 -84
- package/server/service/twin-subject/twin-subject-backfill.ts +0 -196
- package/server/service/twin-subject/twin-subject-event.ts +0 -101
- package/server/service/twin-subject/twin-subject-fast-path.ts +0 -346
- package/server/service/twin-subject/twin-subject-query.ts +0 -210
- package/server/service/twin-subject/twin-subject-writer.ts +0 -189
- package/server/service/twin-target/index.ts +0 -5
- package/server/service/twin-target/twin-target-resolver.ts +0 -142
- package/server/service/twin-target/twin-target.ts +0 -97
- package/server/types/global.d.ts +0 -22
- package/shared/axis-read.ts +0 -28
- package/shared/entity-delta.ts +0 -335
- package/shared/kpi-broadcast.ts +0 -13
- package/shared/touched-items.ts +0 -73
- package/shared/twin-level.ts +0 -48
- package/test/ack-shape-alignment.test.ts +0 -97
- package/test/actuation-advisor.test.ts +0 -55
- package/test/actuation-approval-door.test.ts +0 -411
- package/test/actuation-dispatch.test.ts +0 -209
- package/test/actuation-effect.test.ts +0 -162
- package/test/actuation-outcome.test.ts +0 -152
- package/test/actuation-rule-runner.test.ts +0 -281
- package/test/actuation-rule.test.ts +0 -266
- package/test/actuation-seam.test.ts +0 -255
- package/test/actuation-settle.test.ts +0 -164
- package/test/actuation-target.test.ts +0 -145
- package/test/actuation-verification-state.test.ts +0 -139
- package/test/adopt-structure-live.test.ts +0 -133
- package/test/aggregate-not-findone.test.ts +0 -112
- package/test/area-resolver-db.test.ts +0 -110
- package/test/attention-digest.test.ts +0 -161
- package/test/axis-declaration-passthrough-db.test.ts +0 -152
- package/test/axis-journal-evidence.test.ts +0 -71
- package/test/axis-read.test.ts +0 -188
- package/test/backfill-shape.test.ts +0 -89
- package/test/boot-resume.test.ts +0 -287
- package/test/broadcast-cost-baseline.test.ts +0 -201
- package/test/broadcast-period.test.ts +0 -58
- package/test/broadcast-queue-overflow.test.ts +0 -244
- package/test/canonical-ingest-vocabularies.test.ts +0 -451
- package/test/canonical-quantity-door.test.ts +0 -61
- package/test/capability-mapping.test.ts +0 -89
- package/test/checkpoint-refuses-empty.test.ts +0 -103
- package/test/choose-recipe.test.ts +0 -117
- package/test/column-type-portability.test.ts +0 -122
- package/test/command-routing.test.ts +0 -61
- package/test/command-store-writes-columns.test.ts +0 -126
- package/test/connection-portability-doors.test.ts +0 -87
- package/test/connector-capability-declaration.test.ts +0 -195
- package/test/contract-layer-guard.test.ts +0 -48
- package/test/control-capability.test.ts +0 -98
- package/test/cursor-stall-not-read-failure.test.ts +0 -126
- package/test/declaration-reaches-model.test.ts +0 -226
- package/test/declared-location-types.test.ts +0 -89
- package/test/declared-stimulus.test.ts +0 -88
- package/test/dedupe-transformation.test.ts +0 -112
- package/test/discovery-result.test.ts +0 -75
- package/test/dispatch-after-approval-source.test.ts +0 -81
- package/test/duration-estimators.test.ts +0 -144
- package/test/energy-topology.test.ts +0 -113
- package/test/entity-delta.test.ts +0 -352
- package/test/equipment-identity-reaches.test.ts +0 -57
- package/test/event-subjects.test.ts +0 -148
- package/test/event-time-column.test.ts +0 -67
- package/test/event-type-split.test.ts +0 -178
- package/test/external-resolver.test.ts +0 -177
- package/test/fact-scope-wiring.test.ts +0 -96
- package/test/fill-dedupe.test.ts +0 -59
- package/test/fill-loop.test.ts +0 -35
- package/test/first-envelope.test.ts +0 -153
- package/test/fold-gap-speaks.test.ts +0 -53
- package/test/fold-shift-dst.test.ts +0 -110
- package/test/forecast-metrics.test.ts +0 -157
- package/test/forecast-tuning.test.ts +0 -42
- package/test/gap-analytics.test.ts +0 -113
- package/test/generated-not-counted.test.ts +0 -99
- package/test/guard-roots.ts +0 -76
- package/test/home-in-area.test.ts +0 -90
- package/test/hook-address.test.ts +0 -28
- package/test/hook-rejected-shape.test.ts +0 -86
- package/test/hook-response-sum.test.ts +0 -193
- package/test/hook-sequence.test.ts +0 -333
- package/test/ingest-bench.test.ts +0 -70
- package/test/ingest-dedupe.test.ts +0 -56
- package/test/ingest-expected-quiet.test.ts +0 -111
- package/test/ingest-health-engine.test.ts +0 -248
- package/test/ingest-health-wiring.test.ts +0 -120
- package/test/ingest-health.test.ts +0 -306
- package/test/ingest-history.test.ts +0 -247
- package/test/ingest-idempotent.test.ts +0 -211
- package/test/ingest-reconcile-four-ways.test.ts +0 -97
- package/test/ingest-rules-header.test.ts +0 -100
- package/test/ingest-running-guard.test.ts +0 -136
- package/test/ingest-space.test.ts +0 -78
- package/test/ingest-window-rolls-unobserved.test.ts +0 -72
- package/test/ingest-wiring-guard.test.ts +0 -197
- package/test/instance-cache-lifecycle.test.ts +0 -110
- package/test/intake-mapping-parity.test.ts +0 -175
- package/test/integration-probes.test.ts +0 -103
- package/test/integration-runner.test.ts +0 -95
- package/test/item-ref.test.ts +0 -78
- package/test/journal-order-axis.test.ts +0 -80
- package/test/journal-read-discipline.test.ts +0 -186
- package/test/journal-retention.test.ts +0 -275
- package/test/journal-sort-axis.test.ts +0 -142
- package/test/journal-write-door.test.ts +0 -110
- package/test/journal-write-trend.test.ts +0 -115
- package/test/kernel-kind-guard.test.ts +0 -98
- package/test/knob-defaults.test.ts +0 -72
- package/test/kpi-baseline-db.test.ts +0 -216
- package/test/kpi-baseline.test.ts +0 -196
- package/test/kpi-fold.test.ts +0 -1456
- package/test/kpi-query-bench.test.ts +0 -130
- package/test/lens-own-places.test.ts +0 -50
- package/test/lineage-survives-restart.test.ts +0 -234
- package/test/live-cadence.test.ts +0 -170
- package/test/live-cursor-wiring.test.ts +0 -87
- package/test/live-feed-lease.test.ts +0 -63
- package/test/live-feed-registry.test.ts +0 -75
- package/test/live-kernel-facts.test.ts +0 -161
- package/test/live-mirror-parity.test.ts +0 -286
- package/test/load-meter.test.ts +0 -328
- package/test/local-declarations.test.ts +0 -662
- package/test/log-stamp.test.ts +0 -59
- package/test/loop-lag.test.ts +0 -82
- package/test/master-to-twin.test.ts +0 -279
- package/test/measured-yield.test.ts +0 -90
- package/test/merge-streams.test.ts +0 -70
- package/test/mirror-resumes-from-checkpoint.test.ts +0 -192
- package/test/model-basis.test.ts +0 -141
- package/test/model-gap.test.ts +0 -153
- package/test/model-refusal.test.ts +0 -75
- package/test/model-vocabulary.test.ts +0 -114
- package/test/move-space.test.ts +0 -149
- package/test/mutation-gate.test.ts +0 -122
- package/test/oee-accumulator.test.ts +0 -204
- package/test/oee-site-calendar.test.ts +0 -146
- package/test/open-doors.test.ts +0 -197
- package/test/operation-basis.test.ts +0 -127
- package/test/operational-vocabulary.test.ts +0 -108
- package/test/operations-capability-db.test.ts +0 -165
- package/test/order-and-transaction-split.test.ts +0 -107
- package/test/order-fold-host.test.ts +0 -112
- package/test/producer-guard.test.ts +0 -66
- package/test/project-structure-db.test.ts +0 -226
- package/test/projection-reaches-screen.test.ts +0 -277
- package/test/projection-reads-declared.test.ts +0 -109
- package/test/property-effects.test.ts +0 -128
- package/test/provenance-promotion.test.ts +0 -99
- package/test/read-failure-ledger.test.ts +0 -106
- package/test/read-failure-visible.test.ts +0 -145
- package/test/read-time.test.ts +0 -118
- package/test/reference-fill.test.ts +0 -235
- package/test/reference-grounding.test.ts +0 -70
- package/test/reference-hook.test.ts +0 -177
- package/test/reference-links.test.ts +0 -56
- package/test/reference-reconciliation.test.ts +0 -39
- package/test/registry-key-guard.test.ts +0 -80
- package/test/rejection-carries-event-id.test.ts +0 -101
- package/test/rename-twin.test.ts +0 -89
- package/test/resolve-ts-siblings.mjs +0 -52
- package/test/restart-policy.test.ts +0 -111
- package/test/resync-origin-site.test.ts +0 -83
- package/test/retry-plan.test.ts +0 -139
- package/test/revision-axis.test.ts +0 -110
- package/test/runtime-key.test.ts +0 -66
- package/test/save-intake-collision.test.ts +0 -91
- package/test/scale-twin-bench.test.ts +0 -103
- package/test/secrets-at-rest.test.ts +0 -135
- package/test/snapshot-freshness.test.ts +0 -60
- package/test/source-outcome-audit.test.ts +0 -104
- package/test/space-integrity.test.ts +0 -223
- package/test/space-representation.test.ts +0 -66
- package/test/space-scope-includes-stopped.test.ts +0 -55
- package/test/spec-coverage.test.ts +0 -113
- package/test/stage-path.test.ts +0 -95
- package/test/standard-coverage.test.ts +0 -148
- package/test/state-axes.test.ts +0 -74
- package/test/status-tally.test.ts +0 -55
- package/test/streamline-e2e.test.ts +0 -76
- package/test/structure-revision-db.test.ts +0 -315
- package/test/subject-fast-path.test.ts +0 -148
- package/test/subject-read-model.test.ts +0 -175
- package/test/sweep-dispatch.test.ts +0 -191
- package/test/tenant-registry-db.test.ts +0 -149
- package/test/time-range.test.ts +0 -152
- package/test/touched-items.test.ts +0 -61
- package/test/twin-audit.test.ts +0 -83
- package/test/twin-event-keys.test.ts +0 -193
- package/test/twin-model-item-db.test.ts +0 -319
- package/test/twin-model-parent-relation-db.test.ts +0 -125
- package/test/twin-model-tree-db.test.ts +0 -209
- package/test/twin-origin-resync.test.ts +0 -133
- package/test/twin-state-channel.test.ts +0 -111
- package/test/vocabulary-guard.test.ts +0 -43
- package/test/warm-start-seam.test.ts +0 -162
- package/test/warm-start.test.ts +0 -297
- package/test/withheld-door.test.ts +0 -95
- package/test/yield-loop.test.ts +0 -199
- package/tsconfig.json +0 -15
- package/tsconfig.shared.json +0 -23
- package/tsconfig.shared.tsbuildinfo +0 -1
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* 구간 성과 질의 비용 측정 — **브로드캐스팅이냐 질의냐를 숫자로 정한다.**
|
|
3
|
-
*
|
|
4
|
-
* ── 왜 재는가 (2026-08-06) ─────────────────────────────────────────────────
|
|
5
|
-
* 성과 카드를 여러 단계(공간·트윈·구역·자리·설비)에 붙이려 한다. 두 방법이 있다.
|
|
6
|
-
*
|
|
7
|
-
* · 브로드캐스팅 — 서버가 주기마다 전 단계를 계산해 밀어 준다. 자리가 트윈당 최대 200개고 지표가 6개라
|
|
8
|
-
* 태그가 1,200개가 된다. **모델에 카드를 하나도 안 놓아도 계산은 돈다.**
|
|
9
|
-
* · 질의 — 카드가 필요할 때 묻는다. **모델에 놓인 카드 수만큼만** 든다. 시각(`toTime`)도 물을 수 있어
|
|
10
|
-
* 타임라인과 맞고, 공간 단위 합산(여러 트윈을 한 번에 계산)은 질의에만 있다.
|
|
11
|
-
*
|
|
12
|
-
* 질의로 정하려면 **한 번의 비용**을 알아야 한다. 카드 20장이 30초마다 물으면 감당되는지가 결정을
|
|
13
|
-
* 가른다. 짐작하지 않고 잰다.
|
|
14
|
-
*
|
|
15
|
-
* 빌드 산출물을 실행한다 — **소스를 고친 뒤에는 `npm run build:server` 를 먼저 돌린다.**
|
|
16
|
-
*/
|
|
17
|
-
import { test, before, after } from 'node:test'
|
|
18
|
-
import { createRequire } from 'node:module'
|
|
19
|
-
import type { DataSource } from 'typeorm'
|
|
20
|
-
|
|
21
|
-
const req = createRequire(import.meta.url)
|
|
22
|
-
const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
|
|
23
|
-
const { entities: authEntities } = req('@things-factory/auth-base')
|
|
24
|
-
const { entities: twinEntities } = req('../dist-server/service/index.js')
|
|
25
|
-
const { computeTwinKpi } = req('../dist-server/engine/index.js')
|
|
26
|
-
const { TwinEvent } = req('../dist-server/service/twin-event/twin-event.js')
|
|
27
|
-
const { TwinInstance } = req('../dist-server/service/twin-instance/twin-instance.js')
|
|
28
|
-
const { DataSource: TypeOrmDataSource } = req('typeorm')
|
|
29
|
-
|
|
30
|
-
let ds: DataSource
|
|
31
|
-
let domainId: string
|
|
32
|
-
|
|
33
|
-
const INSTANCE = 'kpi-bench'
|
|
34
|
-
const TO = Date.parse('2026-03-10T10:00:00.000Z')
|
|
35
|
-
const WINDOW_MIN = 60
|
|
36
|
-
|
|
37
|
-
/** 자리 200개 — 실측한 최대 규모(트윈당 자리 최대 200, 평균 19). */
|
|
38
|
-
const LOCATIONS = 200
|
|
39
|
-
/** 창 안의 완료 작업 수 — 한 건이 두 줄(시작·완료)이라 이벤트는 두 배가 된다. */
|
|
40
|
-
const TASK_COUNTS = [500, 2_000, 10_000]
|
|
41
|
-
|
|
42
|
-
function taskRows(count: number, revBase: number) {
|
|
43
|
-
const rows: any[] = []
|
|
44
|
-
for (let i = 0; i < count; i++) {
|
|
45
|
-
const done = TO - 60_000 - (i % (WINDOW_MIN * 60)) * 1000
|
|
46
|
-
const started = done - 30_000
|
|
47
|
-
const at = `loc-${i % LOCATIONS}`
|
|
48
|
-
rows.push(
|
|
49
|
-
{
|
|
50
|
-
domain: { id: domainId },
|
|
51
|
-
instanceId: INSTANCE,
|
|
52
|
-
revision: revBase + i * 2,
|
|
53
|
-
eventType: 'task.status',
|
|
54
|
-
eventTime: new Date(started).toISOString(),
|
|
55
|
-
payload: { data: { taskId: `t-${i}`, status: 'in-progress', resourceRef: 'fk-1', locationRef: at } }
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
domain: { id: domainId },
|
|
59
|
-
instanceId: INSTANCE,
|
|
60
|
-
revision: revBase + i * 2 + 1,
|
|
61
|
-
eventType: 'task.status',
|
|
62
|
-
eventTime: new Date(done).toISOString(),
|
|
63
|
-
payload: { data: { taskId: `t-${i}`, status: 'completed', resourceRef: 'fk-1', locationRef: at } }
|
|
64
|
-
}
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
return rows
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
before(async () => {
|
|
71
|
-
ds = new TypeOrmDataSource({
|
|
72
|
-
type: 'sqlite',
|
|
73
|
-
database: ':memory:',
|
|
74
|
-
synchronize: true,
|
|
75
|
-
dropSchema: true,
|
|
76
|
-
namingStrategy: new NamingStrategy(),
|
|
77
|
-
entities: [...shellEntities, ...authEntities, ...twinEntities],
|
|
78
|
-
logging: false
|
|
79
|
-
})
|
|
80
|
-
await ds.initialize()
|
|
81
|
-
addDataSource('default', ds)
|
|
82
|
-
const d = await ds.getRepository(Domain).save({ name: 'kpi-bench', subdomain: 'kpi-bench' } as any)
|
|
83
|
-
domainId = d.id
|
|
84
|
-
|
|
85
|
-
/* 자리 계층 — 자리 200개를 구역 4개에 나눠 붙인다(구역 단위 계산 비용도 재려면 부모가 있어야 한다). */
|
|
86
|
-
const locations = Array.from({ length: LOCATIONS }, (_, i) => ({
|
|
87
|
-
id: `loc-${i}`,
|
|
88
|
-
type: 'storage',
|
|
89
|
-
capacity: 10,
|
|
90
|
-
parentId: `area-${i % 4}`
|
|
91
|
-
}))
|
|
92
|
-
await ds.getRepository(TwinInstance).save({
|
|
93
|
-
domain: { id: domainId },
|
|
94
|
-
instanceId: INSTANCE,
|
|
95
|
-
kind: 'wms',
|
|
96
|
-
restartPolicy: 'reset', /* 선언은 이제 필수 — 비워 두면 읽는 자리마다 기본값을 고른다 */
|
|
97
|
-
purpose: 'operational',
|
|
98
|
-
status: 'stopped',
|
|
99
|
-
model: { locations, equipment: [{ id: 'fk-1', kind: 'forklift', homeLocation: 'loc-0' }] }
|
|
100
|
-
} as any)
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
after(async () => {
|
|
104
|
-
await ds?.destroy()
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
const ms = async (fn: () => Promise<any>) => {
|
|
108
|
-
const t = process.hrtime.bigint()
|
|
109
|
-
await fn()
|
|
110
|
-
return Number(process.hrtime.bigint() - t) / 1e6
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
test('bench: 구간 성과 폴드 한 번의 비용 vs 창 안의 작업 수', async () => {
|
|
114
|
-
let seeded = 0
|
|
115
|
-
for (const count of TASK_COUNTS) {
|
|
116
|
-
await ds.getRepository(TwinEvent).save(taskRows(count - seeded, seeded * 2 + 1000))
|
|
117
|
-
seeded = count
|
|
118
|
-
|
|
119
|
-
const args = { domainId, instanceId: INSTANCE, toTime: new Date(TO).toISOString(), windowMinutes: WINDOW_MIN }
|
|
120
|
-
await computeTwinKpi(args) // 워밍업(연결·스키마 캐시)
|
|
121
|
-
|
|
122
|
-
const plain = await ms(() => computeTwinKpi(args))
|
|
123
|
-
const byArea = await ms(() => computeTwinKpi({ ...args, groupBy: 'area' }))
|
|
124
|
-
|
|
125
|
-
console.log(` 작업 ${count.toLocaleString()}건(이벤트 ${(count * 2).toLocaleString()}줄) · 자리 ${LOCATIONS}개`)
|
|
126
|
-
console.log(` 폴드 1회 ${plain.toFixed(1)}ms`)
|
|
127
|
-
console.log(` 구역별 폴드 1회 ${byArea.toFixed(1)}ms`)
|
|
128
|
-
console.log(` 카드 20장 동시 ${(plain * 20).toFixed(0)}ms (직렬 상한 — 실제로는 한 번 계산해 나눠 쓸 수 있다)`)
|
|
129
|
-
}
|
|
130
|
-
})
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* **렌즈는 자기 영역의 자리만 세운다** — ADR-0081 보탬(수석 아키텍트 판정 2026-09-24).
|
|
3
|
-
*
|
|
4
|
-
* 사람이 보는 장면: 창고 트윈 miratek-wms 를 불러오면 「종류를 모르는 자리 assembly-line (…00007.0)」 경고가 떴다. 그 자리는 plant 의
|
|
5
|
-
* 조립 라인 자리다. 이제 창고 렌즈는 그 자리를 참조로만 들고 경고하지 않는다. 같은 기준정보를 plant 렌즈로 불러오면 도크가 참조다.
|
|
6
|
-
*/
|
|
7
|
-
import { test } from 'node:test'
|
|
8
|
-
import assert from 'node:assert/strict'
|
|
9
|
-
import { createRequire } from 'node:module'
|
|
10
|
-
|
|
11
|
-
const req = createRequire(import.meta.url)
|
|
12
|
-
const { masterToTwin } = req('../dist-server/service/reference/reference-master.js')
|
|
13
|
-
|
|
14
|
-
const CATALOG = { wms: { locationTypes: ['dock', 'storage'] }, mes: { locationTypes: ['assembly-line'] } }
|
|
15
|
-
const LINE = 'urn:epc:id:sgln:0614141.00007.0'
|
|
16
|
-
|
|
17
|
-
const master = (system: string) => ({
|
|
18
|
-
source: `ops-${system}`,
|
|
19
|
-
system,
|
|
20
|
-
siteName: 'miratek',
|
|
21
|
-
space: { spaceId: 'miratek', width: 60, depth: 30, unit: 'm' },
|
|
22
|
-
locations: [
|
|
23
|
-
{ id: 'dock-recv', type: 'dock', role: 'location' as const, system: 'wms' },
|
|
24
|
-
{ id: 'bin-1', type: 'storage', role: 'location' as const, system: 'wms' },
|
|
25
|
-
{ id: LINE, type: 'assembly-line', role: 'location' as const, system: 'mes' },
|
|
26
|
-
{ id: 'legacy', type: 'storage', role: 'location' as const }
|
|
27
|
-
],
|
|
28
|
-
equipment: []
|
|
29
|
-
})
|
|
30
|
-
const unknown = (r: any) => (r.warnings ?? []).filter((w: any) => w.code === 'unknown-location-type')
|
|
31
|
-
|
|
32
|
-
test('★ 창고 렌즈는 조립 라인 자리를 참조로 들고 경고하지 않는다', () => {
|
|
33
|
-
const r = masterToTwin(master('wms'), CATALOG)
|
|
34
|
-
assert.deepEqual(unknown(r), [], '종류 모르는 자리 경고 0')
|
|
35
|
-
assert.deepEqual(r.model.locations.map((l: any) => l.id), ['dock-recv', 'bin-1', 'legacy'])
|
|
36
|
-
assert.deepEqual(r.model.referencedLocations, [{ id: LINE, system: 'mes' }])
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
test('★ plant 렌즈로 보면 도크와 보관 자리가 참조다', () => {
|
|
40
|
-
const r = masterToTwin(master('mes'), CATALOG)
|
|
41
|
-
assert.deepEqual(r.model.locations.map((l: any) => l.id), [LINE, 'legacy'])
|
|
42
|
-
assert.deepEqual(r.model.referencedLocations.map((x: any) => x.id), ['dock-recv', 'bin-1'])
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
test('영역을 말하지 않은 원본은 지금처럼 선다 — 참조 칸을 만들지 않는다', () => {
|
|
46
|
-
const m = { ...master('wms'), locations: master('wms').locations.map(({ system, ...l }: any) => l) }
|
|
47
|
-
const r = masterToTwin(m, CATALOG)
|
|
48
|
-
assert.equal(r.model.locations.length, 4)
|
|
49
|
-
assert.equal('referencedLocations' in r.model, false)
|
|
50
|
-
})
|
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* ★ 재기동을 건너도 **계보에 입력이 남는다** — 호스트의 웜스타트 경로로 확인한다.
|
|
3
|
-
*
|
|
4
|
-
* ── 무엇이 잘못돼 있었나 ──────────────────────────────────────────────────────
|
|
5
|
-
* 오더의 진행 중 할당(`allocated`)과 거래번호(`bizTransaction`)가 상태 계약에 없어서, 웜스타트가
|
|
6
|
-
* 오더를 되살릴 때 둘 다 비운 채로 세웠다. 그 오더의 진행 중 작업이 완료되면
|
|
7
|
-
* `TransformationEvent` 가 **입력 없이** 나간다 — "무엇이 무엇으로 바뀌었나" 에서 "무엇이" 가
|
|
8
|
-
* 통째로 빠지고, 계보를 거슬러 올라갈 수 없다.
|
|
9
|
-
*
|
|
10
|
-
* 실 앱에서 변환 36건 중 35건이 입력 0 이었고 모든 이벤트의 거래번호가 빈값이었다.
|
|
11
|
-
*
|
|
12
|
-
* ── 왜 커널 검사만으로 충분하지 않나 ──────────────────────────────────────────
|
|
13
|
-
* 커널 검사는 `hydrateObserved` 로 직접 심어 확인한다. 호스트는 **저널을 재생해서** 그 씨앗을
|
|
14
|
-
* 만든다(`recover` → `replay`). 그 경로에서 한 번 더 떨어질 수 있으므로 여기서 실제로 걷는다.
|
|
15
|
-
*/
|
|
16
|
-
import { test, before, after } from 'node:test'
|
|
17
|
-
import assert from 'node:assert/strict'
|
|
18
|
-
import { createRequire } from 'node:module'
|
|
19
|
-
import type { DataSource } from 'typeorm'
|
|
20
|
-
|
|
21
|
-
const req = createRequire(import.meta.url)
|
|
22
|
-
const { NamingStrategy, addDataSource, entities: shellEntities, Domain } = req('@things-factory/shell')
|
|
23
|
-
const { entities: authEntities } = req('@things-factory/auth-base')
|
|
24
|
-
const { entities: twinEntities } = req('../dist-server/service/index.js')
|
|
25
|
-
const { TwinEngine } = req('../dist-server/engine/index.js')
|
|
26
|
-
const { TwinEvent } = req('../dist-server/service/twin-event/twin-event.js')
|
|
27
|
-
const { TwinLineageQuery } = req('../dist-server/service/twin-model/twin-lineage-query.js')
|
|
28
|
-
const { DataSource: TypeOrmDataSource } = req('typeorm')
|
|
29
|
-
|
|
30
|
-
let ds: DataSource
|
|
31
|
-
let domainId: string
|
|
32
|
-
|
|
33
|
-
const INSTANCE = 'lineage-probe'
|
|
34
|
-
const CP = '0614141'
|
|
35
|
-
const pat = (ref: string) => `urn:epc:idpat:sgtin:${CP}.${ref}.*`
|
|
36
|
-
|
|
37
|
-
/** 원자재 하나로 완제품 하나를 만드는 2단 라인 — 실제 트레일러 템플릿의 축소판. */
|
|
38
|
-
const master = (): any => ({
|
|
39
|
-
source: INSTANCE,
|
|
40
|
-
system: 'mes',
|
|
41
|
-
siteName: '계보 공장',
|
|
42
|
-
space: { width: 60, depth: 30, unit: 'm' },
|
|
43
|
-
locations: [
|
|
44
|
-
{ id: 'raw-store', type: 'raw-store', role: 'location', capacity: 500 },
|
|
45
|
-
{ id: 'cut-station', type: 'cut-station', role: 'location', capacity: 50 },
|
|
46
|
-
{ id: 'weld-station', type: 'weld-station', role: 'location', capacity: 50 },
|
|
47
|
-
{ id: 'fg-store', type: 'fg-store', role: 'location', capacity: 500 }
|
|
48
|
-
],
|
|
49
|
-
equipment: [
|
|
50
|
-
{ id: 'cutter-1', kind: 'cutter', homeLocationId: 'cut-station' },
|
|
51
|
-
{ id: 'welder-1', kind: 'welder', homeLocationId: 'weld-station' }
|
|
52
|
-
],
|
|
53
|
-
productionSpec: {
|
|
54
|
-
companyPrefix: CP,
|
|
55
|
-
binding: { steel: '077101', frame: '078101' },
|
|
56
|
-
/*
|
|
57
|
-
* 작업지시의 문서 식별자를 **이 현장이 선언한다** — 커널은 문서 타입을 정하지 않습니다(0.7.43).
|
|
58
|
-
* GDTI 는 「회사 프리픽스 + 문서 타입 + 일련번호」이고, 그 타입은 프리픽스를 배정받은 회사가
|
|
59
|
-
* 자기 번호 용량에서 배정합니다. 그러니 픽스처도 그 선언을 해야 합니다.
|
|
60
|
-
*/
|
|
61
|
-
identity: { documentTypes: { workorder: '403' } },
|
|
62
|
-
definition: {
|
|
63
|
-
/* 자재는 **자기 보관 자리를 선언한다** — 커널이 자재가 놓이는 자리를 지어내지 않습니다(0.7.43). */
|
|
64
|
-
materials: [
|
|
65
|
-
{ key: 'steel', label: '강재', locationType: 'raw-store' },
|
|
66
|
-
{ key: 'frame', label: '프레임', locationType: 'fg-store' }
|
|
67
|
-
],
|
|
68
|
-
locationTypes: [
|
|
69
|
-
{ key: 'raw-store', label: '자재 보관' },
|
|
70
|
-
{ key: 'cut-station', label: '절단' },
|
|
71
|
-
{ key: 'weld-station', label: '용접' },
|
|
72
|
-
{ key: 'fg-store', label: '완제품 보관' }
|
|
73
|
-
],
|
|
74
|
-
routes: [{ key: 'frame-route', steps: ['cut', 'weld'] }],
|
|
75
|
-
recipes: [{ key: 'frame-recipe', label: 'f', route: 'frame-route', inputs: [{ material: 'steel', qty: 2 }], outputs: [{ material: 'frame', qty: 1 }] }],
|
|
76
|
-
operations: [
|
|
77
|
-
{ key: 'cut', label: '절단', intent: 'process', locationType: 'cut-station', resourceType: 'cutter', duration: 'PT1M' },
|
|
78
|
-
{ key: 'weld', label: '용접', intent: 'process', locationType: 'weld-station', resourceType: 'welder', duration: 'PT1M' }
|
|
79
|
-
]
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
const SCENARIO = {
|
|
85
|
-
seed: 9,
|
|
86
|
-
generators: [
|
|
87
|
-
{ kind: 'inbound-arrival', stimulus: 'arrival', rate: { distribution: 'constant', meanPerHour: 3600 },
|
|
88
|
-
content: { skuMix: [{ gtin: pat('077101'), weight: 1 }], qtyPerLine: { min: 1, max: 1 } } },
|
|
89
|
-
{ kind: 'production-order', stimulus: 'order', rate: { distribution: 'constant', meanPerHour: 120 },
|
|
90
|
-
content: { skuMix: [{ gtin: pat('078101'), weight: 1 }], qtyPerLine: { min: 1, max: 1 } } }
|
|
91
|
-
]
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** 저널에 남은 변환 이벤트들 — 계보가 실제로 무엇을 기록했나. */
|
|
95
|
-
async function transforms(): Promise<{ inputs: number; outputs: number; tx: string }[]> {
|
|
96
|
-
const rows: any[] = await ds.getRepository(TwinEvent).find({ where: { domain: { id: domainId } as any, instanceId: INSTANCE } as any })
|
|
97
|
-
return rows
|
|
98
|
-
.filter(r => r.eventType === 'epcis.TransformationEvent')
|
|
99
|
-
.map(r => ({
|
|
100
|
-
inputs: (r.payload?.data?.inputEPCList ?? []).length,
|
|
101
|
-
outputs: (r.payload?.data?.outputEPCList ?? []).length,
|
|
102
|
-
tx: r.payload?.data?.bizTransactionList?.[0]?.bizTransaction ?? ''
|
|
103
|
-
}))
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* 틱과 자극은 **런타임**에 있다 — `startFromRegistry` 가 돌려주는 것은 호스트의 인스턴스 기록이고
|
|
108
|
-
* 커널 런타임은 그 안에 있다(둘을 같은 것으로 보면 `scenario` 가 없다고 나온다).
|
|
109
|
-
*/
|
|
110
|
-
const runtime = () => TwinEngine.runtime(domainId, INSTANCE)
|
|
111
|
-
|
|
112
|
-
function tick(n: number): void {
|
|
113
|
-
const rt = runtime()
|
|
114
|
-
for (let i = 0; i < n; i++) rt.tick(1000)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* 상태는 런타임의 `resync()` 로 얻는다 — `{ revision, state }` 를 돌려주므로 축은 그 **안에** 있다.
|
|
119
|
-
* (`TwinEngine.snapshot` 도 이것을 그대로 넘겨 주므로 축이 한 겹 안에 들어 있다.)
|
|
120
|
-
*/
|
|
121
|
-
const orders = () => ((runtime().resync().state?.orders ?? []) as any[])
|
|
122
|
-
|
|
123
|
-
function drive(): void {
|
|
124
|
-
const rt = runtime()
|
|
125
|
-
rt.scenario.load(SCENARIO)
|
|
126
|
-
rt.scenario.start()
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
before(async () => {
|
|
130
|
-
ds = new TypeOrmDataSource({
|
|
131
|
-
type: 'sqlite',
|
|
132
|
-
database: ':memory:',
|
|
133
|
-
synchronize: true,
|
|
134
|
-
dropSchema: true,
|
|
135
|
-
namingStrategy: new NamingStrategy(),
|
|
136
|
-
entities: [...shellEntities, ...authEntities, ...twinEntities],
|
|
137
|
-
logging: false
|
|
138
|
-
})
|
|
139
|
-
await ds.initialize()
|
|
140
|
-
addDataSource('default', ds)
|
|
141
|
-
const d = await ds.getRepository(Domain).save({ name: 'lineage-test', subdomain: 'lineage-test' } as any)
|
|
142
|
-
domainId = d.id
|
|
143
|
-
await TwinEngine.ingestMaster(domainId, master(), 'reset')
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
after(async () => {
|
|
147
|
-
await TwinEngine.stop(domainId, INSTANCE).catch(() => {})
|
|
148
|
-
await ds?.destroy()
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
test('재기동을 건너도 계보에 입력이 실린다 — 웜스타트가 확보분을 잃지 않는다', async () => {
|
|
152
|
-
/* ① 한 번 굴려 진행 중 할당을 만든다. */
|
|
153
|
-
await TwinEngine.startFromRegistry(domainId, INSTANCE, 'resume')
|
|
154
|
-
drive()
|
|
155
|
-
tick(200)
|
|
156
|
-
const workingBefore = orders().filter(o => (o.allocated ?? []).length)
|
|
157
|
-
assert.ok(workingBefore.length, '진행 중 확보분이 있어야 이 검사가 뜻이 있다')
|
|
158
|
-
|
|
159
|
-
/* ② 멈추고 **저널을 재생해** 다시 세운다 — 호스트의 웜스타트 경로 그대로. */
|
|
160
|
-
await TwinEngine.stop(domainId, INSTANCE)
|
|
161
|
-
await TwinEngine.startFromRegistry(domainId, INSTANCE, 'resume')
|
|
162
|
-
|
|
163
|
-
const revived = orders().filter(o => (o.allocated ?? []).length)
|
|
164
|
-
assert.ok(revived.length, '되살아난 오더가 확보분을 들고 있어야 한다 — 잃으면 계보의 입력이 빈다')
|
|
165
|
-
|
|
166
|
-
/* ③ 되살아난 작업이 끝날 만큼 더 굴린다. */
|
|
167
|
-
drive()
|
|
168
|
-
tick(300)
|
|
169
|
-
|
|
170
|
-
const all = await transforms()
|
|
171
|
-
assert.ok(all.length, '변환이 저널에 남아야 이 검사가 뜻이 있다')
|
|
172
|
-
const withInputs = all.filter(t => t.inputs > 0)
|
|
173
|
-
assert.ok(withInputs.length, '입력이 실린 변환이 하나도 없다 — 계보의 "어디서 왔나" 가 통째로 빈다')
|
|
174
|
-
|
|
175
|
-
/* 거래번호도 함께 — 계보가 **무슨 거래로** 일어났는지 잇는 축이다. */
|
|
176
|
-
assert.ok(all.some(t => t.tx), '거래번호가 전부 빈값이다 — 계보를 거래로 이을 수 없다')
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
test('계보를 거슬러 올라가 선언과 나란히 놓는다 — 그 차이가 진단이다', async () => {
|
|
180
|
-
const q = new TwinLineageQuery()
|
|
181
|
-
const ctx = { state: { domain: { id: domainId } } } as any
|
|
182
|
-
|
|
183
|
-
/* 완제품 하나를 고른다 — 저널이 그것을 산출로 실은 변환이 있어야 계보가 있다. */
|
|
184
|
-
const rows: any[] = await ds.getRepository(TwinEvent).find({ where: { domain: { id: domainId } as any, instanceId: INSTANCE } as any })
|
|
185
|
-
/* **완제품**을 고른다. 변환에는 중간 산물(WIP)을 내는 것도 있어서 아무거나 집으면 WIP 이 잡히고,
|
|
186
|
-
WIP 은 선언된 자재가 아니라 라우트의 내부 산물이므로 견줄 대상이 아니다. */
|
|
187
|
-
const made = rows
|
|
188
|
-
.filter(r => r.eventType === 'epcis.TransformationEvent' && (r.payload?.data?.inputEPCList ?? []).length)
|
|
189
|
-
.flatMap(r => r.payload.data.outputEPCList ?? [])
|
|
190
|
-
.filter((e: string) => e.includes(`.078101.`))
|
|
191
|
-
assert.ok(made.length, '완제품을 낸 변환이 있어야 이 검사가 뜻이 있다')
|
|
192
|
-
|
|
193
|
-
const lin = await q.twinItemLineage(INSTANCE, made[0], ctx)
|
|
194
|
-
assert.ok(lin, '계보가 나와야 한다')
|
|
195
|
-
assert.equal(lin.epc, made[0])
|
|
196
|
-
assert.ok(lin.items.length > 1, '거슬러 올라간 것이 있어야 한다 — 하나면 아무것도 안 찾은 것이다')
|
|
197
|
-
assert.ok(lin.edges.some((e: any) => e.from === made[0]), '이 개체를 만든 직접 투입이 보여야 한다')
|
|
198
|
-
|
|
199
|
-
/* 근거를 밝힌다 — 창을 넘겨 끊겼으면 계보가 실제보다 얕게 보인다. */
|
|
200
|
-
assert.equal(lin.basis.source, 'journal')
|
|
201
|
-
assert.equal(typeof lin.basis.transformationsRead, 'number')
|
|
202
|
-
|
|
203
|
-
/* **겹쳐 보기** — 선언(레시피)과 관측(실제 투입)을 자재별로 나란히. */
|
|
204
|
-
assert.equal(lin.conformance.comparable, true, `견줄 수 없으면 이유를 말한다: ${lin.conformance?.reason}`)
|
|
205
|
-
const steel = lin.conformance.lines.find((l: any) => l.material === 'steel')
|
|
206
|
-
assert.ok(steel, '레시피가 선언한 자재가 줄로 나와야 한다')
|
|
207
|
-
assert.equal(steel.declared, 2, '레시피는 강재 2개를 요구한다')
|
|
208
|
-
assert.equal(steel.observed, 2, '실제로도 2개를 먹었다 — 설계대로다')
|
|
209
|
-
assert.equal(steel.matches, true)
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
test('★ 만든 것을 관측하지 못했으면 「다르다」고 하지 않는다 — 안 본 것과 어긋난 것은 다른 사실이다', async () => {
|
|
213
|
-
const q = new TwinLineageQuery()
|
|
214
|
-
const ctx = { state: { domain: { id: domainId } } } as any
|
|
215
|
-
/*
|
|
216
|
-
* 완제품 클래스의 개체이지만 저널에 그것을 낸 변환이 없다 — 자재로도 이어지고 레시피도 하나다.
|
|
217
|
-
* 예전에는 여기서 셈이 그대로 돌아 관측을 전부 0 으로 적고 「레시피와 다릅니다」를 냈다
|
|
218
|
-
* (2026-09-18 :3000 에서 카메라 로트 23 줄이 그렇게 보였다).
|
|
219
|
-
*/
|
|
220
|
-
const lin = await q.twinItemLineage(INSTANCE, `urn:epc:id:sgtin:${CP}.078101.999999`, ctx)
|
|
221
|
-
assert.equal(lin.conformance.comparable, false, `관측이 없는데 견주었다: ${JSON.stringify(lin.conformance?.lines?.slice(0, 2))}`)
|
|
222
|
-
assert.equal(lin.conformance.reason, 'made-not-observed')
|
|
223
|
-
assert.ok(lin.conformance.recipe, '어느 레시피와 견주려 했는지는 말한다 — 사람이 다음 걸음을 안다')
|
|
224
|
-
assert.equal(lin.basis.transformationsRead >= 0, true)
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
test('바인딩이 없으면 비교하지 않고 이유를 알린다 — 짐작으로 이으면 거짓 진단이 된다', async () => {
|
|
228
|
-
const q = new TwinLineageQuery()
|
|
229
|
-
const ctx = { state: { domain: { id: domainId } } } as any
|
|
230
|
-
/* 개체이긴 하지만 바인딩에 없는 품목 — 짐작으로 자재에 붙이면 "설계와 다르다" 는 거짓이 나온다. */
|
|
231
|
-
const lin = await q.twinItemLineage(INSTANCE, `urn:epc:id:sgtin:${CP}.099999.1`, ctx)
|
|
232
|
-
assert.equal(lin.conformance.comparable, false)
|
|
233
|
-
assert.equal(lin.conformance.reason, 'item-not-bound')
|
|
234
|
-
})
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* ★ **원천마다 시간의 결이 다르다** — 밤마다 나던 거짓 빨강의 나머지 반쪽.
|
|
3
|
-
*
|
|
4
|
-
* 판정은 이미 두 값을 받을 수 있다(`syncVerdictOf` 의 `expectedSilenceMs`·`quietNow`). 없던 것은
|
|
5
|
-
* **원천이 그것을 말할 자리**였다. 인티그레이션 레인이 다섯을 재 왔다.
|
|
6
|
-
*
|
|
7
|
-
* ppms 발전 일몰에 멈춘다 — 두 사이트가 같은 분 19:25 에 함께
|
|
8
|
-
* ppms 계측 밤에도 온다 · 15분마다
|
|
9
|
-
* ppms 가격 화·목만 거래된다 · 그 날 하루 한 번
|
|
10
|
-
* plant 근무시간 창 · 훅이라 「보내면 온다」
|
|
11
|
-
* chef 조업시간 창 · 같음
|
|
12
|
-
*
|
|
13
|
-
* 셋이 다 다르다 — 해에 매인 것, 사람 근무에 매인 것, 거래일에 매인 것. 그런데 **두 축으로
|
|
14
|
-
* 덮인다**: 「지금이 활동 시각인가」와 「그 안에서 얼마나 뜸한가」.
|
|
15
|
-
*/
|
|
16
|
-
import { test } from 'node:test'
|
|
17
|
-
import assert from 'node:assert/strict'
|
|
18
|
-
|
|
19
|
-
import { cadenceOf, ingestExpectation, type LiveCadence } from '../server/service/reference/live-cadence.js'
|
|
20
|
-
|
|
21
|
-
const NOW = 1_800_000_000_000
|
|
22
|
-
|
|
23
|
-
/* ── 축을 찾는다 ──────────────────────────────────────────────────────────── */
|
|
24
|
-
|
|
25
|
-
test('★ 선언한 축을 찾는다', () => {
|
|
26
|
-
const cadences: LiveCadence[] = [
|
|
27
|
-
{ axis: 'equipment.status', windowKind: 'daylight' },
|
|
28
|
-
{ axis: 'quality.output', expectedSilenceMs: 900_000 }
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
assert.equal(cadenceOf(cadences, 'quality.output')?.expectedSilenceMs, 900_000)
|
|
32
|
-
assert.equal(cadenceOf(cadences, 'equipment.status')?.windowKind, 'daylight')
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('★ 선언하지 않은 축은 없다고 답한다 — 옛 거동으로 견주게', () => {
|
|
36
|
-
assert.equal(cadenceOf([{ axis: 'quality.output' }], 'order.status'), undefined)
|
|
37
|
-
assert.equal(cadenceOf(undefined, 'quality.output'), undefined)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
/* ── 판정에 넘길 두 값으로 옮긴다 ───────────────────────────────────────── */
|
|
41
|
-
|
|
42
|
-
test('★ 선언이 없으면 아무것도 답하지 않는다 — 「모른다」를 「안 와도 된다」로 접지 않는다', () => {
|
|
43
|
-
/*
|
|
44
|
-
* 여기서 `quietNow: true` 를 내면 **선언 안 한 원천이 전부 조용해진다.** 정말 끊긴 것도
|
|
45
|
-
* 조용해지고, 그러면 이 축을 만든 목적을 잃는다.
|
|
46
|
-
*/
|
|
47
|
-
assert.deepEqual(ingestExpectation(undefined, { nowMs: NOW }), {})
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
test('★ 15분마다 긷는 원천 — 주기만 넘긴다', () => {
|
|
51
|
-
const out = ingestExpectation({ axis: 'quality.output', expectedSilenceMs: 900_000 }, { nowMs: NOW })
|
|
52
|
-
|
|
53
|
-
assert.equal(out.expectedSilenceMs, 900_000)
|
|
54
|
-
assert.equal(out.quietNow, undefined, '창을 선언하지 않았는데 시각을 단언했다')
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
test('0이나 음수 주기는 선언이 아니다', () => {
|
|
58
|
-
for (const bad of [0, -1, NaN]) {
|
|
59
|
-
const out = ingestExpectation({ axis: 'a', expectedSilenceMs: bad }, { nowMs: NOW })
|
|
60
|
-
assert.equal(out.expectedSilenceMs, undefined, `${bad} 를 주기로 받았다`)
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
/* ── 「보내면 온다」 ──────────────────────────────────────────────────────── */
|
|
65
|
-
|
|
66
|
-
test('★ 훅으로 미는 축은 침묵으로 판정하지 않는다 — plant 가 그렇다', () => {
|
|
67
|
-
/*
|
|
68
|
-
* 보낼 것이 없으면 안 보내는 것이 정상이다. 「주기가 없다」와 「모른다」를 가르는 값이다.
|
|
69
|
-
*/
|
|
70
|
-
const out = ingestExpectation({ axis: 'order.status', pushed: true }, { nowMs: NOW })
|
|
71
|
-
|
|
72
|
-
assert.equal(out.quietNow, true)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
test('★ 미는 축은 창 판정을 기다리지 않는다 — 판정 수단이 없어도 답한다', () => {
|
|
76
|
-
const out = ingestExpectation(
|
|
77
|
-
{ axis: 'order.status', pushed: true, window: [{ id: 'day', entryType: 'production', startTime: '09:00', endTime: '18:00' }] },
|
|
78
|
-
{ nowMs: NOW } /* inWindow 를 주지 않았다 */
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
assert.equal(out.quietNow, true)
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
/* ── 창 ──────────────────────────────────────────────────────────────────── */
|
|
85
|
-
|
|
86
|
-
test('★ 활동 시각 안이면 조용할 때가 아니다', () => {
|
|
87
|
-
const out = ingestExpectation(
|
|
88
|
-
{ axis: 'quality.output', window: [{ id: 'day', entryType: 'production', startTime: '09:00', endTime: '18:00' }] },
|
|
89
|
-
{ nowMs: NOW, inWindow: () => true }
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
assert.equal(out.quietNow, false)
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
test('★ 활동 시각 밖이면 조용할 때다', () => {
|
|
96
|
-
const out = ingestExpectation(
|
|
97
|
-
{ axis: 'quality.output', window: [{ id: 'day', entryType: 'production', startTime: '09:00', endTime: '18:00' }] },
|
|
98
|
-
{ nowMs: NOW, inWindow: () => false }
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
assert.equal(out.quietNow, true)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
test('★ 판정 수단을 안 받았으면 시각을 단언하지 않는다 — 지어낸 값을 만들지 않는다', () => {
|
|
105
|
-
/*
|
|
106
|
-
* 부르는 쪽이 달력 판정 함수를 주지 않았는데 우리가 「활동 시각이다」로 답하면, 창을 선언한
|
|
107
|
-
* 원천이 **창이 없는 것과 같아진다.** 그것은 조용한 실패다.
|
|
108
|
-
*/
|
|
109
|
-
const out = ingestExpectation(
|
|
110
|
-
{ axis: 'quality.output', window: [{ id: 'day', entryType: 'production', startTime: '09:00', endTime: '18:00' }] },
|
|
111
|
-
{ nowMs: NOW }
|
|
112
|
-
)
|
|
113
|
-
|
|
114
|
-
assert.equal(out.quietNow, undefined)
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
test('빈 창은 창이 아니다', () => {
|
|
118
|
-
assert.equal(ingestExpectation({ axis: 'a', window: [] }, { nowMs: NOW, inWindow: () => false }).quietNow, undefined)
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
/* ── 두 축이 함께 온다 ──────────────────────────────────────────────────── */
|
|
122
|
-
|
|
123
|
-
test('★ 주기와 창을 같이 선언할 수 있다 — 인증서 가격이 그 모양이다', () => {
|
|
124
|
-
/*
|
|
125
|
-
* 화·목만 거래되고 그 날 하루 한 번 온다. 「매일 와야 한다」로 재면 주 5일 중 3일이 빨갛고,
|
|
126
|
-
* 「주 2회」로 재면 이어 쓴 날을 못 본다. 두 축이면 둘 다 답한다.
|
|
127
|
-
*/
|
|
128
|
-
const out = ingestExpectation(
|
|
129
|
-
{
|
|
130
|
-
axis: 'quality.output',
|
|
131
|
-
expectedSilenceMs: 26 * 3_600_000,
|
|
132
|
-
window: [
|
|
133
|
-
{ id: 'tue', entryType: 'production', startTime: '00:00', endTime: '23:59' },
|
|
134
|
-
{ id: 'thu', entryType: 'production', startTime: '00:00', endTime: '23:59' }
|
|
135
|
-
]
|
|
136
|
-
},
|
|
137
|
-
{ nowMs: NOW, inWindow: () => false }
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
assert.equal(out.expectedSilenceMs, 26 * 3_600_000)
|
|
141
|
-
assert.equal(out.quietNow, true, '거래일이 아니면 조용한 것이 정상이다')
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
/* ── 「해 있는 동안」은 호스트가 채운다 ──────────────────────────────────── */
|
|
145
|
-
|
|
146
|
-
test('★ 종류만 선언한 것으로는 창 판정을 하지 않는다 — 호스트가 채워야 한다', () => {
|
|
147
|
-
/*
|
|
148
|
-
* 커널은 일출·일몰을 계산하지 않는다(굴절·고위도·박명 정의가 다 선택이고, 정하면 방언이다).
|
|
149
|
-
* 원천은 종류만 말하고, 좌표를 아는 호스트가 날마다 구체적인 구간을 채운다.
|
|
150
|
-
*
|
|
151
|
-
* 그러니 `windowKind` 만 있고 `window` 가 비어 있으면 **아직 채워지지 않은 것**이고, 그때
|
|
152
|
-
* 판정하지 않는다. `false` 로 접으면 태양광이 밤에도 활동 시각인 것이 된다.
|
|
153
|
-
*/
|
|
154
|
-
const out = ingestExpectation({ axis: 'equipment.status', windowKind: 'daylight' }, { nowMs: NOW, inWindow: () => true })
|
|
155
|
-
|
|
156
|
-
assert.equal(out.quietNow, undefined)
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
test('★ 호스트가 채우면 그것으로 판정한다', () => {
|
|
160
|
-
const out = ingestExpectation(
|
|
161
|
-
{
|
|
162
|
-
axis: 'equipment.status',
|
|
163
|
-
windowKind: 'daylight',
|
|
164
|
-
window: [{ id: 'today', entryType: 'production', startTime: '06:12', endTime: '19:25' }]
|
|
165
|
-
},
|
|
166
|
-
{ nowMs: NOW, inWindow: () => false }
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
assert.equal(out.quietNow, true)
|
|
170
|
-
})
|