@things-factory/headless-twin 10.1.277 → 10.1.279
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,215 +0,0 @@
|
|
|
1
|
-
import { bizStepName } from '@operato/ops-contract'
|
|
2
|
-
|
|
3
|
-
import { twinWarn } from '../../engine/log.js'
|
|
4
|
-
/*
|
|
5
|
-
* 저널 검색 키 추출 — **순수**. 인제스트가 기록할 때 한 번 뽑아 인덱스 가능한 실컬럼으로 승격한다.
|
|
6
|
-
*
|
|
7
|
-
* ── 왜 승격하는가 ───────────────────────────────────────────────────────────
|
|
8
|
-
* 사용자가 저널에서 실제로 찾는 것은 "이 팔레트의 이력", "이 오더가 어디까지 갔나", "이 도크에서
|
|
9
|
-
* 무슨 일이 있었나" 다. 그런데 그 값들은 전부 `payload`(simple-json = TEXT) **안**에 있었다.
|
|
10
|
-
* things-factory 는 5개 DB 드라이버를 지원해야 해서 DB별 JSON 연산자를 쓸 수 없다 —
|
|
11
|
-
* 즉 승격 없이는 **어떤 방법으로도 서버에서 그 조건으로 거를 수 없었다**. 클라이언트가 받아온
|
|
12
|
-
* 몇 천 건 안에서만 찾는 시늉이 최선이었고, 저널이 커질수록 그 시늉은 거짓말에 가까워진다.
|
|
13
|
-
*
|
|
14
|
-
* 그래서 검색 축이 되는 값만 골라 컬럼으로 꺼낸다. payload 는 그대로 둔다(정본은 여전히 payload —
|
|
15
|
-
* 이건 파생 색인이지 새로운 진실이 아니다).
|
|
16
|
-
*
|
|
17
|
-
* ── 왜 여기(순수 모듈)인가 ──────────────────────────────────────────────────
|
|
18
|
-
* 기록 경로가 둘이다(`persistBatch` 라이브 벌크 · `persist` 심 단건). 두 곳에 각자 적으면
|
|
19
|
-
* 반드시 어긋나고, 어긋난 색인은 "없는 것처럼 보이는 이벤트" 를 만든다 — 저널에서 가장 나쁜 결함이다.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
/** 승격된 검색 키 — 전부 선택적. 뽑히지 않으면 **빈 문자열이 아니라 undefined**(결측≠빈값). */
|
|
23
|
-
export interface TwinEventKeys {
|
|
24
|
-
action?: string
|
|
25
|
-
bizStep?: string
|
|
26
|
-
epc?: string
|
|
27
|
-
orderId?: string
|
|
28
|
-
bizTransaction?: string
|
|
29
|
-
locationId?: string
|
|
30
|
-
moverId?: string
|
|
31
|
-
/** `'actual'`, `'simulated'`, or absent — absent means not declared, which is not `actual`. */
|
|
32
|
-
provenance?: string
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/*
|
|
36
|
-
* 컬럼 길이 상한. GS1 식별자(EPC URN·GDTI·SGLN)는 규격상 이보다 훨씬 짧다.
|
|
37
|
-
* 넘치는 값이 오면 **알리지 않고 자르지 않고** 경고를 남긴다 — 색인이 원본과 다르면 검색 결과가 거짓이 되는데,
|
|
38
|
-
* 그 사실이 어디에도 안 남으면 아무도 모른다.
|
|
39
|
-
*/
|
|
40
|
-
const MAX_KEY = 255
|
|
41
|
-
|
|
42
|
-
function clip(v: unknown, field: string): string | undefined {
|
|
43
|
-
if (v === undefined || v === null) return undefined
|
|
44
|
-
const s = String(v)
|
|
45
|
-
if (!s) return undefined
|
|
46
|
-
if (s.length <= MAX_KEY) return s
|
|
47
|
-
twinWarn(
|
|
48
|
-
`[twin-event-keys] ${field} exceeds ${MAX_KEY} chars and was clipped for indexing — ` +
|
|
49
|
-
`search on this value may be incomplete. payload keeps the full value. (${s.slice(0, 60)}…)`
|
|
50
|
-
)
|
|
51
|
-
return s.slice(0, MAX_KEY)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* bizStep 의 짧은 이름 — 자르는 규칙은 계약의 `bizStepName` 하나다(CBV URN 과 사설 이름공간 URL 둘 다).
|
|
56
|
-
* 없으면 이벤트 타입에서 유추(`epcis.` 접두 제거).
|
|
57
|
-
*/
|
|
58
|
-
export function bizStepOf(envelope: any): string | undefined {
|
|
59
|
-
const d = envelope?.data ?? envelope ?? {}
|
|
60
|
-
return bizStepName(d.bizStep) || String(envelope?.eventType ?? '').replace('epcis.', '') || undefined
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 품목 식별자 — **전체 값**을 저장한다(끝마디만 저장하지 않는다).
|
|
65
|
-
*
|
|
66
|
-
* 표시용 축약은 화면이 하고, 색인은 원본을 갖는다. `search` 는 부분일치(contains)라
|
|
67
|
-
* 전체를 저장해 두면 끝마디("402.2")로도 URN 전체로도 찾힌다. 반대로 끝마디만 저장하면
|
|
68
|
-
* URN 으로 찾는 경로가 사라진다.
|
|
69
|
-
*/
|
|
70
|
-
export function epcOf(envelope: any): string | undefined {
|
|
71
|
-
const d = envelope?.data ?? envelope ?? {}
|
|
72
|
-
return d.epcList?.[0] ?? d.parentID ?? d.quantityList?.[0]?.epcClass ?? undefined
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* 오더 식별자 — 운영 델타의 `orderId` 우선, EPCIS 는 `bizTransactionList`.
|
|
77
|
-
*
|
|
78
|
-
* ── 실측 (2026-08-24) — 이 컬럼이 **전부 비어 있었다** ──────────────────────
|
|
79
|
-
* 여기가 찾던 이름이 `d.order` 였다. 그런데 커널이 내는 이름은 **`orderId`** 다
|
|
80
|
-
* (`OrderStatusDelta.orderId` · `TaskStatusDelta.orderId`). `d.order` 를 내는 코드는 커널에 **한 곳도
|
|
81
|
-
* 없다** — 죽은 가지였다. 그래서 운영 델타는 이 컬럼을 한 번도 채우지 못했다.
|
|
82
|
-
*
|
|
83
|
-
* order.status 29,403,565 행 — order_id 비어 있음 29,403,565 (100%)
|
|
84
|
-
* task.status 191,175 행 — 비어 있음 191,175 (100%)
|
|
85
|
-
*
|
|
86
|
-
* 그 결과 색인 `ix_twin_event_4` 가 **자기 주석이 적어 둔 용도**(「이 오더가 어디까지 갔나」)로 쓸 수
|
|
87
|
-
* 없었다. 화면은 오더를 눌러도 「연결된 이벤트가 없습니다」를 냈고, 그 답은 질의 결과로는 정직했다 —
|
|
88
|
-
* 시점을 어디로 옮겨도 0 이었다.
|
|
89
|
-
*
|
|
90
|
-
* **과거 행은 채워지지 않는다**(사용자 결정 2026-08-24, `moverId` 때와 같은 방식). 앞으로 들어오는
|
|
91
|
-
* 사건부터 조회된다.
|
|
92
|
-
*
|
|
93
|
-
* ── 한 칸에 두 낱말이 들어 있었다 (2026-09-05 실측) ────────────────────────
|
|
94
|
-
* 위 주석이 이미 알고 있었다 — 「EPCIS 의 `bizTransactionList` 는 **거래**(PO/SO)이고 오더와 같은
|
|
95
|
-
* 것이 아닐 수 있다」. 그런데 그 둘을 **같은 칸에** 넣고 있었다. 그래서 이렇게 됐다.
|
|
96
|
-
*
|
|
97
|
-
* order.status order-1 내부 오더 id
|
|
98
|
-
* epcis.TransformationEvent urn:epc:id:gdti:9521321.403.1 GS1 거래 식별자
|
|
99
|
-
* epcis.TransactionEvent urn:epc:id:gdti:9521321.403.1
|
|
100
|
-
*
|
|
101
|
-
* 한 오더의 이력이 **색인 안에서 두 쪽으로 갈라진다.** 어느 이름으로 물어도 절반만 나오고,
|
|
102
|
-
* 오류는 나지 않는다. 실측: 어휘가 섞인 행 10,004개.
|
|
103
|
-
*
|
|
104
|
-
* 이것이 실제로 막은 것 — 「이 개체를 어느 레시피로 만들었나」다. 답은 기록되어 있다(오더 사건이
|
|
105
|
-
* `recipeKey` 를 든다, 실측 328,021/328,021 = 100%). 변환 사건은 그 오더를 GDTI 로 가리키는데
|
|
106
|
-
* 오더 사건은 `order-1` 로 적혀 있어 **색인으로 이을 수가 없었다.**
|
|
107
|
-
*
|
|
108
|
-
* 그래서 칸을 갈랐다(사용자 결정 2026-09-05).
|
|
109
|
-
*
|
|
110
|
-
* orderId 내부 오더 id — 읽기 모델의 이음쇠
|
|
111
|
-
* bizTransaction GS1 거래 식별자 — 표준이 말하는 그 거래
|
|
112
|
-
*
|
|
113
|
-
* 오더 사건은 **둘 다** 든다(`order.status` 의 payload 에 `orderId` 와 `bizTransaction` 이 함께
|
|
114
|
-
* 있다). 그래서 EPCIS 사건의 거래 식별자로 오더를 찾을 수 있다 — 이 두 칸이 그 다리다.
|
|
115
|
-
*/
|
|
116
|
-
export function orderOf(envelope: any): string | undefined {
|
|
117
|
-
const d = envelope?.data ?? envelope ?? {}
|
|
118
|
-
return d.orderId ?? undefined
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* **그 사건이 가리키는 거래** — EPCIS `bizTransactionList` 의 첫 항목, 또는 운영 델타가 직접 든 값.
|
|
123
|
-
*
|
|
124
|
-
* 오더가 아니다. 표준이 말하는 거래(PO/SO/생산오더)이고, 한 오더가 여러 거래에 걸릴 수도 있다.
|
|
125
|
-
* 그 구별을 지키려고 `orderId` 와 갈라 두었다 — 합치면 위 주석의 그 일이 다시 난다.
|
|
126
|
-
*/
|
|
127
|
-
export function bizTransactionOf(envelope: any): string | undefined {
|
|
128
|
-
const d = envelope?.data ?? envelope ?? {}
|
|
129
|
-
return d.bizTransactionList?.[0]?.bizTransaction ?? d.bizTransaction ?? undefined
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* 위치 — EPCIS 는 읽은 지점(readPoint) 우선, 없으면 업무 위치(bizLocation).
|
|
134
|
-
* 운영 델타(무버 이동 등)는 그 둘이 없고 평범한 `location` 을 쓴다 — 빠뜨리면 설비가 어디서
|
|
135
|
-
* 무엇을 했는지가 위치 축에서 통째로 사라진다.
|
|
136
|
-
*/
|
|
137
|
-
export function locationOf(envelope: any): string | undefined {
|
|
138
|
-
const d = envelope?.data ?? envelope ?? {}
|
|
139
|
-
return d.readPoint?.id ?? d.bizLocation?.id ?? d.location ?? undefined
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* 설비·무버 — 운영 델타(equipment.status·task.status)가 대상을 가리키는 축.
|
|
144
|
-
*
|
|
145
|
-
* EPCIS 어휘가 아니라서 다른 축 어디에도 안 잡힌다. 이게 없으면 "이 지게차가 오늘 무엇을 했나" 를
|
|
146
|
-
* 서버에서 물을 방법이 없어, 화면이 저널을 통째로 받아 전수 조회하는 수밖에 없다.
|
|
147
|
-
*/
|
|
148
|
-
export function equipmentIdOf(envelope: any): string | undefined {
|
|
149
|
-
const d = envelope?.data ?? envelope ?? {}
|
|
150
|
-
/*
|
|
151
|
-
* ── 실측 (2026-08-24) — 두 갈래를 놓치고 있었다 ────────────────────────────
|
|
152
|
-
* 위 주석이 `task.status` 를 출처로 **적어 두었는데** 이 함수는 `d.moverId` 만 봤다. 작업이 자원을
|
|
153
|
-
* 가리키는 이름은 `resourceRef` 다(`TaskStatusDelta.resourceRef`) — 그래서 작업 191,175 행 전부
|
|
154
|
-
* 이 컬럼이 비었고, 「이 지게차가 오늘 무엇을 했나」에서 **작업이 통째로 빠졌다.**
|
|
155
|
-
*
|
|
156
|
-
* 그리고 에너지 사건은 `equipmentId` 를 쓴다(어휘가 `movers`→`equipment` 로 개명된 뒤에 생긴
|
|
157
|
-
* 채널이다). 실측 `energy.equipment` 31,079 행 전부 비어 있었다 — 「이 설비가 얼마를 먹었나」를
|
|
158
|
-
* 설비 축으로 물을 수 없었다.
|
|
159
|
-
*
|
|
160
|
-
* 셋을 함께 본다. 개명 세대가 섞여 있는 것은 저널의 성질이고, 읽는 쪽이 그것을 흡수한다.
|
|
161
|
-
*/
|
|
162
|
-
return d.moverId ?? d.resourceRef ?? d.equipmentId ?? undefined
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* EPCIS 행위 — `ADD`·`OBSERVE`·`DELETE`. 세 값이 아니면 `undefined`(원천의 잡값을 색인에 넣지 않는다).
|
|
167
|
-
*
|
|
168
|
-
* 이 키는 검색 축이 아니라 **판별식**이다: 되풀어 읽는 스냅샷은 원리적으로 `DELETE` 를 못 낸다.
|
|
169
|
-
* 그래서 「이 트윈이 반출을 한 번이라도 계산했는가」가 진짜 delta 피드의 증거인데, payload 안에 있는
|
|
170
|
-
* 동안에는 5개 드라이버 어디에서도 그 질문을 할 수 없었다. 운영 델타에는 행위가 없다 — 비운다.
|
|
171
|
-
*/
|
|
172
|
-
export function actionOf(envelope: any): string | undefined {
|
|
173
|
-
const a = (envelope?.data ?? envelope ?? {}).action
|
|
174
|
-
return a === 'ADD' || a === 'OBSERVE' || a === 'DELETE' ? a : undefined
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* **Whether the sender declared this fact as having actually happened** — the envelope's
|
|
179
|
-
* `provenance`, promoted to a column.
|
|
180
|
-
*
|
|
181
|
-
* ── Why it is an indexed column (2026-09-09) ──────────────────────────────
|
|
182
|
-
* The journal held 1,134 rows, all of them generator output, and there was nowhere to ask about
|
|
183
|
-
* it. While the declaration sits inside `payload`, none of the five drivers can answer "count
|
|
184
|
-
* these without the invented ones" — the same reason `action` was promoted.
|
|
185
|
-
*
|
|
186
|
-
* ── Only the two declared values are taken ────────────────────────────────
|
|
187
|
-
* Anything that is not `actual` or `simulated` becomes `undefined`. A source's stray value does
|
|
188
|
-
* not reach the index (the discipline in `actionOf`).
|
|
189
|
-
*
|
|
190
|
-
* **`undefined` means "not declared", not "it happened".** A reader has to distinguish three
|
|
191
|
-
* states — declared simulated, declared actual, not declared. Folding the last two together
|
|
192
|
-
* means a generator that omits the field has its output counted as production.
|
|
193
|
-
*/
|
|
194
|
-
export function provenanceOf(envelope: any): string | undefined {
|
|
195
|
-
/*
|
|
196
|
-
* Read from the envelope only. `data` is where the source system writes, and a source that
|
|
197
|
-
* could declare its own facts actual would make this no longer the connecting side's statement.
|
|
198
|
-
*/
|
|
199
|
-
const p = envelope?.provenance
|
|
200
|
-
return p === 'actual' || p === 'simulated' ? p : undefined
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/** Every promoted key for one event — the write path calls this function and nothing else. */
|
|
204
|
-
export function twinEventKeys(envelope: any): TwinEventKeys {
|
|
205
|
-
return {
|
|
206
|
-
action: actionOf(envelope),
|
|
207
|
-
bizStep: clip(bizStepOf(envelope), 'bizStep'),
|
|
208
|
-
epc: clip(epcOf(envelope), 'epc'),
|
|
209
|
-
orderId: clip(orderOf(envelope), 'orderId'),
|
|
210
|
-
bizTransaction: clip(bizTransactionOf(envelope), 'bizTransaction'),
|
|
211
|
-
locationId: clip(locationOf(envelope), 'locationId'),
|
|
212
|
-
moverId: clip(equipmentIdOf(envelope), 'moverId'),
|
|
213
|
-
provenance: provenanceOf(envelope)
|
|
214
|
-
}
|
|
215
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { Field, Int, ObjectType } from 'type-graphql'
|
|
2
|
-
|
|
3
|
-
import { TwinEvent } from './twin-event.js'
|
|
4
|
-
|
|
5
|
-
/*
|
|
6
|
-
* 저널 목록 반환형 — things-factory 표준 `{ items, total }`(AttributeSetList·DomainList 등과 동형).
|
|
7
|
-
*
|
|
8
|
-
* `total` 이 이 타입의 존재 이유다. 기존 `twinEvents` 는 배열만 돌려줘서 **화면이 자기가 전체를 받은
|
|
9
|
-
* 건지 잘린 건지 알 방법이 없었다** — 그래서 리스트가 알리지 않고 잘린 채로 "이게 전부" 처럼 보였다.
|
|
10
|
-
* 총건수를 함께 주면 화면은 "48 / 12,904" 라고 정직하게 말할 수 있고, 사용자는 좁혀야 한다는 걸 안다.
|
|
11
|
-
*/
|
|
12
|
-
@ObjectType({ description: 'A page of twin journal events together with the total number of matching records.' })
|
|
13
|
-
export class TwinEventList {
|
|
14
|
-
@Field(type => [TwinEvent], { description: 'The events on this page, ordered by the requested sorting (revision descending by default).' })
|
|
15
|
-
items: TwinEvent[]
|
|
16
|
-
|
|
17
|
-
/*
|
|
18
|
-
* 전체 수 — **상한을 넘으면 비운다.**
|
|
19
|
-
*
|
|
20
|
-
* 세는 데도 값이 든다(2026-08-22 실측: 저널 358만 행인 트윈에서 전량 세기 5.32초 · 상한 1만까지
|
|
21
|
-
* 0.04초). 그래서 상한까지만 세고, 넘으면 「모른다」로 둔다. 그때 상한값을 전체로 적으면 화면이
|
|
22
|
-
* 거짓을 말한다 — 없는 것과 모르는 것을 가르는 것이 이 필드의 규율이다.
|
|
23
|
-
*/
|
|
24
|
-
@Field(type => Int, {
|
|
25
|
-
nullable: true,
|
|
26
|
-
description:
|
|
27
|
-
'Total number of events matching the filters, ignoring pagination. Lets the caller show an honest "shown of total" count instead of silently truncating. NULL when the server stopped counting at countCap: the exact total is then unknown, and capped says so — do not render the cap as if it were the total.'
|
|
28
|
-
})
|
|
29
|
-
total?: number
|
|
30
|
-
|
|
31
|
-
@Field({
|
|
32
|
-
nullable: true,
|
|
33
|
-
description:
|
|
34
|
-
'True when there are more matching events than countCap, so total could not be established. The caller should say "first N shown" and offer narrowing rather than implying it received everything.'
|
|
35
|
-
})
|
|
36
|
-
capped?: boolean
|
|
37
|
-
|
|
38
|
-
@Field(type => Int, {
|
|
39
|
-
nullable: true,
|
|
40
|
-
description: 'The counting limit the server applied. Reported so the screen can say how far the count is trustworthy instead of guessing.'
|
|
41
|
-
})
|
|
42
|
-
countCap?: number
|
|
43
|
-
|
|
44
|
-
/*
|
|
45
|
-
* 다음 페이지 커서. 저널은 **머리에 계속 쌓이는 목록**이라 offset 으로 뒤를 읽으면
|
|
46
|
-
* 읽는 사이 들어온 이벤트만큼 밀려 본 행이 또 나오거나 못 본 행이 사라진다.
|
|
47
|
-
* 이 값을 그대로 다음 요청의 `pagination.after` 로 돌려주면 그 문제가 없다.
|
|
48
|
-
*/
|
|
49
|
-
@Field({ nullable: true, description: 'Opaque cursor for the next page. Pass it back as pagination.after to continue exactly where this page ended, without the duplicate or skipped rows that offset paging produces on a journal that keeps growing at the head. Null when this page is the last one.' })
|
|
50
|
-
nextCursor?: string
|
|
51
|
-
|
|
52
|
-
/*
|
|
53
|
-
* **앞부분이 지워졌다** — 보관 기간 정리가 이 트윈의 오래된 사건을 지운 경우 (2026-08-27).
|
|
54
|
-
*
|
|
55
|
-
* 정리는 선언된 보관 기간(기본 7일)보다 오래된 사건을 지운다. 그러면 이 목록의 첫 페이지 뒤로 더
|
|
56
|
-
* 내려가도 어느 지점에서 기록이 끝난다. 화면이 그것을 말하지 않으면 사람은 「이 트윈은 그때부터
|
|
57
|
-
* 시작했다」로 읽는다. 없었던 것과 지워진 것은 다른 사실이다.
|
|
58
|
-
*
|
|
59
|
-
* 값은 저장하지 않고 조회할 때 구한다(남아 있는 가장 작은 리비전). 저장하면 실제 데이터와 어긋날 수
|
|
60
|
-
* 있고, 어긋나면 어느 쪽이 사실인지 알 수 없다.
|
|
61
|
-
*/
|
|
62
|
-
@Field(type => Int, {
|
|
63
|
-
nullable: true,
|
|
64
|
-
description:
|
|
65
|
-
'The oldest revision still stored for this twin. When it is greater than 1, older events were deleted by the journal retention policy: the screen must say the record starts here rather than implying the twin began at this point. NULL when the caller asked for more than one twin (the axis is per twin) or when nothing is stored.'
|
|
66
|
-
})
|
|
67
|
-
oldestRevision?: number
|
|
68
|
-
}
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
|
|
2
|
-
import { ObjectType, Field, ID, Int } from 'type-graphql'
|
|
3
|
-
|
|
4
|
-
import { Domain, ScalarObject } from '@things-factory/shell'
|
|
5
|
-
|
|
6
|
-
/*
|
|
7
|
-
* TwinEvent — append-only 트윈 이벤트 저널(EPCIS 이벤트 + 운영 델타).
|
|
8
|
-
* 커널 EventJournal 의 영속 대응 — 상태=이벤트열의 함수(재부팅 시 DB→replay 재구성).
|
|
9
|
-
* append-only 이므로 updater/deletedAt 없음(이력 CRUD 가 아니라 불변 이벤트 스트림).
|
|
10
|
-
* payload 는 simple-json(멀티DB 이식 — postgres/mysql/sqlite/mssql/oracle 공통, DB-specific JSON 타입 금지).
|
|
11
|
-
* (CLAUDE.md: 모든 @ObjectType/@Field 는 영문 description 필수.)
|
|
12
|
-
*/
|
|
13
|
-
/*
|
|
14
|
-
* ── 인덱스 설계 (2026-07-31) ────────────────────────────────────────────────
|
|
15
|
-
* 이 표는 **인제스트 경로의 뜨거운 append-only 테이블**이다. 인덱스 하나하나가 쓰기 증폭이므로
|
|
16
|
-
* "있으면 좋을" 인덱스를 붙이지 않는다. 실제 질의 패턴에 대응하는 것만 둔다.
|
|
17
|
-
*
|
|
18
|
-
* ix_0 (domain, instanceId, revision) 원장 기본 정렬·커서 페이징·replay(ASC 주사)
|
|
19
|
-
* ix_1 (domain, instanceId, eventTime) 시각 커서(untilTime)·시간창 KPI — 거의 모든 조회가 탄다
|
|
20
|
-
* ix_2 (domain, instanceId, eventType, revision) 타입 필터 + 정렬 동시 충족(스케줄 화면 task/equipment)
|
|
21
|
-
* ix_3 (domain, instanceId, epc) "이 물건의 이력" — Entity360 의 본질 질문
|
|
22
|
-
* ix_4 (domain, instanceId, orderId) "이 오더가 어디까지 갔나"
|
|
23
|
-
* ix_9 (domain, instanceId, bizTransaction) "이 거래에 무슨 일이 있었나" — EPCIS↔오더의 다리
|
|
24
|
-
*
|
|
25
|
-
* bizStep·locationId·moverId 는 컬럼만 두고 인덱스는 두지 않는다 — 한 트윈 안에서 카디널리티가
|
|
26
|
-
* 낮아(업무단계 몇 개, 위치 수백, 설비 수십) (domain,instanceId) 로 이미 좁혀진 뒤의 잔여 필터로
|
|
27
|
-
* 충분하고, 뜨거운 표에 인덱스를 더 얹을 가치가 없다. 저널 하나가 아주 커져서 이 축들의 조회가
|
|
28
|
-
* 느려지면 그때 측정을 근거로 인덱스를 추가할 일이지, 지레 얹어 쓰기를 무겁게 할 일은 아니다.
|
|
29
|
-
*/
|
|
30
|
-
@Entity()
|
|
31
|
-
@Index('ix_twin_event_0', (e: TwinEvent) => [e.domain, e.instanceId, e.revision], { unique: false })
|
|
32
|
-
@Index('ix_twin_event_1', (e: TwinEvent) => [e.domain, e.instanceId, e.eventTime], { unique: false })
|
|
33
|
-
@Index('ix_twin_event_2', (e: TwinEvent) => [e.domain, e.instanceId, e.eventType, e.revision], { unique: false })
|
|
34
|
-
@Index('ix_twin_event_3', (e: TwinEvent) => [e.domain, e.instanceId, e.epc], { unique: false })
|
|
35
|
-
@Index('ix_twin_event_4', (e: TwinEvent) => [e.domain, e.instanceId, e.orderId], { unique: false })
|
|
36
|
-
/* ix_5 — "이 지시가 무엇을 일으켰나". 감사 기록의 commandId 로 저널을 다시 계산하는 축. */
|
|
37
|
-
@Index('ix_twin_event_5', (e: TwinEvent) => [e.domain, e.correlationId], { unique: false })
|
|
38
|
-
/* ix_6 — "반출을 한 번이라도 계산했나". 없으면 그 질문이 인스턴스 저널 전량 주사가 된다. */
|
|
39
|
-
@Index('ix_twin_event_6', (e: TwinEvent) => [e.domain, e.instanceId, e.action], { unique: false })
|
|
40
|
-
/*
|
|
41
|
-
* ix_7 — **"이 종류의 사실을 시각순으로"** (2026-08-25 실측으로 추가)
|
|
42
|
-
*
|
|
43
|
-
* 이 축이 없어서 공정 타임라인이 22초였다. 종류로 거르고 시각으로 정렬하는 조회가 갈 곳이 없었다:
|
|
44
|
-
*
|
|
45
|
-
* ix_2 (…, eventType, revision) 종류는 걸러지고 정렬이 **적힌 순서**다 → 4월 사실을 최근으로 그렸다
|
|
46
|
-
* ix_1 (…, eventTime) 정렬은 맞고 **종류를 못 거른다** → 행마다 테이블을 열어 확인한다
|
|
47
|
-
*
|
|
48
|
-
* 뒤쪽으로 걸으면 그 트윈에서 찾는 종류가 멈춘 시점까지의 모든 행을 읽고 버린다. 승화푸드에서 작업
|
|
49
|
-
* 사실은 8월 22일에 멈춰 있고 그 뒤로 리비전이 110만 늘었으므로, 200건에 닿기까지 110만 행을 열었다.
|
|
50
|
-
*
|
|
51
|
-
* 위 주석이 「측정을 근거로 추가할 일이지 지레 얹을 일은 아니다」라고 적어 두었다. 그 측정이 나왔다.
|
|
52
|
-
*/
|
|
53
|
-
@Index('ix_twin_event_7', (e: TwinEvent) => [e.domain, e.instanceId, e.eventType, e.eventTime], { unique: false })
|
|
54
|
-
/*
|
|
55
|
-
* ix_8 — **"이 트윈의 오래된 기록"** (2026-08-27 실측으로 추가)
|
|
56
|
-
*
|
|
57
|
-
* 보관 기간 정리가 `created_at` 으로 자르는데(보관은 저장 나이의 문제다) 그 축에 인덱스가 없었다.
|
|
58
|
-
* 그래서 정리가 매 배치마다 그 트윈의 저널을 전량 주사했다.
|
|
59
|
-
*
|
|
60
|
-
* hatio-mx2 의 7일 밖 행을 세기 208초 ← 1,029만 행을 전부 읽는다(7일 밖은 2,446건뿐이다)
|
|
61
|
-
* revision 으로 한 행 짚기 0.004초
|
|
62
|
-
*
|
|
63
|
-
* 정리는 한 창에 2초만 쓰도록 예산이 걸려 있어서, 그 2초를 주사에 다 쓰고 44건만 지우고 멈췄다.
|
|
64
|
-
*/
|
|
65
|
-
@Index('ix_twin_event_8', (e: TwinEvent) => [e.domain, e.instanceId, e.createdAt], { unique: false })
|
|
66
|
-
/* ix_9 — "이 거래에 무슨 일이 있었나". EPCIS 사건에서 오더로 건너가는 다리(§`bizTransaction`). */
|
|
67
|
-
@Index('ix_twin_event_9', (e: TwinEvent) => [e.domain, e.instanceId, e.bizTransaction], { unique: false })
|
|
68
|
-
@ObjectType({ description: 'Append-only twin event journal record (EPCIS event or operational delta).' })
|
|
69
|
-
export class TwinEvent {
|
|
70
|
-
@PrimaryGeneratedColumn('uuid')
|
|
71
|
-
@Field(type => ID, { description: 'Unique identifier of the event record.' })
|
|
72
|
-
readonly id: string
|
|
73
|
-
|
|
74
|
-
@ManyToOne(type => Domain)
|
|
75
|
-
@Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })
|
|
76
|
-
domain?: Domain
|
|
77
|
-
|
|
78
|
-
@RelationId((e: TwinEvent) => e.domain)
|
|
79
|
-
domainId?: string
|
|
80
|
-
|
|
81
|
-
/*
|
|
82
|
-
* 이 사실을 낸 트윈. **빌 수 없다** — 저널 행을 만드는 곳은 `journalRow` 하나뿐이고 거기서
|
|
83
|
-
* 필수 인자로 받는다. nullable 로 두면 읽는 쪽이 매번 `?? ''` 를 달게 되고, 그 방어가 실제로는
|
|
84
|
-
* 일어나지 않는 경우를 대비하느라 "빈 인스턴스의 이벤트" 라는 없는 개념을 코드에 남긴다.
|
|
85
|
-
*/
|
|
86
|
-
@Column()
|
|
87
|
-
@Field({ description: 'Twin runtime instance id that emitted the event.' })
|
|
88
|
-
instanceId: string
|
|
89
|
-
|
|
90
|
-
/* 커널 봉투의 필수 필드(`CanonicalEnvelope.eventType`)라 빌 수 없다 — 계약을 그대로 옮긴다. */
|
|
91
|
-
@Column()
|
|
92
|
-
@Field({ description: 'Event type: epcis.* | task.status | equipment.status | order.status.' })
|
|
93
|
-
eventType: string
|
|
94
|
-
|
|
95
|
-
@Column({ type: 'int', nullable: true })
|
|
96
|
-
@Field(type => Int, { nullable: true, description: 'Monotonic state revision at which the event was emitted.' })
|
|
97
|
-
revision?: number
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* 이 사실이 **어느 공장에서** 일어났나 — `TwinStructure.rev`.
|
|
101
|
-
*
|
|
102
|
-
* 이것이 없던 시절에는 구조가 바뀌면 저널을 통째로 지우는 것이 유일한 길이었다(안 지우면 옛
|
|
103
|
-
* 이벤트를 새 공장에 대고 계산해 이력이 거짓말을 한다). 이 한 칸이 셋째 길을 연다 — 재생이
|
|
104
|
-
* 구조가 바뀌는 지점에서 전환한 뒤 이어서 계산한다.
|
|
105
|
-
*
|
|
106
|
-
* **비어 있을 수 있다**: 컬럼이 생기기 전에 쓰인 행이다. 그 행들은 **가장 오래된 리비전**에
|
|
107
|
-
* 속한다(0 을 채워 넣지 않는다 — 0 은 "모름" 이 아니라 유효한 번호처럼 보인다).
|
|
108
|
-
*/
|
|
109
|
-
@Column({ type: 'int', nullable: true })
|
|
110
|
-
@Field(type => Int, { nullable: true, description: 'Structure revision (TwinStructure.rev) in force when this event happened. Absent on rows written before structure revisions existed; those belong to the oldest revision.' })
|
|
111
|
-
structureRev?: number
|
|
112
|
-
|
|
113
|
-
/*
|
|
114
|
-
* 이 사실이 일어난 시각(트윈의 시계). **날짜 타입이다.**
|
|
115
|
-
*
|
|
116
|
-
* 예전에는 문자열이었다. 읽을 때마다 `Date.parse` 했고, 정렬은 UTC ISO 만 들어온다는 전제 위에서
|
|
117
|
-
* 사전식 비교가 우연히 맞았다 — `+09:00` 오프셋 표기가 하나 섞이면 알리지 않고 순서가 틀린다.
|
|
118
|
-
* 그 전제는 컬럼 어디에도 적혀 있지 않았다.
|
|
119
|
-
*
|
|
120
|
-
* **타입 이름을 적지 않는다** (2026-08-19 Postgres 부팅 실패로 고침).
|
|
121
|
-
*
|
|
122
|
-
* `datetime` 을 적었더니 Postgres 가 부팅 중에 거절했다(`DataTypeNotSupportedError`) — 그 이름은
|
|
123
|
-
* sqlite·MySQL 의 것이고 Postgres 는 `timestamp` 만 안다. 거꾸로 `timestamp` 는 sqlite 가 모른다:
|
|
124
|
-
* **다섯 드라이버에 다 통하는 이름이 아예 없다.**
|
|
125
|
-
*
|
|
126
|
-
* 그래서 이름을 고르는 일을 TypeORM 에 맡긴다. `emitDecoratorMetadata` 가 켜져 있으므로 이 속성의
|
|
127
|
-
* TS 타입(`Date`)에서 드라이버별 타입을 스스로 고른다(Postgres `timestamp` · sqlite·MySQL `datetime`).
|
|
128
|
-
* 이 레포의 다중 DB 규약이 요구하는 것이 바로 그것이다 — 드라이버 방언을 코드에 적지 않는다.
|
|
129
|
-
*/
|
|
130
|
-
@Column({ nullable: true })
|
|
131
|
-
@Field({ nullable: true, description: 'Time at which the fact happened on the twin clock.' })
|
|
132
|
-
eventTime?: Date
|
|
133
|
-
|
|
134
|
-
/*
|
|
135
|
-
* ── 승격된 검색 축 ────────────────────────────────────────────────────────
|
|
136
|
-
* payload 안에 있던 값을 인제스트 시점에 꺼내 실컬럼으로 둔다(`twin-event-keys.ts` 가 단독 소유).
|
|
137
|
-
* payload 가 여전히 정본이고 이것들은 **파생 색인**이다 — 새로운 진실이 아니라 찾을 수 있게 하는 장치.
|
|
138
|
-
* simple-json(TEXT) 안의 값은 5개 DB 드라이버 공통으로 거를 방법이 없어서(멀티DB 호환 규칙상
|
|
139
|
-
* DB별 JSON 연산자 금지) 승격 외의 선택지가 없다.
|
|
140
|
-
* 길이 상한 255 는 GS1 식별자 규격 대비 충분하며, 넘치는 값은 알리지 않고 잘리지 않고 경고를 남긴다.
|
|
141
|
-
*
|
|
142
|
-
* ── 축을 새로 추가할 때 ──────────────────────────────────────────────────
|
|
143
|
-
* 새 승격 컬럼을 만들면 **이미 쌓인 행은 비어 있다.** 그 행들은 새 축으로 검색되지 않고,
|
|
144
|
-
* 사용자에게는 "과거가 없는 것" 으로 보인다(알리지 않고 빠진 데이터).
|
|
145
|
-
*
|
|
146
|
-
* 예전에는 기동 훅이 매번 테이블을 살펴 채웠다. 그건 두 가지로 틀렸다 — 저널이 커질수록 부팅이
|
|
147
|
-
* 느려지고, "bizStep 이 비었으면 옛 행" 이라는 전제를 코드에 고정해 그 전제가 깨지는 순간
|
|
148
|
-
* (감사 행처럼 업무 단계가 없는 행) 매 부팅마다 헛돌았다. 그래서 걷어냈다(git: backfill-keys.ts).
|
|
149
|
-
*
|
|
150
|
-
* 채우는 일은 **마이그레이션 한 번**이 맞다(`yarn migration`). 그 컬럼에 맞는 것을 그때 쓴다 —
|
|
151
|
-
* 범용 스캐너를 되살리지 말 것. 개발 데이타라면 그냥 버리는 것도 답이다.
|
|
152
|
-
*/
|
|
153
|
-
/**
|
|
154
|
-
* 이 사실을 일으킨 **지시** — 커널이 커맨드에서 이어 준 상관값(기본은 commandId).
|
|
155
|
-
*
|
|
156
|
-
* 이것이 감사 기록(TwinAuditEvent.commandId)과 저널을 잇는 유일한 다리다. 없으면 승인 기록은
|
|
157
|
-
* "사람이 허락했다" 까지이고, 그 뒤 공장이 실제로 어떻게 움직였는지와 이어지지 않는다.
|
|
158
|
-
*
|
|
159
|
-
* **대부분의 행은 비어 있다** — 커맨드가 아니라 시뮬 시간이 낳은 사실이기 때문이다. 그것이 정상이고,
|
|
160
|
-
* 비어 있다고 "덜 채워진 옛 행" 으로 보면 안 된다(같은 오해를 bizStep 에서 이미 한 번 했다).
|
|
161
|
-
*/
|
|
162
|
-
@Column({ length: 255, nullable: true })
|
|
163
|
-
@Field({ nullable: true, description: 'Id of the command that caused this fact (kernel correlation id; defaults to the commandId). Empty for facts that simulation time produced rather than a command.' })
|
|
164
|
-
correlationId?: string
|
|
165
|
-
|
|
166
|
-
/* 옛 행은 비어 있다 — 승격 전에 기록된 것이라 **모른다**(0 이나 OBSERVE 로 위장하지 않는다). */
|
|
167
|
-
@Column({ length: 16, nullable: true })
|
|
168
|
-
@Field({ nullable: true, description: 'EPCIS action (ADD / OBSERVE / DELETE), promoted from the payload. Empty for operational deltas, and for rows journaled before this column existed.' })
|
|
169
|
-
action?: string
|
|
170
|
-
|
|
171
|
-
@Column({ length: 255, nullable: true })
|
|
172
|
-
@Field({ nullable: true, description: 'Business step (CBV bizStep tail), promoted from the payload for indexed filtering.' })
|
|
173
|
-
bizStep?: string
|
|
174
|
-
|
|
175
|
-
@Column({ length: 255, nullable: true })
|
|
176
|
-
@Field({ nullable: true, description: 'Item identifier (EPC / EPC class / parent id), promoted from the payload for indexed lookup of one item history.' })
|
|
177
|
-
epc?: string
|
|
178
|
-
|
|
179
|
-
@Column({ length: 255, nullable: true })
|
|
180
|
-
@Field({ nullable: true, description: 'Internal order identifier, promoted from the payload for indexed lookup of one order history.' })
|
|
181
|
-
orderId?: string
|
|
182
|
-
|
|
183
|
-
/*
|
|
184
|
-
* **거래 식별자는 오더 식별자와 다른 것이다.**
|
|
185
|
-
*
|
|
186
|
-
* 전에는 둘이 한 칸(`orderId`)에 들어갔다. 그래서 한 오더의 이력이 색인 안에서 두 쪽으로
|
|
187
|
-
* 갈라졌다 — 운영 델타는 `order-1`, EPCIS 사건은 `urn:epc:id:gdti:…` 로 적혀 어느 이름으로
|
|
188
|
-
* 물어도 절반만 나왔다(실측 2026-09-05: 어휘가 섞인 행 10,004개, 오류는 나지 않음).
|
|
189
|
-
*
|
|
190
|
-
* 오더 사건은 두 값을 다 들고 있다. 그래서 이 칸이 **EPCIS 사건에서 오더로 건너가는 다리**가
|
|
191
|
-
* 된다 — 「이 개체를 어느 레시피로 만들었나」가 그 다리로 답해진다.
|
|
192
|
-
*/
|
|
193
|
-
@Column({ length: 255, nullable: true })
|
|
194
|
-
@Field({ nullable: true, description: 'Business transaction identifier (PO / SO / production order), promoted from the payload for indexed lookup of one transaction.' })
|
|
195
|
-
bizTransaction?: string
|
|
196
|
-
|
|
197
|
-
@Column({ length: 255, nullable: true })
|
|
198
|
-
@Field({ nullable: true, description: 'Location identifier (read point, business location, or the plain location an operational delta carries), promoted from the payload for indexed filtering.' })
|
|
199
|
-
locationId?: string
|
|
200
|
-
|
|
201
|
-
@Column({ length: 255, nullable: true })
|
|
202
|
-
@Field({ nullable: true, description: 'Equipment identifier carried by operational deltas, promoted from the payload so one machine history can be asked for on the server. The column keeps the legacy name `moverId`: the journal is append-only history and mixing two names for the same fact across time is worse than an outdated name. Renaming belongs with event-schema versioning.' })
|
|
203
|
-
moverId?: string
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* **Whether the sender declared this fact as having actually happened** — the envelope's
|
|
207
|
-
* `provenance`, promoted here.
|
|
208
|
-
*
|
|
209
|
-
* ── Why a column (measured 2026-09-09) ──────────────────────────────────
|
|
210
|
-
* This table held 1,134 rows, all of them generator output, and **there was nowhere to ask
|
|
211
|
-
* about it**:
|
|
212
|
-
*
|
|
213
|
-
* ```
|
|
214
|
-
* select count(*) from twin_events 1134
|
|
215
|
-
* select count(*) where payload like '%SIM-%' 1134
|
|
216
|
-
* select count(*) where order_id like 'WO-SIM-%' 558 <- half of them
|
|
217
|
-
* ```
|
|
218
|
-
*
|
|
219
|
-
* The only signal was the sender's naming convention (`SIM-`), and the column that convention
|
|
220
|
-
* reaches was empty on half the rows. While it sits inside `payload`, none of the five drivers
|
|
221
|
-
* can answer "count these without the invented ones" — the same reason `action` was promoted.
|
|
222
|
-
*
|
|
223
|
-
* ── Three states, kept apart ────────────────────────────────────────────
|
|
224
|
-
* ```
|
|
225
|
-
* 'simulated' the sender said it was invented
|
|
226
|
-
* 'actual' the sender said it happened
|
|
227
|
-
* null **not declared** — which is not `actual`
|
|
228
|
-
* ```
|
|
229
|
-
*
|
|
230
|
-
* Folding the last two together means a generator that omits the declaration has its output
|
|
231
|
-
* counted as production, and nothing says so. Hence no default: an absent declaration is not
|
|
232
|
-
* disguised as a valid-looking value (the discipline of `structureRev` and `lastWarningCount`).
|
|
233
|
-
*
|
|
234
|
-
* ── No index ────────────────────────────────────────────────────────────
|
|
235
|
-
* Three possible values is low cardinality within one twin — the judgement already made for
|
|
236
|
-
* `bizStep` and `locationId`. Performance folds arrive already narrowed by domain, instance and
|
|
237
|
-
* time, so filtering after that is cheap.
|
|
238
|
-
*/
|
|
239
|
-
@Column({ length: 16, nullable: true })
|
|
240
|
-
@Field({ nullable: true, description: 'Whether the sending side declared this fact as actually having happened. Either "actual" or "simulated"; null means it was not declared, which is not the same as actual — a generator that omits it must not be counted as production.' })
|
|
241
|
-
provenance?: string
|
|
242
|
-
|
|
243
|
-
@Column({ type: 'simple-json', nullable: true })
|
|
244
|
-
@Field(type => ScalarObject, { nullable: true, description: 'Raw canonical envelope (EPCIS event or operational delta) as JSON.' })
|
|
245
|
-
payload?: any
|
|
246
|
-
|
|
247
|
-
@CreateDateColumn()
|
|
248
|
-
@Field({ nullable: true, description: 'Wall-clock timestamp when the record was persisted.' })
|
|
249
|
-
createdAt?: Date
|
|
250
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* 예측 지표 — **스냅샷에서 수 하나를 뽑는 규칙.**
|
|
3
|
-
*
|
|
4
|
-
* ── 왜 순수 모듈인가 (2026-08-15) ───────────────────────────────────────────
|
|
5
|
-
* 이 표가 리졸버 안에 있어서 시험이 불러올 수 없었다(type-graphql·shell 을 물고 있다). 그런데 여기서
|
|
6
|
-
* 틀리면 예측 그래프 전체가 알리지 않고 다른 것을 그린다 — 오류 없이. 규칙은 시험이 닿는 자리에 둔다.
|
|
7
|
-
*
|
|
8
|
-
* ── 에너지 지표를 더한 이유 ─────────────────────────────────────────────────
|
|
9
|
-
* 예측 화면의 지표가 물류 여섯(재고·점유·작업·오더·출고·백로그)으로 고정돼 있어서, 에너지 트윈을
|
|
10
|
-
* 고르면 **남의 질문에 답하는 그래프**가 떴다. 에너지 트윈에는 재고도 오더도 없으므로 그 값들은
|
|
11
|
-
* 전부 0 이고, 0 은 「없다」가 아니라 「이 트윈의 질문이 아니다」이다.
|
|
12
|
-
*
|
|
13
|
-
* 여기 더한 셋은 **커널이 이미 상태로 들고 있는 것**이다 — 새 계산을 만들지 않았다. 특히 부하 합은
|
|
14
|
-
* 커널이 뿌리 계량기로만 세는데(계층 계량의 이중 계상 방지), 그 규칙을 여기서 다시 쓰면 두 벌이 된다.
|
|
15
|
-
* 그래서 지점을 직접 더하지 않고 **구간 값**을 읽는다.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import { isFlowOrder, isOrderTerminal } from '@operato/ops-contract'
|
|
19
|
-
|
|
20
|
-
/*
|
|
21
|
-
* ── Folded orders are counted too (ADR-0092 decision 3, ruling 2026-09-24) ─────────────
|
|
22
|
-
*
|
|
23
|
-
* A twin folds finished orders out of its hot list at checkpoint time and keeps only their counts
|
|
24
|
-
* (`foldedOrders.counts`, kind × terminal status, never trimmed). Counting the hot list alone would drop
|
|
25
|
-
* `orders` and `shipped` the moment a fold happens — and "the increase since the fork" alone would still
|
|
26
|
-
* break `twinForecastGapTrend`, whose actual at T+h is read from recovered state: a fold between T and
|
|
27
|
-
* T+h makes the actual increase negative. So both metrics are cumulative including the folded side, and
|
|
28
|
-
* an increase is the difference of the same number. Which folded kinds are flow orders is asked of the
|
|
29
|
-
* contract's `isFlowOrder`, the same as the hot list; `shipped` uses the same word on both sides.
|
|
30
|
-
*/
|
|
31
|
-
function foldedFlowOrders(s: any, status?: string): number {
|
|
32
|
-
let n = 0
|
|
33
|
-
for (const [kind, byStatus] of Object.entries((s?.foldedOrders?.counts ?? {}) as Record<string, Record<string, number>>)) {
|
|
34
|
-
if (!isFlowOrder({ kind })) continue
|
|
35
|
-
if (status) n += Number(byStatus?.[status]) || 0
|
|
36
|
-
else for (const c of Object.values(byStatus ?? {})) n += Number(c) || 0
|
|
37
|
-
}
|
|
38
|
-
return n
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** 스냅샷 → 수 하나. 값이 없으면 0 이 아니라 **그 지표를 그릴 수 없다**는 뜻이지만, 그래프 계약이
|
|
42
|
-
* 수를 요구하므로 0 을 낸다 — 그래서 에너지 지표는 「없음」이 0 과 헷갈리지 않는 것만 골랐다. */
|
|
43
|
-
export type MetricFn = (s: any) => number
|
|
44
|
-
|
|
45
|
-
export const FORECAST_METRICS: Record<string, MetricFn> = {
|
|
46
|
-
items: s => (s?.items || []).length,
|
|
47
|
-
occupancy: s => (s?.locations || []).reduce((a: number, n: any) => a + (n.occupancy || 0), 0),
|
|
48
|
-
tasks: s => (s?.tasks || []).length,
|
|
49
|
-
/*
|
|
50
|
-
* ── 세는 것은 **흐름 오더**다 (2026-09-19, ADR-0076 보탬 ⑥) ────────────────
|
|
51
|
-
*
|
|
52
|
-
* 받는 오더(입고 · 반품 입고)는 도착이 세우고 도착이 이행한다. 그대로 세면 「나간 것」이 받을 때마다
|
|
53
|
-
* 한 건씩 늘고 백로그는 영영 안 줄어든다 — 예측 그래프가 있지도 않은 일을 그린다. 무엇이 흐름
|
|
54
|
-
* 오더인지는 계약의 `isFlowOrder` 한 곳이 정한다(여기서 `kind` 를 다시 적지 않는다).
|
|
55
|
-
*/
|
|
56
|
-
orders: s => (s?.orders || []).filter(isFlowOrder).length + foldedFlowOrders(s),
|
|
57
|
-
// 이행 지표 — 라이브 예측의 핵심 질문("언제 다 나가나·백로그 언제 풀리나").
|
|
58
|
-
shipped: s => (s?.orders || []).filter(isFlowOrder).filter((o: any) => o.status === 'shipped').length + foldedFlowOrders(s, 'shipped'),
|
|
59
|
-
/*
|
|
60
|
-
* ── 백로그는 **「종결인가」**로 묻는다 (2026-09-19) ─────────────────────────
|
|
61
|
-
*
|
|
62
|
-
* 낱말 둘(`shipped`·`cancelled`)로 물으면 **원본이 다른 낱말을 쓰는 미러에서 끝난 오더가 영영
|
|
63
|
-
* 백로그에 남는다.** `status` 는 열린 축이고(표준도 `RequestState` 를 열거하지 않는다) 실 시스템은
|
|
64
|
-
* `completed`·`FINISHED` 를 쓴다 — 그 트윈의 백로그 곡선은 내려가지 않는다. 종결 판정은 커널이
|
|
65
|
-
* 한 곳에서 한다(`isOrderTerminal` — 낱말이 아니라 **양**을 1차 근거로 본다).
|
|
66
|
-
*
|
|
67
|
-
* `shipped` 한 낱말은 남는다. 그것은 이 커널이 **자기가 쓰는 말**이고(WMS 의 출하 완료), 계약의
|
|
68
|
-
* 종결 목록(`completed` · `cancelled`)에는 없다. 양을 말하지 않는 스냅샷에서 그 오더가 백로그로
|
|
69
|
-
* 되돌아오지 않게 둘을 함께 본다 — 빼는 쪽이라 이 셈이 전보다 커지는 일은 없다. 커널의 낱말이
|
|
70
|
-
* 계약의 종결 목록에 들어오는 날 이 줄이 지워진다(아키텍트에게 올림).
|
|
71
|
-
*/
|
|
72
|
-
backlog: s =>
|
|
73
|
-
(s?.orders || [])
|
|
74
|
-
.filter(isFlowOrder)
|
|
75
|
-
.filter((o: any) => !isOrderTerminal(o) && o.status !== 'shipped').length,
|
|
76
|
-
|
|
77
|
-
/*
|
|
78
|
-
* ── 에너지 ────────────────────────────────────────────────────────────────
|
|
79
|
-
* `peakKW` 는 **마감된 구간의 최대**다 — 단조 증가라 지평선 위에서 「최대수요가 어디까지 오르나」로
|
|
80
|
-
* 읽힌다. 열린 구간은 넣지 않는다(아직 확정이 아니다 — 커널이 지키는 규율을 여기서도 지킨다).
|
|
81
|
-
*/
|
|
82
|
-
peakKW: s => Number(s?.energy?.peakSince?.kW) || 0,
|
|
83
|
-
/*
|
|
84
|
-
* 이번 구간이 이대로 가면 얼마로 마감되나 — 커널이 낸 투영(`mean-so-far`)을 그대로 읽는다.
|
|
85
|
-
* 우리가 다시 계산하지 않는다: 투영 규칙이 두 벌이 되면 화면과 판정이 다른 말을 한다.
|
|
86
|
-
*/
|
|
87
|
-
projectedKW: s => Number(s?.energy?.open?.projectedKW ?? s?.energy?.open?.meanKW) || 0,
|
|
88
|
-
/*
|
|
89
|
-
* 계약을 넘긴 구간 수 — 「몇 번 넘나」는 요금이 걸린 질문이라 최대치와 따로 본다.
|
|
90
|
-
* 계약을 모르는 트윈에서는 늘 0 이다(넘김을 판정할 근거가 없다 — 지어내지 않는다).
|
|
91
|
-
*/
|
|
92
|
-
overWindows: s => (s?.energy?.closed || []).filter((w: any) => w?.overContract === true).length
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** 이 지표가 그 종류의 트윈에서 뜻이 있나 — 화면이 목록을 고를 때 쓴다. */
|
|
96
|
-
export const ENERGY_METRICS = ['projectedKW', 'peakKW', 'overWindows'] as const
|
|
97
|
-
export const FLOW_METRICS = ['items', 'occupancy', 'tasks', 'orders', 'shipped', 'backlog'] as const
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* 트윈 종류에 맞는 지표 목록 — **한 곳에서 정한다.**
|
|
101
|
-
*
|
|
102
|
-
* 화면이 각자 목록을 들고 있으면 종류가 늘 때 어느 화면이 뒤처졌는지 알 수 없다.
|
|
103
|
-
*/
|
|
104
|
-
export function metricsForKind(kind?: string): string[] {
|
|
105
|
-
return kind === 'ems' ? [...ENERGY_METRICS] : [...FLOW_METRICS]
|
|
106
|
-
}
|