@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,146 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* 현장의 조업 달력이 계획 조업 시간에 닿나.
|
|
3
|
-
*
|
|
4
|
-
* ── 왜 필요한가 (2026-09-07) ────────────────────────────────────────────────
|
|
5
|
-
* 계획 조업 시간(PBT)이 「재기 시작한 뒤 흐른 시간 전부」였다. 주말도 야간도 휴일도 계획 조업으로
|
|
6
|
-
* 세었다. [산술] 8시간 × 주5일이면 168시간 중 40시간이 조업이니 PBT 가 4.2배 크다.
|
|
7
|
-
*
|
|
8
|
-
* plant 레인이 같은 자리를 먼저 겪고 실측을 냈다 — 3교대를 물려받으면 `availability 0.4583`,
|
|
9
|
-
* 달력이 아예 없으면 수를 안 낸다. 트윈은 창 전체를 계획으로 쳐서 수를 냈다.
|
|
10
|
-
*
|
|
11
|
-
* ── 이 시험이 지키는 것은 「자리가 있고 부르는 곳이 있다」다 ─────────────────
|
|
12
|
-
* 오늘 이 저장소에서 그것을 여섯 번 놓쳤다. 값을 받을 칸을 만들고 아무도 채우지 않거나, 채우고
|
|
13
|
-
* 아무도 안 읽는 자리다. 그래서 여기서는 **누적기가 그 값을 실제로 쓰는지**를 본다 — 달력을 얹은
|
|
14
|
-
* 것과 안 얹은 것의 답이 달라야 한다.
|
|
15
|
-
*/
|
|
16
|
-
import test from 'node:test'
|
|
17
|
-
import assert from 'node:assert/strict'
|
|
18
|
-
|
|
19
|
-
import { OeeAccumulator } from '../server/engine/oee-accumulator.js'
|
|
20
|
-
|
|
21
|
-
const HOUR = 3_600_000
|
|
22
|
-
const MON = Date.UTC(2026, 8, 7, 0, 0, 0)
|
|
23
|
-
|
|
24
|
-
/** 08:00~16:00 만 조업 — 하루 열여섯 시간이 비근무다. */
|
|
25
|
-
const EIGHT_HOURS = [{ id: 'day', fromTime: '08:00', toTime: '16:00' }] as any[]
|
|
26
|
-
|
|
27
|
-
/** 여덟 시간 내내 돈 설비 한 대. */
|
|
28
|
-
function ranAllShift(calendar?: any[]) {
|
|
29
|
-
const acc = new OeeAccumulator()
|
|
30
|
-
acc.setWorkCalendar(calendar ? { workCalendar: calendar } : undefined)
|
|
31
|
-
/*
|
|
32
|
-
* 봉투의 `data` 에 `moverId` 다 — `payload.data` 도 `equipmentId` 도 아니다. 처음 그렇게 써서
|
|
33
|
-
* 누적기가 아무것도 안 받았고, 시험 넷이 빨개져서 알았다. 읽어서 고쳤다(`oee-accumulator.ts:111`).
|
|
34
|
-
*/
|
|
35
|
-
acc.apply({
|
|
36
|
-
eventType: 'equipment.status',
|
|
37
|
-
eventTime: new Date(MON + 8 * HOUR).toISOString(),
|
|
38
|
-
data: { moverId: 'EQ-1', status: 'busy' }
|
|
39
|
-
} as any)
|
|
40
|
-
|
|
41
|
-
return acc.counters('EQ-1', MON + 24 * HOUR)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
test('달력을 얹으면 계획 정지가 나온다 — 계측 창 안의 비근무만', () => {
|
|
45
|
-
/*
|
|
46
|
-
* ⚠ 하루가 아니다. 계측 창은 **첫 이벤트부터**이므로 08:00~24:00 의 열여섯 시간이고, 그중 조업이
|
|
47
|
-
* 08:00~16:00 이니 비근무가 여덟 시간이다.
|
|
48
|
-
*
|
|
49
|
-
* 처음 이 값을 열여섯으로 적었다 — 「하루 중 열여섯 시간이 비근무」라는 달력의 성질을 계측 창에
|
|
50
|
-
* 그대로 옮긴 것이다. 재보고 고쳤다. 계획 정지는 **달력의 성질이 아니라 이 창에서 잰 값**이다.
|
|
51
|
-
*/
|
|
52
|
-
const c = ranAllShift(EIGHT_HOURS) as any
|
|
53
|
-
|
|
54
|
-
assert.equal(c.holdMs, 8 * HOUR)
|
|
55
|
-
assert.equal(c.metricsSinceMs, MON + 8 * HOUR, '창이 첫 이벤트부터라는 것이 위 계산의 전제다')
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('달력이 없으면 그 칸을 만들지 않는다 — 0 은 「쉬는 시간이 없다」는 주장이다', () => {
|
|
59
|
-
const c = ranAllShift() as any
|
|
60
|
-
|
|
61
|
-
assert.equal('holdMs' in c, false)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
test('얹은 것과 안 얹은 것의 답이 다르다 — 같으면 그 값이 안 쓰이는 것이다', () => {
|
|
65
|
-
/*
|
|
66
|
-
* 이 시험이 이 파일의 요점이다. 오늘 제가 낸 결함 중 하나가 「값을 넣어 줄 사람이 있는지 아무것도
|
|
67
|
-
* 검사하지 않은 시험」이었다 — 고쳐도 통과하고 안 고쳐도 통과했다.
|
|
68
|
-
*/
|
|
69
|
-
const withCal = ranAllShift(EIGHT_HOURS) as any
|
|
70
|
-
const without = ranAllShift() as any
|
|
71
|
-
|
|
72
|
-
assert.notEqual(withCal.holdMs, without.holdMs)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
test('실 생산 시간은 달력과 무관하다 — APT 는 잰 값이다', () => {
|
|
76
|
-
/*
|
|
77
|
-
* 달력은 PBT 를 정하고 APT 는 안 건드린다. 휴일에 돌린 열한 시간이 사라지던 것이 그 반대 방향의
|
|
78
|
-
* 결함이었고, 그것은 자르는 쪽이었다.
|
|
79
|
-
*/
|
|
80
|
-
const withCal = ranAllShift(EIGHT_HOURS)
|
|
81
|
-
const without = ranAllShift()
|
|
82
|
-
|
|
83
|
-
assert.equal(withCal.runMs, without.runMs)
|
|
84
|
-
assert.equal(withCal.runMs, 16 * HOUR, '08:00 에 busy 로 들어가 24:00 까지면 열여섯 시간이다')
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
test('잰 구간의 시작은 그대로다 — 그 칸에 파생값을 얹지 않는다', () => {
|
|
88
|
-
/*
|
|
89
|
-
* 같은 효과를 `metricsSinceMs` 를 당겨서 낼 수도 있는데, 그 칸은 「언제부터 쟀나」라는 사실이다.
|
|
90
|
-
* plant 레인이 그 방식으로 하고 있었고 `holdMs` 로 옮겼다 — 수는 자릿수까지 같았다.
|
|
91
|
-
*/
|
|
92
|
-
const c = ranAllShift(EIGHT_HOURS)
|
|
93
|
-
|
|
94
|
-
assert.equal(c.metricsSinceMs, MON + 8 * HOUR)
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
/*
|
|
98
|
-
* ── 설비의 달력이 현장의 것을 이긴다 ────────────────────────────────────────
|
|
99
|
-
* 이 자리가 실제 자료를 살렸다. rosarito 트윈들이 설비 41대에 3교대 × 평일 달력을 이미 갖고 있었는데,
|
|
100
|
-
* 처음 배선할 때 **현장 달력만 읽었다.** 현장에 달력을 선언한 공간이 하나도 없어서, 있는 자료를 두고
|
|
101
|
-
* 계획 조업 시간이 창 전체로 남아 있었다.
|
|
102
|
-
*
|
|
103
|
-
* 사용자가 「모든 공간에 달력을 세우라」고 한 것이 그 말을 듣고 나온 지시였고, 재보니 세울 것이 아니라
|
|
104
|
-
* **읽을 것이 있었다.**
|
|
105
|
-
*/
|
|
106
|
-
const ROUND_CLOCK = [{ id: 'always', fromTime: '00:00', toTime: '24:00' }] as any[]
|
|
107
|
-
|
|
108
|
-
function withModel(model: any) {
|
|
109
|
-
const acc = new OeeAccumulator()
|
|
110
|
-
acc.setWorkCalendar(model)
|
|
111
|
-
acc.apply({
|
|
112
|
-
eventType: 'equipment.status',
|
|
113
|
-
eventTime: new Date(MON + 8 * HOUR).toISOString(),
|
|
114
|
-
data: { moverId: 'EQ-1', status: 'busy' }
|
|
115
|
-
} as any)
|
|
116
|
-
|
|
117
|
-
return acc.counters('EQ-1', MON + 24 * HOUR) as any
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
test('설비가 자기 달력을 선언하면 그것을 쓴다 — 24시간 도는 로가 현장 근무조에 안 잘린다', () => {
|
|
121
|
-
const c = withModel({ workCalendar: EIGHT_HOURS, equipment: [{ id: 'EQ-1', workCalendar: ROUND_CLOCK }] })
|
|
122
|
-
|
|
123
|
-
assert.equal(c.holdMs, 0, '자기 달력이 종일 가동이면 계획 정지가 없다')
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
test('설비가 선언하지 않으면 현장의 달력으로 떨어진다', () => {
|
|
127
|
-
const c = withModel({ workCalendar: EIGHT_HOURS, equipment: [{ id: 'EQ-OTHER', workCalendar: ROUND_CLOCK }] })
|
|
128
|
-
|
|
129
|
-
assert.equal(c.holdMs, 8 * HOUR, '이 설비의 것이 없으니 현장 것을 쓴다')
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
test('현장이 없고 설비만 있어도 답한다 — 지금 실제 자료가 그 모양이다', () => {
|
|
133
|
-
/*
|
|
134
|
-
* rosarito 가 이렇다: 공간에 달력이 없고 설비 41대에 3교대가 있다. 현장 달력만 읽으면 이 자료가
|
|
135
|
-
* 통째로 안 쓰인다.
|
|
136
|
-
*/
|
|
137
|
-
const c = withModel({ equipment: [{ id: 'EQ-1', workCalendar: EIGHT_HOURS }] })
|
|
138
|
-
|
|
139
|
-
assert.equal(c.holdMs, 8 * HOUR)
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
test('둘 다 없으면 그 칸을 만들지 않는다', () => {
|
|
143
|
-
const c = withModel({ equipment: [{ id: 'EQ-1' }] })
|
|
144
|
-
|
|
145
|
-
assert.equal('holdMs' in c, false)
|
|
146
|
-
})
|
package/test/open-doors.test.ts
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Which of headless-twin's doors are open, and why each one is allowed to be.
|
|
3
|
-
*
|
|
4
|
-
* ── The thing this catches ──────────────────────────────────────────────────
|
|
5
|
-
* `@privilege` is opt-in. A root field that declares nothing is recorded as open, and that is
|
|
6
|
-
* indistinguishable from a field somebody decided to open. The list below turns the absence into a
|
|
7
|
-
* statement: anything open that is not on it fails, and the reason has to be written first.
|
|
8
|
-
* Same measure as `auth-base/tests/open-doors.test.ts`.
|
|
9
|
-
*
|
|
10
|
-
* ── The decision the reads rest on ──────────────────────────────────────────
|
|
11
|
-
* ADR-0027: the twin gates **writes** only. Reading is the product's purpose, and the boundary for a
|
|
12
|
-
* read is tenant membership — so an ungated read is correct only if its body narrows to the caller's
|
|
13
|
-
* domain. Every entry below says how it does. (The one read that crosses tenants on purpose,
|
|
14
|
-
* `twinLoad`, is super-user gated and so is not here.) A door that answers from the installation
|
|
15
|
-
* rather than from any tenant's rows says so instead.
|
|
16
|
-
*
|
|
17
|
-
* ── Why this reads the build ────────────────────────────────────────────────
|
|
18
|
-
* The schema is built from `service/index`'s own `resolverClasses`, the list the server boots from.
|
|
19
|
-
* type-graphql needs decorator metadata to build it, and Node's type stripping (how the other tests
|
|
20
|
-
* here run the source) does not emit it. So this one reads `dist-server`. A stale build would miss a
|
|
21
|
-
* door added since, and pass — hence the freshness check before anything else.
|
|
22
|
-
*/
|
|
23
|
-
import { test } from 'node:test'
|
|
24
|
-
import assert from 'node:assert/strict'
|
|
25
|
-
import { createRequire } from 'node:module'
|
|
26
|
-
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'
|
|
27
|
-
import { dirname, join, relative } from 'node:path'
|
|
28
|
-
import { fileURLToPath } from 'node:url'
|
|
29
|
-
|
|
30
|
-
const PKG = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
31
|
-
const DIST = join(PKG, 'dist-server')
|
|
32
|
-
|
|
33
|
-
/* Resolver sources newer than their build: the schema below would not be the one served. */
|
|
34
|
-
function staleResolvers(): string[] {
|
|
35
|
-
const out: string[] = []
|
|
36
|
-
const walk = (dir: string) => {
|
|
37
|
-
for (const name of readdirSync(dir)) {
|
|
38
|
-
const p = join(dir, name)
|
|
39
|
-
if (statSync(p).isDirectory()) walk(p)
|
|
40
|
-
else if (p.endsWith('.ts') && /@(Query|Mutation|Subscription)\(/.test(readFileSync(p, 'utf8'))) {
|
|
41
|
-
const built = join(DIST, relative(join(PKG, 'server'), p)).replace(/\.ts$/, '.js')
|
|
42
|
-
if (!existsSync(built) || statSync(built).mtimeMs < statSync(p).mtimeMs) out.push(relative(PKG, p))
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
walk(join(PKG, 'server'))
|
|
47
|
-
return out
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const INSTALLATION = 'answers from the installation, not from any tenant\'s rows'
|
|
51
|
-
const DOMAIN_ROWS = 'reads rows where domain = the caller\'s'
|
|
52
|
-
const DOMAIN_RUNTIME = 'reads the runtime keyed (caller\'s domain, instanceId)'
|
|
53
|
-
|
|
54
|
-
/** Open on purpose (ADR-0027), each with how it stays inside the caller's tenant. */
|
|
55
|
-
const OPEN_BY_DECISION: Record<'Query' | 'Subscription', Record<string, string>> = {
|
|
56
|
-
Query: {
|
|
57
|
-
/* Catalogues — what this build can do. */
|
|
58
|
-
referenceAdapterTypes: `${INSTALLATION}: registered connector type keys`,
|
|
59
|
-
referenceAdapters: `${INSTALLATION}: connector metadata and judged capabilities`,
|
|
60
|
-
twinDomainCatalog: `${INSTALLATION}: the kernel's location-type vocabulary`,
|
|
61
|
-
twinTargetMetrics: `${INSTALLATION}: the metric ids a target may name`,
|
|
62
|
-
twinTemplates: `${INSTALLATION}: registered twin templates and their knobs`,
|
|
63
|
-
|
|
64
|
-
/* Connections and references. */
|
|
65
|
-
discoverReferenceSites: `${DOMAIN_ROWS} (TwinReference by source), then asks that connection`,
|
|
66
|
-
referenceSources: `${DOMAIN_ROWS} (TwinInstance) and the caller's runtimes`,
|
|
67
|
-
twinConnection: `${DOMAIN_ROWS} (TwinReference, TwinInstance)`,
|
|
68
|
-
twinConnections: `${DOMAIN_ROWS} (TwinReference, TwinInstance)`,
|
|
69
|
-
twinReference: `${DOMAIN_ROWS} (TwinReference)`,
|
|
70
|
-
twinReferences: `${DOMAIN_ROWS} (TwinReference, TwinInstance)`,
|
|
71
|
-
twinReferenceReconciliation: `${DOMAIN_ROWS} (TwinReferenceReconciliation)`,
|
|
72
|
-
twinReferenceReconciliations: `${DOMAIN_ROWS} (TwinReferenceReconciliation)`,
|
|
73
|
-
|
|
74
|
-
/* Actuation — reading what was proposed and how it went. Acting is gated. */
|
|
75
|
-
twinActuationOpinion: 'loads the command by (caller\'s domain, id); refuses without a domain',
|
|
76
|
-
twinActuationOutcome: 'loads the command by (caller\'s domain, id); refuses without a domain',
|
|
77
|
-
twinActuationReadiness: 'loads the command by (caller\'s domain, id); refuses without a domain',
|
|
78
|
-
twinActuationRules: `${DOMAIN_ROWS} (TwinActuationRule list params with the caller's domain)`,
|
|
79
|
-
twinCommands: `${DOMAIN_ROWS} (TwinCommandRecord list params with the caller's domain)`,
|
|
80
|
-
|
|
81
|
-
/* Instances and lifecycle. */
|
|
82
|
-
twinAdoptionPath: `${DOMAIN_ROWS} after an ownership check`,
|
|
83
|
-
twinDeletionPreview: `${DOMAIN_ROWS} (TwinInstance, TwinEvent) — describes, deletes nothing`,
|
|
84
|
-
twinInstanceDetail: `${DOMAIN_ROWS} (TwinEngine.detail)`,
|
|
85
|
-
twinInstanceList: `${DOMAIN_ROWS} (TwinEngine.list)`,
|
|
86
|
-
twinInstances: `${DOMAIN_ROWS} (TwinEngine.list)`,
|
|
87
|
-
twinSourceCapability: `${DOMAIN_RUNTIME}; empty without a domain`,
|
|
88
|
-
twinSpaceInstanceIds: `${DOMAIN_ROWS} (TwinEngine.instanceIdsOfSpace)`,
|
|
89
|
-
|
|
90
|
-
/* Journal, history, time travel. */
|
|
91
|
-
twinAuditList: `${DOMAIN_ROWS} (TwinAuditEvent list params with the caller's domain)`,
|
|
92
|
-
twinCapacity: `${DOMAIN_RUNTIME} after an ownership check`,
|
|
93
|
-
twinEventList: `${DOMAIN_ROWS} (TwinEvent) for targets resolved inside the caller's domain`,
|
|
94
|
-
twinEvents: `${DOMAIN_ROWS} (TwinEvent)`,
|
|
95
|
-
twinKpi: `${DOMAIN_ROWS} after an ownership check`,
|
|
96
|
-
twinOperationsCapability: `${DOMAIN_RUNTIME} after an ownership check`,
|
|
97
|
-
twinReplay: `${DOMAIN_RUNTIME} or its journal (TwinEngine.recover)`,
|
|
98
|
-
twinStructures: `${DOMAIN_ROWS} (TwinStructure, TwinEvent) after an ownership check`,
|
|
99
|
-
twinSubjectHistory: `${DOMAIN_ROWS} (TwinSubjectEvent)`,
|
|
100
|
-
twinTimeRange: `${DOMAIN_ROWS} (TwinInstance, TwinEvent)`,
|
|
101
|
-
|
|
102
|
-
/* Model and entity views. */
|
|
103
|
-
spaceDeclarations: `${DOMAIN_ROWS} (TwinSpace, TwinInstance) and the caller's runtimes`,
|
|
104
|
-
twinDeclarations: `${DOMAIN_ROWS} (TwinInstance, TwinSpace) and the caller's runtime`,
|
|
105
|
-
twinItemLineage: `${DOMAIN_ROWS} (TwinInstance, TwinEvent)`,
|
|
106
|
-
twinModelEntities: `${DOMAIN_ROWS} (TwinInstance and the entity tables) or the caller's runtime`,
|
|
107
|
-
twinModelItem: `${DOMAIN_ROWS} (TwinInstance and the entity tables) or the caller's runtime`,
|
|
108
|
-
twinModelSummary: `${DOMAIN_ROWS} (TwinInstance, TwinReference, TwinEvent) or the caller's runtime`,
|
|
109
|
-
twinModelTree: `${DOMAIN_ROWS} (TwinInstance)`,
|
|
110
|
-
|
|
111
|
-
/* Spaces and targets. */
|
|
112
|
-
twinAreas: `${DOMAIN_ROWS} (TwinArea)`,
|
|
113
|
-
twinSpace: `${DOMAIN_ROWS} (TwinSpace, representations, areas)`,
|
|
114
|
-
twinSpaceIntegrity: `${DOMAIN_ROWS} (every space table)`,
|
|
115
|
-
twinSpaces: `${DOMAIN_ROWS} (TwinSpace, representations, TwinInstance)`,
|
|
116
|
-
twinTargets: `${DOMAIN_ROWS} (TwinTarget)`,
|
|
117
|
-
|
|
118
|
-
/* Live health and forecasting — computed from the caller's runtime. */
|
|
119
|
-
twinAttentionDigest: `${DOMAIN_RUNTIME} after an ownership check`,
|
|
120
|
-
twinAttentions: `${DOMAIN_RUNTIME} after an ownership check`,
|
|
121
|
-
twinForecast: `${DOMAIN_RUNTIME} (forks the caller's kernel)`,
|
|
122
|
-
twinForecastGapTrend: `${DOMAIN_RUNTIME} for the caller's co-located twins`,
|
|
123
|
-
twinIngestHealth: `${DOMAIN_RUNTIME} after an ownership check; raw samples need more`,
|
|
124
|
-
twinIngestHistory: `${DOMAIN_ROWS} (TwinIngestWindow) and the caller's runtime`,
|
|
125
|
-
twinMetrics: `${DOMAIN_RUNTIME} after an ownership check`,
|
|
126
|
-
twinMetricsAll: `${DOMAIN_RUNTIME} for every runtime of the caller's domain`
|
|
127
|
-
},
|
|
128
|
-
Subscription: {
|
|
129
|
-
twinState: 'the caller must own the instance to subscribe (ADR-0027 read)',
|
|
130
|
-
twinReferenceProgress: 'import progress for one source (ADR-0027 read)'
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const req = createRequire(import.meta.url)
|
|
135
|
-
let schemaPromise: Promise<any> | undefined
|
|
136
|
-
|
|
137
|
-
function schema(): Promise<any> {
|
|
138
|
-
const stale = staleResolvers()
|
|
139
|
-
if (stale.length) {
|
|
140
|
-
throw new Error(
|
|
141
|
-
`dist-server is older than ${stale.length} resolver source(s), so the schema below is not the one served:\n ` +
|
|
142
|
-
stale.join('\n ') +
|
|
143
|
-
'\nBuild first: yarn workspace @things-factory/headless-twin build:server'
|
|
144
|
-
)
|
|
145
|
-
}
|
|
146
|
-
schemaPromise ??= (async () => {
|
|
147
|
-
req('reflect-metadata')
|
|
148
|
-
const { buildSchema } = req('type-graphql')
|
|
149
|
-
const { schema: declared } = req(join(DIST, 'service/index.js'))
|
|
150
|
-
const { privilegeDirectiveResolver } = req('@things-factory/auth-base/dist-server/service/privilege/privilege-directive.js')
|
|
151
|
-
/* Subscriptions need a PubSub to build. Nothing is published here — only the shape is read. */
|
|
152
|
-
const pubSub = { publish() {}, subscribe: () => (async function* () {})() }
|
|
153
|
-
const built = await buildSchema({ resolvers: declared.resolverClasses, validate: false, pubSub })
|
|
154
|
-
privilegeDirectiveResolver(built)
|
|
155
|
-
return built
|
|
156
|
-
})()
|
|
157
|
-
return schemaPromise
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const privilegeOfField = (t: string, f: string) =>
|
|
161
|
-
req('@things-factory/auth-base/dist-server/service/privilege/privilege-directive.js').privilegeOfField(t, f)
|
|
162
|
-
|
|
163
|
-
async function fieldsOf(typeName: 'Query' | 'Mutation' | 'Subscription'): Promise<string[]> {
|
|
164
|
-
const s = await schema()
|
|
165
|
-
const type = typeName === 'Query' ? s.getQueryType() : typeName === 'Mutation' ? s.getMutationType() : s.getSubscriptionType()
|
|
166
|
-
return Object.keys(type?.getFields() ?? {})
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
async function openFields(typeName: 'Query' | 'Mutation' | 'Subscription'): Promise<string[]> {
|
|
170
|
-
return (await fieldsOf(typeName)).filter(f => {
|
|
171
|
-
const gate = privilegeOfField(typeName, f)
|
|
172
|
-
return gate.known && gate.gate === null
|
|
173
|
-
})
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
test('every open read is one somebody chose, with how it stays in the caller\'s tenant', async () => {
|
|
177
|
-
for (const t of ['Query', 'Subscription'] as const) {
|
|
178
|
-
assert.deepEqual((await openFields(t)).sort(), Object.keys(OPEN_BY_DECISION[t]).sort(), `${t}: open fields ≠ OPEN_BY_DECISION`)
|
|
179
|
-
}
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
test('no write is open — ADR-0027 gates every mutation', async () => {
|
|
183
|
-
assert.deepEqual(await openFields('Mutation'), [])
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
test('the walk reaches the whole schema, not a handful of fields', async () => {
|
|
187
|
-
/* If the resolver list shrank to nothing, the two tests above would pass by having nothing to look at. */
|
|
188
|
-
assert.ok((await fieldsOf('Query')).length > 50)
|
|
189
|
-
assert.ok((await fieldsOf('Mutation')).length > 40)
|
|
190
|
-
assert.ok((await fieldsOf('Subscription')).length >= 2)
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
test('an undeclared field is told apart from one the schema does not have', async () => {
|
|
194
|
-
await schema()
|
|
195
|
-
/* `known: false` must never read as open — that is how a typo becomes a gate that is not there. */
|
|
196
|
-
assert.deepEqual(privilegeOfField('Query', 'noSuchField'), { known: false })
|
|
197
|
-
})
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* 공정 목록 — **무엇을 돌리고, 그 시간이 어디서 오나.**
|
|
3
|
-
*
|
|
4
|
-
* ── 왜 이 목록이 필요한가 (2026-08-18) ─────────────────────────────────────
|
|
5
|
-
* 「측정이 없을 때의 표준 시간」을 현장이 선언하려면 먼저 무엇에 선언할지 보여야 한다. 그런데 실측으로
|
|
6
|
-
* 운영 중인 트윈 35개 중 **창고·야드는 공정 명세 행이 0개**였다 — 모델만 보면 「공정이 없다」로 읽힌다.
|
|
7
|
-
* 실제로는 `putaway`·`spot` 을 돌리고 있고, 그 사실은 **커널만 안다**(`specCoverage`).
|
|
8
|
-
*
|
|
9
|
-
* 그래서 이 모듈이 지키는 것:
|
|
10
|
-
* ① 목록을 지어내지 않는다 — 원천 행·커널 보고·우리 선언, 세 곳에서만 모은다.
|
|
11
|
-
* ② 돌지 않은 트윈에서 「공정이 없다」고 말하지 않는다 — `basis` 가 비는 것으로 모름을 드러낸다.
|
|
12
|
-
* ③ 선언해 둔 공정이 목록에서 사라지지 않는다(그러면 철회할 자리가 없어진다).
|
|
13
|
-
*/
|
|
14
|
-
import { test } from 'node:test'
|
|
15
|
-
import assert from 'node:assert/strict'
|
|
16
|
-
|
|
17
|
-
import { readFileSync } from 'node:fs'
|
|
18
|
-
import { fileURLToPath } from 'node:url'
|
|
19
|
-
|
|
20
|
-
import { operationBasis, knownOperationKinds } from '../server/engine/operation-basis.ts'
|
|
21
|
-
|
|
22
|
-
/** 커널 흉내 — 자기보고만 낸다(이 모듈이 커널에서 읽는 것은 그것뿐이다). */
|
|
23
|
-
const kernelReporting = (ops: { kind: string; duration: 'measured' | 'declared' | 'default' }[]) => ({
|
|
24
|
-
specCoverage: () => ({
|
|
25
|
-
operations: ops.map(o => ({ ...o, parameters: [] })),
|
|
26
|
-
measuredDurations: ops.filter(o => o.duration === 'measured').length,
|
|
27
|
-
declaredDurations: ops.filter(o => o.duration === 'declared').length,
|
|
28
|
-
defaultDurations: ops.filter(o => o.duration === 'default').length
|
|
29
|
-
})
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('행이 없는 트윈에서도 돌린 공정이 나온다 — 창고·야드가 바로 그 경우다', () => {
|
|
33
|
-
const rows = operationBasis({ locations: [], equipment: [] }, kernelReporting([{ kind: 'putaway', duration: 'default' }]))
|
|
34
|
-
assert.deepEqual(rows, [{ kind: 'putaway', basis: 'default' }])
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('원천 명세 행은 이름과 시간을 함께 든다 — 우리 선언이 그것을 이긴다', () => {
|
|
38
|
-
const model = { operations: [{ key: 'weld', label: 'Welding', intent: 'process', duration: 'PT90S' }], localDurations: { weld: 'PT60S' } }
|
|
39
|
-
const rows = operationBasis(model, kernelReporting([{ kind: 'weld', duration: 'declared' }]))
|
|
40
|
-
assert.deepEqual(rows, [{ kind: 'weld', label: 'Welding', referenceDuration: 'PT90S', basis: 'declared', localDuration: 'PT60S' }])
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test('정지 트윈은 basis 가 빈다 — 「공정이 없다」가 아니라 「모른다」다', () => {
|
|
44
|
-
const rows = operationBasis({ operations: [{ key: 'pick', label: 'Pick' }] }, undefined)
|
|
45
|
-
assert.deepEqual(rows, [{ kind: 'pick', label: 'Pick' }])
|
|
46
|
-
assert.equal(rows[0].basis, undefined)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
test('선언해 둔 공정은 커널이 아직 돌리지 않아도 목록에 남는다 — 철회할 자리가 사라지지 않게', () => {
|
|
50
|
-
const rows = operationBasis({ localDurations: { spot: 'PT300S' } }, kernelReporting([]))
|
|
51
|
-
assert.deepEqual(rows, [{ kind: 'spot', localDuration: 'PT300S' }])
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
test('아무 근거도 없으면 목록을 지어내지 않는다 — 빈 배열이다', () => {
|
|
55
|
-
assert.deepEqual(operationBasis({}, undefined), [])
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('확인 목록은 하나도 없을 때 undefined 다 — 빈 배열은 「아무것도 안 된다」로 읽힌다', () => {
|
|
59
|
-
assert.equal(knownOperationKinds({}, undefined), undefined)
|
|
60
|
-
assert.deepEqual(knownOperationKinds({}, kernelReporting([{ kind: 'putaway', duration: 'default' }])), ['putaway'])
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
test('커널이 보고하지 못해도 터지지 않는다 — 옛 커널에서도 목록은 나온다', () => {
|
|
64
|
-
const rows = operationBasis({ operations: [{ key: 'pick', label: 'Pick' }] }, { tick: () => {} })
|
|
65
|
-
assert.deepEqual(rows, [{ kind: 'pick', label: 'Pick' }])
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
/*
|
|
69
|
-
* ── 재기동 직후의 빈칸 (2026-08-18 실측) ────────────────────────────────────
|
|
70
|
-
* 커널의 자기보고는 **작업이 새로 생길 때** 채워진다. 그래서 이력이 풍부한 창고 트윈(pick·putaway 를
|
|
71
|
-
* 이미 배운 트윈)도 재기동 직후에는 목록이 비었다 — 값을 채울 곳을 보여야 하는 화면이 그때 아무 말도
|
|
72
|
-
* 못 한다. 이력에서 배운 종류를 넷째 근거로 넣어 그 빈칸을 메운다.
|
|
73
|
-
*/
|
|
74
|
-
test('이력에서 배운 종류가 목록에 나온다 — 재기동 직후에도 빈칸이 아니다', () => {
|
|
75
|
-
const rows = operationBasis({}, kernelReporting([]), ['pick', 'putaway'])
|
|
76
|
-
assert.deepEqual(rows, [{ kind: 'pick', basis: 'measured' }, { kind: 'putaway', basis: 'measured' }])
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
test('커널이 실제로 돌린 사실이 이력 목록을 덮지 않는다 — 더 강한 사실이 이긴다', () => {
|
|
80
|
-
const rows = operationBasis({}, kernelReporting([{ kind: 'putaway', duration: 'default' }]), ['putaway'])
|
|
81
|
-
assert.deepEqual(rows, [{ kind: 'putaway', basis: 'default' }], '지금 상수로 돌고 있으면 그렇게 말한다')
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
test('이력 목록은 선언 대조에도 쓰인다 — 오타를 그때부터 잡는다', () => {
|
|
85
|
-
assert.deepEqual(knownOperationKinds({}, undefined, ['pick']), ['pick'])
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
/*
|
|
89
|
-
* ── 도는 시뮬레이션은 「저장했다」가 아니다 (2026-08-18 실측) ────────────────
|
|
90
|
-
* 시뮬 기동 경로가 `mode` 를 비워 두어(「미지정=sim」 규약에 기대) `modeOf()` 가 도는 트윈에 undefined 를
|
|
91
|
-
* 답했다. 그래서 선언·철회의 답이 「저장했다」로 나갔다 — 실제로는 도는 커널이 옛 수를 쓰고 재기동 때
|
|
92
|
-
* 받는데, 사용자는 지금 화면의 수가 새 값으로 계산된 줄로 읽는다. 사실을 적는 쪽으로 고쳤다.
|
|
93
|
-
*/
|
|
94
|
-
test('시뮬 기동이 모드를 적는다 — 「돌고 있나」를 묻는 쪽이 답을 받아야 한다', () => {
|
|
95
|
-
const src = readFileSync(fileURLToPath(new URL('../server/engine/twin-engine.ts', import.meta.url)), 'utf-8')
|
|
96
|
-
assert.match(src, /mode: 'sim',\s*\n\s*runtime/, '시뮬 런타임도 모드를 든다')
|
|
97
|
-
/* 답이 갈리는 자리 — 도는 트윈이면 「재기동 때 받는다」로 말해야 한다. */
|
|
98
|
-
const mut = readFileSync(fileURLToPath(new URL('../server/service/twin-model/twin-model-mutation.ts', import.meta.url)), 'utf-8')
|
|
99
|
-
assert.match(mut, /running \? 'on-restart' : 'stored'/)
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
/*
|
|
103
|
-
* ── 공정 모수도 목록에 실린다 (2026-08-19) ──────────────────────────────────
|
|
104
|
-
* 수율·셋업은 시간과 다른 표에 담긴다(`localParams`). 목록이 그것을 함께 들지 않으면 선언해 둔 값이
|
|
105
|
-
* 화면에서 사라지고, 그러면 철회할 자리도 없어진다. 원천이 말한 모수도 함께 들어 견줄 수 있게 한다.
|
|
106
|
-
*/
|
|
107
|
-
test('선언한 모수와 원천 모수를 함께 든다 — 무엇을 고쳤나가 보인다', () => {
|
|
108
|
-
const model = {
|
|
109
|
-
operations: [{ key: 'weld', label: 'Welding', intent: 'process', parameters: [{ id: 'yield', value: '0.7' }] }],
|
|
110
|
-
localParams: { weld: { yield: '0.92', setupDuration: 'PT30S' } }
|
|
111
|
-
}
|
|
112
|
-
const rows = operationBasis(model, kernelReporting([{ kind: 'weld', duration: 'declared' }]))
|
|
113
|
-
assert.deepEqual(rows, [
|
|
114
|
-
{
|
|
115
|
-
kind: 'weld',
|
|
116
|
-
label: 'Welding',
|
|
117
|
-
referenceParams: { yield: '0.7' },
|
|
118
|
-
basis: 'declared',
|
|
119
|
-
localParams: { yield: '0.92', setupDuration: 'PT30S' }
|
|
120
|
-
}
|
|
121
|
-
])
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
test('모수만 선언한 공정도 목록에 남는다 — 커널이 아직 돌리지 않았어도', () => {
|
|
125
|
-
const rows = operationBasis({ localParams: { inspect: { yield: '0.99' } } }, undefined)
|
|
126
|
-
assert.deepEqual(rows, [{ kind: 'inspect', localParams: { yield: '0.99' } }])
|
|
127
|
-
})
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* **라이브 문이 운영 사실을 안다** — 미러가 시뮬보다 가난하지 않게 (ADR-0029 어휘 넓히기, 2026-08-19).
|
|
3
|
-
*
|
|
4
|
-
* ── 무엇이 막혀 있었나 ──────────────────────────────────────────────────────
|
|
5
|
-
* 이 문(`ingestCanonicalRecords`)은 어휘를 셋만 알았다: EPCIS 품목 · 에너지 계량 · 설비 에너지. 그리고
|
|
6
|
-
* **모르는 것은 EPCIS 로 떨어졌다** — 작업 사실을 넣으면 `epc` 가 없어 거부됐고, 원본은 「이 작업이
|
|
7
|
-
* 끝났다」를 말할 길이 없었다. 시뮬 커널만 그것을 알고 미러는 영원히 몰랐다.
|
|
8
|
-
*
|
|
9
|
-
* ── 이 시험이 지키는 것 ─────────────────────────────────────────────────────
|
|
10
|
-
* ① 네 어휘가 **한 문**에서 갈린다(판정은 커널의 것이고 여기서 다시 짐작하지 않는다).
|
|
11
|
-
* ② 운영 사실이 자기 봉투로 나온다 — EPCIS 로 감싸지지 않는다.
|
|
12
|
-
* ③ 섞여 와도 갈린다(실 피드는 한 배치에 여러 어휘가 섞인다).
|
|
13
|
-
* ④ 거부는 이유와 함께 남는다 — 피드 결선이 그 이유를 사람에게 말한다.
|
|
14
|
-
*/
|
|
15
|
-
import { test } from 'node:test'
|
|
16
|
-
import assert from 'node:assert/strict'
|
|
17
|
-
import { readFileSync } from 'node:fs'
|
|
18
|
-
import { fileURLToPath } from 'node:url'
|
|
19
|
-
|
|
20
|
-
import { ingestCanonicalRecords } from '../server/engine/canonical-ingest.ts'
|
|
21
|
-
|
|
22
|
-
const AT = '2026-08-19T09:00:00.000Z'
|
|
23
|
-
|
|
24
|
-
test('운영 사실이 자기 봉투로 나온다 — EPCIS 로 감싸지지 않는다', () => {
|
|
25
|
-
const { accepted, rejected } = ingestCanonicalRecords(
|
|
26
|
-
[{ taskId: 'tk-1', kind: 'putaway', status: 'completed' } as any],
|
|
27
|
-
'domain-1',
|
|
28
|
-
AT
|
|
29
|
-
)
|
|
30
|
-
assert.deepEqual(rejected, [])
|
|
31
|
-
assert.equal(accepted.length, 1)
|
|
32
|
-
assert.equal(accepted[0].eventType, 'task.status')
|
|
33
|
-
assert.equal(accepted[0].eventTime, AT, '시각을 주지 않으면 이 문이 정한 기본 시각을 쓴다')
|
|
34
|
-
assert.equal(accepted[0].tenantId, 'domain-1')
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('네 어휘가 한 배치에서 갈린다 — 실 피드는 섞여 온다', () => {
|
|
38
|
-
const { accepted, rejected } = ingestCanonicalRecords(
|
|
39
|
-
[
|
|
40
|
-
{ epc: 'urn:epc:id:sgtin:9521321.012345.1', action: 'ADD', bizStep: 'urn:epcglobal:cbv:bizstep:receiving', readPoint: 'dock-1' },
|
|
41
|
-
{ meterId: 'm-1', kW: 120 },
|
|
42
|
-
{ equipmentId: 'pv-1', generatedKW: 40 },
|
|
43
|
-
{ moverId: 'fk-1', kind: 'forklift', status: 'busy' }, // vocabulary-guard: allow 저널 와이어 필드
|
|
44
|
-
{ orderId: 'or-1', kind: 'outbound', status: 'picking', requested: 10, fulfilled: 3 }
|
|
45
|
-
] as any,
|
|
46
|
-
'domain-1',
|
|
47
|
-
AT
|
|
48
|
-
)
|
|
49
|
-
assert.deepEqual(rejected, [], '어느 어휘도 남의 길로 떨어지지 않는다')
|
|
50
|
-
assert.deepEqual(accepted.map(e => e.eventType).sort(), [
|
|
51
|
-
'energy.equipment', 'energy.measured', 'epcis.ObjectEvent', 'equipment.status', 'order.status'
|
|
52
|
-
].sort())
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test('거부는 이유와 함께 남는다 — 유효한 것은 함께 통과한다', () => {
|
|
56
|
-
const { accepted, rejected } = ingestCanonicalRecords(
|
|
57
|
-
[
|
|
58
|
-
{ taskId: 'tk-1', kind: 'pick', status: 'completed' },
|
|
59
|
-
{ taskId: 'tk-2', kind: 'pick', status: 'FINISHED' } // 커널이 다룰 수 없는 낱말
|
|
60
|
-
] as any,
|
|
61
|
-
'domain-1',
|
|
62
|
-
AT
|
|
63
|
-
)
|
|
64
|
-
assert.equal(accepted.length, 1)
|
|
65
|
-
assert.equal(rejected.length, 1)
|
|
66
|
-
assert.ok(rejected[0].errors.join(' ').length > 0)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
test('피드 결선이 거부를 알리지 않고 버리지 않는다 — 이유를 사람에게 말한다', () => {
|
|
70
|
-
const src = readFileSync(fileURLToPath(new URL('../server/service/reference/reference-live.ts', import.meta.url)), 'utf-8')
|
|
71
|
-
assert.match(src, /record\(s\) rejected/, '거부 수와 이유를 남긴다')
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
/*
|
|
75
|
-
* ── 담김도 이 문을 지난다 (2026-08-19) ──────────────────────────────────────
|
|
76
|
-
* 실 앱에서 한 바퀴 돌리자 「옮기지 못했다」 로그가 `epcis.AggregationEvent` 를 짚었다 — 관측 리듀서는 그
|
|
77
|
-
* 사실로 자식 물품에 `parent` 를 붙이는데(3D 가 「이 상자가 어느 팔레트에 실렸나」를 묻는 자리) 문에 그
|
|
78
|
-
* 어휘가 없었다.
|
|
79
|
-
*/
|
|
80
|
-
test('담김 레코드가 자기 봉투로 나온다 — 개체 관측과 한 배치에 섞여 와도 갈린다', () => {
|
|
81
|
-
const { accepted, rejected } = ingestCanonicalRecords(
|
|
82
|
-
[
|
|
83
|
-
{ epc: 'urn:epc:id:sgtin:9521321.012345.1', action: 'ADD', bizStep: 'urn:epcglobal:cbv:bizstep:receiving', readPoint: 'dock-1' },
|
|
84
|
-
{ parentID: 'urn:epc:id:sscc:0614141.0000000001', childEPCs: ['urn:epc:id:sgtin:9521321.012345.1'], action: 'ADD', bizStep: 'urn:epcglobal:cbv:bizstep:packing', readPoint: 'packing' }
|
|
85
|
-
] as any,
|
|
86
|
-
'domain-1',
|
|
87
|
-
AT
|
|
88
|
-
)
|
|
89
|
-
assert.deepEqual(rejected, [])
|
|
90
|
-
assert.deepEqual(accepted.map(e => e.eventType), ['epcis.ObjectEvent', 'epcis.AggregationEvent'])
|
|
91
|
-
assert.equal((accepted[1].data as any).parentID, 'urn:epc:id:sscc:0614141.0000000001')
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
test('자리를 구조째 실으면 거부한다 — 예전에는 "[object Object]" 로 굳어 저널에 쌓였다', () => {
|
|
95
|
-
const { accepted, rejected } = ingestCanonicalRecords(
|
|
96
|
-
[{ epc: 'urn:epc:id:sgtin:9521321.012345.1', action: 'ADD', bizStep: 'urn:epcglobal:cbv:bizstep:receiving', readPoint: { id: 'dock-1' } }] as any,
|
|
97
|
-
'domain-1',
|
|
98
|
-
AT
|
|
99
|
-
)
|
|
100
|
-
assert.equal(accepted.length, 0)
|
|
101
|
-
assert.match(rejected[0].errors.join(' '), /readPoint/)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
test('이 문이 어휘가 넷임을 스스로 말한다 — 다음 사람이 세 어휘로 읽지 않게', () => {
|
|
105
|
-
const src = readFileSync(fileURLToPath(new URL('../server/engine/canonical-ingest.ts', import.meta.url)), 'utf-8')
|
|
106
|
-
assert.match(src, /어휘가 넷이다/)
|
|
107
|
-
assert.match(src, /isOperationalRecord/, '판정은 커널의 것을 부른다(여기서 다시 짐작하지 않는다)')
|
|
108
|
-
})
|