@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,104 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* **허락과 일어남 사이를 같은 행에 닫는다** — ADR-0029 §1 결정 C (2026-08-19).
|
|
3
|
-
*
|
|
4
|
-
* ── 무엇이 열려 있었나 ──────────────────────────────────────────────────────
|
|
5
|
-
* 명령이 원본으로 가면 감사는 「허락했다」까지만 증명한다: 어댑터가 오류 없이 실패하면 원장에는 승인만 남는다.
|
|
6
|
-
* 그리고 구동 문(`controlTwinSource`)은 감사를 **아예 남기지 않았다** — 자극을 바꾸고 배속을 올리는 것은
|
|
7
|
-
* 그 트윈의 사실을 바꾸는 행위인데, 나중에 「무엇이 이 공장을 흔들었나」에 답할 수 없었다.
|
|
8
|
-
*
|
|
9
|
-
* ── 세 값을 구별한다 ────────────────────────────────────────────────────────
|
|
10
|
-
* · 칸이 **없음** — 원본에 묻지 않았다(커널이 받은 명령).
|
|
11
|
-
* · `unknown` — 물었는데 답이 없다. **성공으로 적지 않는다.**
|
|
12
|
-
* · `applied`·`refused` — 원본이 답했다(둘 다 사실이다).
|
|
13
|
-
*
|
|
14
|
-
* 셋을 뭉개면 둘 중 하나가 된다: 일어난 일을 없던 일로 만들거나, 없던 일을 일어난 일로 만든다.
|
|
15
|
-
*/
|
|
16
|
-
import { test } from 'node:test'
|
|
17
|
-
import assert from 'node:assert/strict'
|
|
18
|
-
import { readFileSync } from 'node:fs'
|
|
19
|
-
import { fileURLToPath } from 'node:url'
|
|
20
|
-
|
|
21
|
-
import { buildCommandAudit, sourceOutcomeOf } from '../server/service/twin-audit/command-audit.ts'
|
|
22
|
-
|
|
23
|
-
const at = new Date('2026-08-19T05:00:00.000Z')
|
|
24
|
-
|
|
25
|
-
test('묻지 않았으면 칸을 만들지 않는다 — 커널이 받은 명령이 그렇다', () => {
|
|
26
|
-
const row = buildCommandAudit({ command: { type: 'order.hold', origin: 'user' }, ack: { accepted: true }, at })
|
|
27
|
-
assert.equal('sourceOutcome' in row, false, '없음은 「모른다」가 아니라 「묻지 않았다」다')
|
|
28
|
-
assert.equal('sourceCode' in row, false)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
test('물었는데 답이 없으면 unknown — 성공으로 적지 않는다', () => {
|
|
32
|
-
const row = buildCommandAudit({
|
|
33
|
-
command: { type: 'source.stimulus', origin: 'user' },
|
|
34
|
-
ack: { accepted: true },
|
|
35
|
-
source: { answered: false },
|
|
36
|
-
at
|
|
37
|
-
})
|
|
38
|
-
assert.equal(row.sourceOutcome, 'unknown')
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
test('답이 있으면 그대로 적는다 — 거절도 사실이다', () => {
|
|
42
|
-
const applied = buildCommandAudit({ command: {}, ack: { accepted: true }, source: { answered: true, ok: true }, at })
|
|
43
|
-
assert.equal(applied.sourceOutcome, 'applied')
|
|
44
|
-
const refused = buildCommandAudit({
|
|
45
|
-
command: {},
|
|
46
|
-
ack: { accepted: true },
|
|
47
|
-
source: { answered: true, ok: false, code: 'not-declared' },
|
|
48
|
-
at
|
|
49
|
-
})
|
|
50
|
-
assert.equal(refused.sourceOutcome, 'refused')
|
|
51
|
-
assert.equal(refused.sourceCode, 'not-declared', '원본이 준 사유를 그대로 적는다')
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
test('사유가 없으면 사유 칸도 없다 — 지어내지 않는다', () => {
|
|
55
|
-
const row = buildCommandAudit({ command: {}, ack: { accepted: true }, source: { answered: true, ok: true }, at })
|
|
56
|
-
assert.equal('sourceCode' in row, false)
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
test('판정 함수가 세 값만 낸다 — ok 가 참/거짓이 아니면 모른다', () => {
|
|
60
|
-
assert.equal(sourceOutcomeOf({ answered: true, ok: true }), 'applied')
|
|
61
|
-
assert.equal(sourceOutcomeOf({ answered: true, ok: false }), 'refused')
|
|
62
|
-
assert.equal(sourceOutcomeOf({ answered: false }), 'unknown')
|
|
63
|
-
assert.equal(sourceOutcomeOf({ answered: true }), 'unknown', '답했다고 하면서 값이 없으면 모르는 것이다')
|
|
64
|
-
assert.equal(sourceOutcomeOf({ answered: true, ok: undefined as any }), 'unknown')
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('신원은 여전히 서버만 채운다 — 원본의 답이 그 규율을 흔들지 않는다', () => {
|
|
68
|
-
const row = buildCommandAudit({
|
|
69
|
-
command: { type: 'source.pause', origin: 'user', actorId: 'forged', actorEmail: 'forged@x' },
|
|
70
|
-
ack: { accepted: true },
|
|
71
|
-
source: { answered: true, ok: true },
|
|
72
|
-
at,
|
|
73
|
-
actor: { id: 'u1', email: 'real@x' }
|
|
74
|
-
})
|
|
75
|
-
assert.equal(row.actorId, 'u1')
|
|
76
|
-
assert.equal(row.actorEmail, 'real@x')
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
/*
|
|
80
|
-
* ── 구동 문이 실제로 남기는지 (소스로 지킨다) ───────────────────────────────
|
|
81
|
-
* 순수 함수만 시험하면 「기록을 만들 수 있다」까지만 지킨다. 남기지 않으면 그 함수는 아무 일도 하지 않는다.
|
|
82
|
-
*/
|
|
83
|
-
test('구동 문이 게이트 뒤에서 원본의 답까지 남긴다', () => {
|
|
84
|
-
const src = readFileSync(fileURLToPath(new URL('../server/service/twin-control/twin-control-mutation.ts', import.meta.url)), 'utf-8')
|
|
85
|
-
const code = src
|
|
86
|
-
.split('\n')
|
|
87
|
-
.filter(line => !/^\s*(\*|\/\/|\/\*)/.test(line))
|
|
88
|
-
.join('\n')
|
|
89
|
-
/* 게이트는 남는다(결정 C 의 절반). */
|
|
90
|
-
const gates = code.match(/@privilege\(category: "twin", privilege: "mutation"/g) ?? []
|
|
91
|
-
assert.ok(gates.length >= 2, `구동 문에도 게이트가 있어야 한다(발견 ${gates.length})`)
|
|
92
|
-
/* 원본의 답을 같은 행에 닫는다. */
|
|
93
|
-
assert.match(code, /source: \{ answered: typeof result\?\.ok === 'boolean', ok: result\?\.ok, code: result\?\.code \}/)
|
|
94
|
-
assert.match(code, /type: `source\.\$\{action\}`/, '커맨드 채널과 같은 어휘로 적는다')
|
|
95
|
-
/* 기록 실패를 삼키지 않는다. */
|
|
96
|
-
assert.match(code, /source control audit not recorded/)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
test('엔티티가 그 두 칸을 든다 — 비어 있음이 뜻을 갖는다', () => {
|
|
100
|
-
const src = readFileSync(fileURLToPath(new URL('../server/service/twin-audit/twin-audit-event.ts', import.meta.url)), 'utf-8')
|
|
101
|
-
assert.match(src, /sourceOutcome\?: string/)
|
|
102
|
-
assert.match(src, /sourceCode\?: string/)
|
|
103
|
-
assert.match(src, /the source was not asked/, '비어 있음의 뜻을 필드 설명이 말한다')
|
|
104
|
-
})
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* 공간 ↔ 트윈 ↔ 가시화 정합성 — 어긋난 모양마다 하나씩 세운다.
|
|
3
|
-
*
|
|
4
|
-
* 검사가 **무는지** 확인하는 것이 이 파일의 일이다: 정합한 입력에서는 아무것도 내지 않고, 어긋난
|
|
5
|
-
* 입력에서는 그 자리를 코드와 id 로 지목해야 한다. 지목하지 못하면 사람이 어디를 볼지 알 수 없다.
|
|
6
|
-
*/
|
|
7
|
-
import { test } from 'node:test'
|
|
8
|
-
import assert from 'node:assert/strict'
|
|
9
|
-
|
|
10
|
-
import { checkSpaceIntegrity, sortFindings, type SpaceIntegrityInput } from '../server/service/twin-space/space-integrity.ts'
|
|
11
|
-
|
|
12
|
-
/** 정합한 한 현장 — 트윈 하나(창고), 지도 표현 하나, 구역 하나, 폴리곤이 그 구역과 로케이션을 가리킨다. */
|
|
13
|
-
const SOUND: SpaceIntegrityInput = {
|
|
14
|
-
spaces: [{ spaceId: 'rosarito-site', primaryRepresentationId: 'rep-map' }],
|
|
15
|
-
instances: [
|
|
16
|
-
{
|
|
17
|
-
instanceId: 'wms-a',
|
|
18
|
-
spaceId: 'rosarito-site',
|
|
19
|
-
modelSpaceId: 'rosarito-site',
|
|
20
|
-
locationIds: ['rack-1', 'dock-1'],
|
|
21
|
-
equipmentIds: ['fork-1'],
|
|
22
|
-
areaRefs: ['bldg-1']
|
|
23
|
-
}
|
|
24
|
-
],
|
|
25
|
-
representations: [
|
|
26
|
-
{
|
|
27
|
-
id: 'rep-map',
|
|
28
|
-
spaceId: 'rosarito-site',
|
|
29
|
-
type: 'map',
|
|
30
|
-
polygons: [
|
|
31
|
-
{ id: 'p1', groupId: 'bldg-1' },
|
|
32
|
-
{ id: 'p2', targetKind: 'location', targetId: 'rack-1' },
|
|
33
|
-
{ id: 'p3', targetKind: 'equipment', targetId: 'fork-1' }
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
],
|
|
37
|
-
areasBySpace: { 'rosarito-site': ['bldg-1'] },
|
|
38
|
-
boardIds: []
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
test('정합하면 아무것도 내지 않는다 — 멀쩡한 현장을 시끄럽게 만들지 않는다', () => {
|
|
42
|
-
assert.deepEqual(checkSpaceIntegrity(SOUND), [])
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
test('없는 현장을 가리키는 트윈을 잡는다 — 무대가 사라진 트윈', () => {
|
|
46
|
-
const f = checkSpaceIntegrity({
|
|
47
|
-
...SOUND,
|
|
48
|
-
instances: [{ ...SOUND.instances[0], spaceId: 'gone-site', modelSpaceId: 'gone-site' }]
|
|
49
|
-
})
|
|
50
|
-
const hit = f.find(x => x.code === 'twin-space-missing')
|
|
51
|
-
assert.ok(hit)
|
|
52
|
-
assert.equal(hit.severity, 'broken')
|
|
53
|
-
assert.equal(hit.instanceId, 'wms-a')
|
|
54
|
-
assert.equal(hit.spaceId, 'gone-site')
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
test('레지스트리와 model 의 현장이 다르면 잡는다 — 어느 쪽이 사실인지 알 수 없다', () => {
|
|
58
|
-
const f = checkSpaceIntegrity({
|
|
59
|
-
...SOUND,
|
|
60
|
-
instances: [{ ...SOUND.instances[0], modelSpaceId: 'other-site' }]
|
|
61
|
-
})
|
|
62
|
-
const hit = f.find(x => x.code === 'twin-space-mismatch')
|
|
63
|
-
assert.ok(hit)
|
|
64
|
-
assert.equal(hit.severity, 'broken')
|
|
65
|
-
assert.equal(hit.params?.registry, 'rosarito-site')
|
|
66
|
-
assert.equal(hit.params?.model, 'other-site')
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
test('현장 없는 트윈은 경고로 낸다 — 뗀 결과일 수 있어 고장은 아니다', () => {
|
|
70
|
-
const f = checkSpaceIntegrity({
|
|
71
|
-
...SOUND,
|
|
72
|
-
instances: [{ ...SOUND.instances[0], spaceId: undefined, modelSpaceId: undefined }]
|
|
73
|
-
})
|
|
74
|
-
const hit = f.find(x => x.code === 'twin-without-space')
|
|
75
|
-
assert.ok(hit)
|
|
76
|
-
assert.equal(hit.severity, 'warn')
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
test('로케이션이 이 현장에 없는 구역에 소속되어 있으면 잡는다', () => {
|
|
80
|
-
const f = checkSpaceIntegrity({
|
|
81
|
-
...SOUND,
|
|
82
|
-
instances: [{ ...SOUND.instances[0], areaRefs: ['bldg-1', 'floor-9', 'floor-9'] }]
|
|
83
|
-
})
|
|
84
|
-
const hit = f.find(x => x.code === 'location-area-missing')
|
|
85
|
-
assert.ok(hit)
|
|
86
|
-
assert.equal(hit.params?.count, 1, '중복은 한 번만 센다')
|
|
87
|
-
assert.equal(hit.params?.areas, 'floor-9')
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
test('폴리곤이 없는 구역을 가리키면 잡는다 — 그 도형은 아무것도 보여 주지 않는다', () => {
|
|
91
|
-
const f = checkSpaceIntegrity({
|
|
92
|
-
...SOUND,
|
|
93
|
-
representations: [{ ...SOUND.representations[0], polygons: [{ id: 'p1', groupId: 'ghost-area' }] }]
|
|
94
|
-
})
|
|
95
|
-
const hit = f.find(x => x.code === 'polygon-area-missing')
|
|
96
|
-
assert.ok(hit)
|
|
97
|
-
assert.equal(hit.severity, 'broken')
|
|
98
|
-
assert.equal(hit.representationId, 'rep-map')
|
|
99
|
-
assert.equal(hit.params?.areaId, 'ghost-area')
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
test('폴리곤이 이 현장의 어느 트윈에도 없는 로케이션을 가리키면 잡는다 — 트윈을 옮긴 뒤 남는 모양', () => {
|
|
103
|
-
const f = checkSpaceIntegrity({
|
|
104
|
-
...SOUND,
|
|
105
|
-
instances: [{ ...SOUND.instances[0], spaceId: 'other-site', modelSpaceId: 'other-site' }],
|
|
106
|
-
spaces: [...SOUND.spaces, { spaceId: 'other-site' }]
|
|
107
|
-
})
|
|
108
|
-
const hits = f.filter(x => x.code === 'polygon-target-missing')
|
|
109
|
-
assert.equal(hits.length, 2, '로케이션과 설비 둘 다 끊긴다')
|
|
110
|
-
assert.equal(hits[0].severity, 'broken')
|
|
111
|
-
assert.equal(hits.find(h => h.params?.kind === 'equipment')?.params?.targetId, 'fork-1')
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
test('설비 바인딩을 로케이션 목록으로 판정하지 않는다 — 종류를 섞으면 거짓 경보가 난다', () => {
|
|
115
|
-
const f = checkSpaceIntegrity({
|
|
116
|
-
...SOUND,
|
|
117
|
-
representations: [
|
|
118
|
-
{ ...SOUND.representations[0], polygons: [{ id: 'p3', targetKind: 'equipment', targetId: 'rack-1' }] }
|
|
119
|
-
]
|
|
120
|
-
})
|
|
121
|
-
assert.ok(f.find(x => x.code === 'polygon-target-missing'), '로케이션 id 를 설비로 가리키면 끊긴 것이다')
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
test('대표 표현이 이 현장의 것이 아니면 잡는다', () => {
|
|
125
|
-
const f = checkSpaceIntegrity({
|
|
126
|
-
...SOUND,
|
|
127
|
-
spaces: [{ spaceId: 'rosarito-site', primaryRepresentationId: 'rep-elsewhere' }]
|
|
128
|
-
})
|
|
129
|
-
const hit = f.find(x => x.code === 'primary-representation-missing')
|
|
130
|
-
assert.ok(hit)
|
|
131
|
-
assert.equal(hit.severity, 'broken')
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
test('보드 표현이 보드를 가리키지 않으면 잡는다', () => {
|
|
135
|
-
const f = checkSpaceIntegrity({
|
|
136
|
-
...SOUND,
|
|
137
|
-
representations: [{ id: 'rep-board', spaceId: 'rosarito-site', type: 'board', boardId: null, polygons: [] }],
|
|
138
|
-
spaces: [{ spaceId: 'rosarito-site', primaryRepresentationId: 'rep-board' }]
|
|
139
|
-
})
|
|
140
|
-
const hit = f.find(x => x.code === 'board-representation-unbound')
|
|
141
|
-
assert.ok(hit)
|
|
142
|
-
assert.equal(hit.params?.boardId, '—')
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
test('없는 보드를 가리키는 보드 표현도 잡는다', () => {
|
|
146
|
-
const f = checkSpaceIntegrity({
|
|
147
|
-
...SOUND,
|
|
148
|
-
representations: [{ id: 'rep-board', spaceId: 'rosarito-site', type: 'board', boardId: 'gone', polygons: [] }],
|
|
149
|
-
spaces: [{ spaceId: 'rosarito-site', primaryRepresentationId: 'rep-board' }],
|
|
150
|
-
boardIds: ['other-board']
|
|
151
|
-
})
|
|
152
|
-
assert.ok(f.find(x => x.code === 'board-representation-unbound'))
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
test('트윈이 사는데 표현이 없으면 경고한다 — 볼 화면이 없다', () => {
|
|
156
|
-
const f = checkSpaceIntegrity({ ...SOUND, representations: [], spaces: [{ spaceId: 'rosarito-site' }] })
|
|
157
|
-
const hit = f.find(x => x.code === 'space-without-representation')
|
|
158
|
-
assert.ok(hit)
|
|
159
|
-
assert.equal(hit.params?.twins, 1)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
test('트윈이 없는 빈 현장은 정상이다 — 만들어 두고 아직 안 쓴 현장', () => {
|
|
163
|
-
const f = checkSpaceIntegrity({
|
|
164
|
-
spaces: [{ spaceId: 'empty-site' }],
|
|
165
|
-
instances: [],
|
|
166
|
-
representations: [],
|
|
167
|
-
areasBySpace: {},
|
|
168
|
-
boardIds: []
|
|
169
|
-
})
|
|
170
|
-
assert.deepEqual(f, [])
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
test('벤치 사본은 검사 대상이 아니다 — 잠깐 살고 지워지는 사본', () => {
|
|
174
|
-
const f = checkSpaceIntegrity({
|
|
175
|
-
...SOUND,
|
|
176
|
-
instances: [
|
|
177
|
-
...SOUND.instances,
|
|
178
|
-
{ instanceId: 'bench-1', spaceId: 'nowhere-site', modelSpaceId: 'else', purpose: 'bench' }
|
|
179
|
-
]
|
|
180
|
-
})
|
|
181
|
-
assert.deepEqual(f, [], '사본의 어긋남은 세지 않는다')
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
test('심각한 것이 먼저 온다 — 사람이 무엇부터 볼지 정하지 않아도 되게', () => {
|
|
185
|
-
const f = sortFindings([
|
|
186
|
-
{ code: 'twin-without-space', severity: 'warn', message: 'w' },
|
|
187
|
-
{ code: 'twin-space-missing', severity: 'broken', message: 'b' }
|
|
188
|
-
])
|
|
189
|
-
assert.equal(f[0].severity, 'broken')
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
/*
|
|
193
|
-
* ── 어휘가 맞지 않는 트윈 (2026-08-14, EMS 를 붙이며) ────────────────────────
|
|
194
|
-
*
|
|
195
|
-
* 커널은 모르는 `eventType` 을 버리고 종류별로 센다(`state.unhandled`). 그 수가 0이 아니면 저널은
|
|
196
|
-
* 들어오는데 상태가 채워지지 않는 것이고, 화면에는 「정상인데 빈」 트윈으로 보인다.
|
|
197
|
-
*
|
|
198
|
-
* 이 검사가 지키는 것은 **모른다와 없다의 구별**이다: 정지한 트윈은 확인한 바가 없으므로 세지 않는다.
|
|
199
|
-
*/
|
|
200
|
-
test('담을 줄 모르는 어휘가 들어오는 트윈을 잡는다 — 리비전만 오르는 빈 트윈', () => {
|
|
201
|
-
const f = checkSpaceIntegrity({
|
|
202
|
-
...SOUND,
|
|
203
|
-
instances: [{ ...SOUND.instances[0], unhandled: [{ eventType: 'energy.measured', count: 96 }, { eventType: 'energy.peak', count: 4 }] }]
|
|
204
|
-
})
|
|
205
|
-
const hit = f.find(x => x.code === 'twin-unhandled-vocabulary')!
|
|
206
|
-
assert.ok(hit, '이것을 놓치면 사용자는 커넥터가 잘못 붙은 것을 알 수 없다')
|
|
207
|
-
assert.equal(hit.severity, 'warn')
|
|
208
|
-
assert.equal(hit.instanceId, 'wms-a', '어느 트윈인지 지목해야 한다')
|
|
209
|
-
assert.equal(hit.params?.events, 100, '건수를 합쳐 낸다')
|
|
210
|
-
assert.equal(hit.params?.kinds, 2)
|
|
211
|
-
assert.match(String(hit.params?.types), /energy\.measured/, '많은 것부터 이름을 낸다')
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
test('정지한 트윈은 세지 않는다 — 확인하지 않은 것을 정합으로도 결함으로도 세지 않는다', () => {
|
|
215
|
-
/* `unhandled` 가 undefined 인 것은 「없다」가 아니라 「모른다」다(런타임이 없으면 알 수 없다). */
|
|
216
|
-
const f = checkSpaceIntegrity(SOUND)
|
|
217
|
-
assert.equal(f.find(x => x.code === 'twin-unhandled-vocabulary'), undefined)
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
test('빈 배열은 결함이 아니다 — 받은 것이 없으면 들어온 것이 없다', () => {
|
|
221
|
-
const f = checkSpaceIntegrity({ ...SOUND, instances: [{ ...SOUND.instances[0], unhandled: [] }] })
|
|
222
|
-
assert.equal(f.find(x => x.code === 'twin-unhandled-vocabulary'), undefined)
|
|
223
|
-
})
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* ★ 표현을 묶고 가른다 — 목록에 나올 것과 다른 표현에서 열리는 것.
|
|
3
|
-
*
|
|
4
|
-
* ── 왜 (2026-08-27 · 사용자 지시, UX 레인 요청) ─────────────────────────────
|
|
5
|
-
* 「각 표현이 많아지게 되면 관리가 어려우니, 그루핑과 정렬 기능도 필요하다.」
|
|
6
|
-
* 「표현 인덱스에 포함될 표현과 팝업 같은 파생 표현이 구분될 수 있어야 한다.」
|
|
7
|
-
*
|
|
8
|
-
* 칸 둘을 더한다.
|
|
9
|
-
*
|
|
10
|
-
* group 자유 문자열. 묶는 축이 현장마다 다르다(건물별·용도별·층별)
|
|
11
|
-
* role index(기본) · derived. 닫힌 목록이다
|
|
12
|
-
*/
|
|
13
|
-
import { test } from 'node:test'
|
|
14
|
-
import assert from 'node:assert/strict'
|
|
15
|
-
import { readFileSync } from 'node:fs'
|
|
16
|
-
import { join } from 'node:path'
|
|
17
|
-
import { REPRESENTATION_ROLES } from '../server/service/twin-space/representation-role.js'
|
|
18
|
-
|
|
19
|
-
const dir = (...p: string[]) => join(import.meta.dirname, '..', 'server', 'service', 'twin-space', ...p)
|
|
20
|
-
const entity = readFileSync(dir('twin-space-representation.ts'), 'utf8')
|
|
21
|
-
const resolver = readFileSync(dir('twin-space-resolver.ts'), 'utf8')
|
|
22
|
-
|
|
23
|
-
test('★ 묶는 이름은 자유 문자열이다 — 묶는 축이 현장마다 다르다', () => {
|
|
24
|
-
assert.match(entity, /group\?: string/, 'group 칸이 있어야 한다')
|
|
25
|
-
/* 고정 목록으로 두면 현장마다 맞지 않는다 — 값을 검사하지 않는다. */
|
|
26
|
-
assert.doesNotMatch(resolver, /GROUPS as readonly|REPRESENTATION_GROUPS/, '묶는 이름을 목록으로 닫지 않는다')
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test('★ 그룹 자체의 순서는 칸으로 두지 않는다 — 그 그룹의 최소 seq 가 그 순서다', () => {
|
|
30
|
-
/* 칸을 두면 그룹 이름을 바꿀 때 두 곳을 맞춰야 하고, 어긋나면 목록 순서가 오류 없이 달라진다. */
|
|
31
|
-
assert.doesNotMatch(entity, /groupSeq|groupOrder/, '그룹 순서 칸을 만들지 않는다')
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test('★ role 은 닫힌 목록이고, 모르는 값은 저장하지 않는다', () => {
|
|
35
|
-
assert.deepEqual([...REPRESENTATION_ROLES], ['index', 'derived'])
|
|
36
|
-
/*
|
|
37
|
-
* 모르는 값을 그냥 저장하면 화면이 그것을 어느 쪽으로도 그리지 못하고, 그 표현이 목록에서 알리지 않고
|
|
38
|
-
* 사라진다. 저장하는 자리에서 거절한다.
|
|
39
|
-
*/
|
|
40
|
-
assert.match(resolver, /REPRESENTATION_ROLES as readonly string\[\]\)\.includes\(role\)/, '닫힌 목록으로 검사한다')
|
|
41
|
-
assert.match(resolver, /unknown representation role/, '거절 사유를 말한다')
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
test('★ 비어 있으면 index 다 — 흔한 쪽을 기본으로 둔다', () => {
|
|
45
|
-
assert.match(entity, /role\?: string/, 'role 은 선택 칸이다')
|
|
46
|
-
assert.match(entity, /default when absent/, '비어 있을 때의 뜻이 설명에 있어야 한다')
|
|
47
|
-
/* 공백만 있는 값은 「없음」과 같다 — 그것을 값으로 저장하면 검사를 지나며 뜻이 없는 값이 남는다. */
|
|
48
|
-
assert.match(resolver, /String\(rep\.role\)\.trim\(\) === ''/, '공백만 있는 값은 비운다')
|
|
49
|
-
assert.match(resolver, /String\(rep\.group\)\.trim\(\) === ''/, '묶는 이름도 같다')
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test('★ isPrimary 에 얹지 않는다 — 다른 질문에 답하는 칸이다', () => {
|
|
53
|
-
/*
|
|
54
|
-
* `isPrimary` 는 「현장 현황에 나올 하나」를 정한다. `role` 은 「목록에 나오나」를 정한다. 한 칸이
|
|
55
|
-
* 두 질문에 답하면 한쪽을 고칠 때 다른 쪽이 오류 없이 바뀐다.
|
|
56
|
-
*/
|
|
57
|
-
assert.match(entity, /isPrimary\?: boolean/, 'isPrimary 는 그대로 있어야 한다')
|
|
58
|
-
assert.match(entity, /Kept separate from isPrimary/, '왜 따로 두는지 설명에 있어야 한다')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
test('★ 조회가 두 값을 실어 보낸다 — 화면이 묶을 수 있어야 한다', () => {
|
|
62
|
-
assert.match(resolver, /group: rep\.group, role: rep\.role/, '표현 목록에 두 값을 싣는다')
|
|
63
|
-
assert.match(resolver, /order: \{ group: 'ASC', seq: 'ASC' \}/, '묶은 이름 다음에 순서로 정렬한다')
|
|
64
|
-
/* 빈 값이 앞에 오는지 뒤에 오는지는 드라이버마다 다르다 — 그 순서에 기대지 않는다. */
|
|
65
|
-
assert.match(resolver, /드라이버마다\s*\n?\s*\*?\s*다르므로/, '그 순서에 기대지 않는다는 것을 적어 둔다')
|
|
66
|
-
})
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* ★ 현장으로 물으면 멈춘 트윈의 기록도 나온다 — 저널은 기록이고, 지금 도는지는 다른 축이다.
|
|
3
|
-
*
|
|
4
|
-
* ── 무엇이 났나 (2026-08-28 실측) ───────────────────────────────────────────
|
|
5
|
-
* 대상 해소에 `running` 조건이 있었다. 그래서 현장으로 물으면 멈춘 트윈이 대상에서 빠지고, 화면은
|
|
6
|
-
* 「기록이 없습니다」라고 말했다 — 저널에는 있는데.
|
|
7
|
-
*
|
|
8
|
-
* twinEventList(instanceId: "ems-plant-1") 1,792건
|
|
9
|
-
* twinEventList(spaceId: "ems-plant-1-site") 0건 ← 같은 트윈 · 같은 도메인
|
|
10
|
-
*
|
|
11
|
-
* 규모로 보면 예외가 아니라 기본값이었다: 등록된 트윈 30개 중 도는 것 2개, 멈춘 것 28개.
|
|
12
|
-
*
|
|
13
|
-
* ── 왜 지웠나 ──────────────────────────────────────────────────────────────
|
|
14
|
-
* 옛 주석이 대는 이유(「벤치 사본은 사용자가 보는 현장이 아니다」)는 벤치 제외만 설명한다. `running` 에는
|
|
15
|
-
* 근거가 적혀 있지 않았다. 그리고 바로 다음 줄이 반대 원칙을 적어 두었다 — 「정지·비등록이어도 저널은
|
|
16
|
-
* 남아 있을 수 있다」. 그 원칙이 현장 경로에만 적용되지 않고 있었다.
|
|
17
|
-
*/
|
|
18
|
-
import { test } from 'node:test'
|
|
19
|
-
import assert from 'node:assert/strict'
|
|
20
|
-
import { readFileSync } from 'node:fs'
|
|
21
|
-
import { join } from 'node:path'
|
|
22
|
-
|
|
23
|
-
const KPI = join(import.meta.dirname, '..', 'server', 'engine', 'kpi-query.ts')
|
|
24
|
-
const src = readFileSync(KPI, 'utf8')
|
|
25
|
-
|
|
26
|
-
/** 대상을 고르는 그 한 줄만 떼어 본다. */
|
|
27
|
-
const targetLine = (() => {
|
|
28
|
-
const from = src.indexOf('async function resolveTargets')
|
|
29
|
-
const body = src.slice(from, from + 1200)
|
|
30
|
-
const m = /: list\.filter\(\(x: any\) => [^\n]+\)/.exec(body)
|
|
31
|
-
return m?.[0] ?? ''
|
|
32
|
-
})()
|
|
33
|
-
|
|
34
|
-
test('★ 현장 경로가 「지금 도는가」로 걸러내지 않는다', () => {
|
|
35
|
-
assert.ok(targetLine, '대상을 고르는 줄을 찾아야 한다')
|
|
36
|
-
assert.doesNotMatch(targetLine, /running/, '멈춘 트윈을 현장에서 빼면 화면이 거짓 「없다」를 낸다')
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
test('벤치 사본은 계속 뺀다 — 그 제외에는 근거가 있다', () => {
|
|
40
|
-
/* 부하 시험용 사본은 사용자가 보는 현장이 아니다. 이 제외는 지우지 않는다. */
|
|
41
|
-
assert.match(targetLine, /purpose !== 'bench'/)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
test('현장과 트윈 두 경로가 같은 원칙을 쓴다 — 저널은 기록이다', () => {
|
|
45
|
-
/* 트윈을 지정한 경로는 처음부터 「정지·비등록이어도 저널은 남아 있을 수 있다」였다. */
|
|
46
|
-
assert.match(src, /정지·비등록\)? ?지정된 트윈은 그대로 조회한다|정지·비등록/)
|
|
47
|
-
/* 왜 지웠는지가 코드에 남아 있어야 한다 — 다음 사람이 성능을 이유로 되넣지 않게. */
|
|
48
|
-
assert.match(src, /「지금 도는가」로 걸러내지 않는다/)
|
|
49
|
-
assert.match(src, /1,792건/, '무엇을 재서 알았는지 적혀 있어야 한다')
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test('★ 「지금 도는 것만」이 필요하면 이름 있는 축으로 받는다 — 여기 숨기지 않는다', () => {
|
|
53
|
-
/* 한 칸에 두 물음을 담으면 어느 화면이 무엇을 보는지 아무도 모른다. */
|
|
54
|
-
assert.match(src, /\*\*이름 있는 축\*\*으로 받는다/)
|
|
55
|
-
})
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* 시뮬 명세 자격 판정 — **"이 예측으로 무엇을 말할 수 있나" 를 숫자로 가른다.**
|
|
3
|
-
*
|
|
4
|
-
* 배경: 공정 소요가 커널 상수였을 때와 현장 명세로 굴렸을 때가 응답에서 똑같이 "p50 168" 로 보였다.
|
|
5
|
-
* 그 둘을 구별하지 못하면 상대 비교용 숫자가 절대 예측처럼 읽힌다.
|
|
6
|
-
*/
|
|
7
|
-
import { test } from 'node:test'
|
|
8
|
-
import assert from 'node:assert/strict'
|
|
9
|
-
|
|
10
|
-
import { classifySpecCoverage, readSpecCoverage } from '../server/engine/spec-coverage.ts'
|
|
11
|
-
|
|
12
|
-
test('전부 기본값이면 상대 비교만 — 절대 시각을 주장할 근거가 없다', () => {
|
|
13
|
-
const r = classifySpecCoverage({
|
|
14
|
-
operations: [
|
|
15
|
-
{ kind: 'putaway', duration: 'default' },
|
|
16
|
-
{ kind: 'pick', duration: 'default' }
|
|
17
|
-
]
|
|
18
|
-
})
|
|
19
|
-
assert.equal(r!.qualification, 'relative')
|
|
20
|
-
assert.equal(r!.declaredDurations, 0)
|
|
21
|
-
assert.equal(r!.defaultDurations, 2)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('전부 선언되면 절대 예측 시도 가능 — 단 정확도는 별개(이름이 capable 이다)', () => {
|
|
25
|
-
const r = classifySpecCoverage({
|
|
26
|
-
operations: [
|
|
27
|
-
{ kind: 'cut', duration: 'declared', variability: 'triangular', parameters: ['yield'] },
|
|
28
|
-
{ kind: 'weld', duration: 'declared', variability: 'uniform' }
|
|
29
|
-
]
|
|
30
|
-
})
|
|
31
|
-
assert.equal(r!.qualification, 'absolute-capable')
|
|
32
|
-
assert.equal(r!.varyingDurations, 2)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('섞이면 partial — 한쪽만 계산하지된 사실을 감추지 않는다', () => {
|
|
36
|
-
const r = classifySpecCoverage({
|
|
37
|
-
operations: [
|
|
38
|
-
{ kind: 'cut', duration: 'declared' },
|
|
39
|
-
{ kind: 'paint', duration: 'default' }
|
|
40
|
-
]
|
|
41
|
-
})
|
|
42
|
-
assert.equal(r!.qualification, 'partial')
|
|
43
|
-
assert.equal(r!.declaredDurations, 1)
|
|
44
|
-
assert.equal(r!.defaultDurations, 1)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test('변동 없는 선언은 varying 0 — 고정값이면 대기·병목이 과소평가된다는 신호', () => {
|
|
48
|
-
const r = classifySpecCoverage({ operations: [{ kind: 'cut', duration: 'declared' }] })
|
|
49
|
-
assert.equal(r!.varyingDurations, 0)
|
|
50
|
-
const c = classifySpecCoverage({ operations: [{ kind: 'cut', duration: 'declared', variability: 'constant' }] })
|
|
51
|
-
assert.equal(c!.varyingDurations, 0, 'constant 는 변동이 아니다')
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
test('관측된 작업이 없으면 판정하지 않는다 — 모름을 relative 로 단정하지 않는다', () => {
|
|
55
|
-
assert.equal(classifySpecCoverage({ operations: [] }), undefined)
|
|
56
|
-
assert.equal(classifySpecCoverage({} as any), undefined)
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
test('커널이 보고 API 를 갖지 않으면 undefined — "전부 기본값" 이라 단정하지 않는다', () => {
|
|
60
|
-
assert.equal(readSpecCoverage({}), undefined)
|
|
61
|
-
assert.equal(readSpecCoverage(undefined), undefined)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
test('커널 보고가 오류를 내어도 예측을 깨지 않는다', () => {
|
|
65
|
-
assert.equal(readSpecCoverage({ specCoverage: () => { throw new Error('boom') } }), undefined)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
test('커널 보고를 그대로 분류한다 — 카운트를 다시 세지 않고 준 값을 존중', () => {
|
|
69
|
-
const r = readSpecCoverage({
|
|
70
|
-
specCoverage: () => ({
|
|
71
|
-
operations: [{ kind: 'cut', duration: 'declared', parameters: ['yield'] }],
|
|
72
|
-
declaredDurations: 1,
|
|
73
|
-
defaultDurations: 0
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
assert.equal(r!.qualification, 'absolute-capable')
|
|
77
|
-
assert.deepEqual(r!.operations[0].parameters, ['yield'])
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
/* ── 실측이 들어오면 자격이 한 칸 올라간다 ─────────────────────────────── */
|
|
81
|
-
|
|
82
|
-
test('전부 이력에서 온 소요면 calibrated — 선언은 사람이 적은 값, 이것은 일어난 값', () => {
|
|
83
|
-
const r = classifySpecCoverage({
|
|
84
|
-
operations: [
|
|
85
|
-
{ kind: 'putaway', duration: 'measured' },
|
|
86
|
-
{ kind: 'pick', duration: 'measured' }
|
|
87
|
-
]
|
|
88
|
-
})
|
|
89
|
-
assert.equal(r!.qualification, 'calibrated')
|
|
90
|
-
assert.equal(r!.measuredDurations, 2)
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
test('실측과 선언이 섞이면 absolute-capable — 상수가 없으면 시각을 말할 수 있다', () => {
|
|
94
|
-
const r = classifySpecCoverage({
|
|
95
|
-
operations: [
|
|
96
|
-
{ kind: 'putaway', duration: 'measured' },
|
|
97
|
-
{ kind: 'cut', duration: 'declared' }
|
|
98
|
-
]
|
|
99
|
-
})
|
|
100
|
-
assert.equal(r!.qualification, 'absolute-capable')
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
test('상수가 하나라도 섞이면 partial — 실측이 있어도 감추지 않는다', () => {
|
|
104
|
-
const r = classifySpecCoverage({
|
|
105
|
-
operations: [
|
|
106
|
-
{ kind: 'putaway', duration: 'measured' },
|
|
107
|
-
{ kind: 'pick', duration: 'default' }
|
|
108
|
-
]
|
|
109
|
-
})
|
|
110
|
-
assert.equal(r!.qualification, 'partial')
|
|
111
|
-
assert.equal(r!.measuredDurations, 1)
|
|
112
|
-
assert.equal(r!.defaultDurations, 1)
|
|
113
|
-
})
|
package/test/stage-path.test.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* ★ 단계 판정 — **체크리스트가 아니라 증거로 센다.**
|
|
3
|
-
*
|
|
4
|
-
* 이 테스트가 지키는 것:
|
|
5
|
-
* ① **「모른다」는 달성이 아니다.** 계측되지 않은 신호(`null`)를 0 으로 대체하면 「반출 0건」과
|
|
6
|
-
* 「반출을 세지 않았다」가 같아진다. 배선하지 않은 계측으로 단계를 주장할 길을 남기지 않는다.
|
|
7
|
-
* ② **반출을 세었는데 없으면 라이브가 아니다.** 되풀어 읽는 스냅샷은 원리적으로 반출을 못 낸다 —
|
|
8
|
-
* 이 판별식이 폴링을 「실시간」이라 부르는 것을 막는다.
|
|
9
|
-
* ③ **선언이 비면 예측이 아니다.** 커널 기본값 위에 선 숫자도 화면에서는 예측처럼 보인다.
|
|
10
|
-
* ④ **앞을 건너뛸 수 없다.** 뒤 단계는 자기 조건을 따지지 않고 `prerequisite` 으로 막는다.
|
|
11
|
-
*/
|
|
12
|
-
import { test } from 'node:test'
|
|
13
|
-
import assert from 'node:assert/strict'
|
|
14
|
-
|
|
15
|
-
import { assessStagePath, forbiddenClaims, type StageEvidence } from '../server/engine/stage-path.ts'
|
|
16
|
-
|
|
17
|
-
/** 전부 달성한 증거 — 각 시험은 여기서 한 축만 무너뜨린다(무엇이 판정을 바꿨는지 분명해진다). */
|
|
18
|
-
const full = (): StageEvidence => ({
|
|
19
|
-
locationCount: 12,
|
|
20
|
-
itemCount: 340,
|
|
21
|
-
masterWarnings: 3,
|
|
22
|
-
liveIngestTotal: 1200,
|
|
23
|
-
removalsObserved: 17,
|
|
24
|
-
forecastRan: true,
|
|
25
|
-
specCoverage: { declared: 6, total: 8 },
|
|
26
|
-
actuateCapability: true,
|
|
27
|
-
correlatedEffectObserved: 2
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('전부 증거가 있으면 폐루프까지 도달하고 금지 표현이 없다', () => {
|
|
31
|
-
const p = assessStagePath(full())
|
|
32
|
-
assert.deepEqual(p.stages.map(s => s.achieved), [true, true, true, true])
|
|
33
|
-
assert.equal(p.reached, 'closed-loop')
|
|
34
|
-
assert.equal(p.next, null)
|
|
35
|
-
assert.deepEqual(forbiddenClaims(p), [])
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
test('못 옮긴 값을 세지 않았으면 구조도 달성이 아니다 — 0 이라고 우기지 않는다', () => {
|
|
39
|
-
const p = assessStagePath({ ...full(), masterWarnings: null })
|
|
40
|
-
const s1 = p.stages[0]
|
|
41
|
-
assert.equal(s1.achieved, false)
|
|
42
|
-
assert.deepEqual(s1.unmeasured, ['master-warnings'])
|
|
43
|
-
assert.deepEqual(s1.blockedBy, [], '자리와 물품은 있으므로 막힌 것이 아니라 모르는 것이다')
|
|
44
|
-
assert.equal(p.reached, null, '첫 칸을 못 밟았으면 서 있는 칸이 없다')
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
test('못 옮긴 값이 3건이어도 구조는 달성이다 — 요구는 「없다」가 아니라 「말할 수 있다」', () => {
|
|
48
|
-
assert.equal(assessStagePath({ ...full(), masterWarnings: 3 }).stages[0].achieved, true)
|
|
49
|
-
assert.equal(assessStagePath({ ...full(), masterWarnings: 0 }).stages[0].achieved, true)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test('반출을 세었는데 0 이면 라이브가 아니다 — 스냅샷 되풀어 읽기의 징표', () => {
|
|
53
|
-
const p = assessStagePath({ ...full(), removalsObserved: 0 })
|
|
54
|
-
assert.equal(p.stages[1].achieved, false)
|
|
55
|
-
assert.deepEqual(p.stages[1].blockedBy, ['no-removal-observed'])
|
|
56
|
-
assert.equal(p.reached, 'structure')
|
|
57
|
-
assert.ok(forbiddenClaims(p).includes('claim.realtime'), '실시간이라고 말할 수 없다')
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
test('반출이 계측되지 않으면 「없다」가 아니라 「모른다」로 막힌다', () => {
|
|
61
|
-
const p = assessStagePath({ ...full(), removalsObserved: null })
|
|
62
|
-
assert.deepEqual(p.stages[1].unmeasured, ['removals'])
|
|
63
|
-
assert.deepEqual(p.stages[1].blockedBy, [], '인제스트는 있으므로 막힌 것이 아니다')
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
test('선언이 비면 예측이 아니다 — 기본값 위에 선 숫자도 숫자로 보인다', () => {
|
|
67
|
-
const p = assessStagePath({ ...full(), specCoverage: { declared: 0, total: 8 } })
|
|
68
|
-
assert.equal(p.stages[2].achieved, false)
|
|
69
|
-
assert.deepEqual(p.stages[2].blockedBy, ['declarations-empty'])
|
|
70
|
-
assert.equal(p.reached, 'live')
|
|
71
|
-
assert.ok(forbiddenClaims(p).includes('claim.prediction'))
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
test('접수만으로는 폐루프가 아니다 — 효과가 관측으로 돌아와야 닫힌다', () => {
|
|
75
|
-
const p = assessStagePath({ ...full(), correlatedEffectObserved: 0 })
|
|
76
|
-
assert.deepEqual(p.stages[3].blockedBy, ['effect-not-observed'])
|
|
77
|
-
assert.equal(p.reached, 'forecast')
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
test('앞이 막히면 뒤는 자기 조건을 따지지 않는다 — 순서를 건너뛸 수 없다', () => {
|
|
81
|
-
const p = assessStagePath({ ...full(), locationCount: 0, itemCount: 0 })
|
|
82
|
-
assert.deepEqual(p.stages[0].blockedBy, ['no-locations', 'no-items'])
|
|
83
|
-
for (const later of p.stages.slice(1)) assert.deepEqual(later.blockedBy, ['prerequisite'])
|
|
84
|
-
assert.deepEqual(p.next, { stage: 'structure', blockedBy: ['no-locations', 'no-items'], unmeasured: [] })
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
test('다음 걸음은 목록이 아니라 하나다', () => {
|
|
88
|
-
const p = assessStagePath({ ...full(), removalsObserved: 0, specCoverage: null, actuateCapability: false })
|
|
89
|
-
assert.equal(p.next?.stage, 'live', '뒤쪽 결손을 함께 들이밀지 않는다')
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
test('비직렬 수량 물품만 있어도 구조는 달성이다 — 식품·화학은 개수로 오지 않는다', () => {
|
|
93
|
-
/* itemCount 는 「자리에 놓인 물품 수」이고, 비직렬 수량 물품(subLot)도 한 줄로 센다. */
|
|
94
|
-
assert.equal(assessStagePath({ ...full(), itemCount: 1 }).stages[0].achieved, true)
|
|
95
|
-
})
|