@operato/twin-kernel 0.7.63 → 0.7.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contract.d.ts +25 -0
- package/dist/face2-adapter.js +7 -0
- package/dist/operational-ingest.js +12 -2
- package/dist-cjs/index.cjs +6 -1
- package/package.json +1 -1
package/dist/contract.d.ts
CHANGED
|
@@ -5,6 +5,31 @@ export interface CanonicalEnvelope<T = unknown> {
|
|
|
5
5
|
eventTime: ISOTime;
|
|
6
6
|
tenantId: string;
|
|
7
7
|
correlationId?: string;
|
|
8
|
+
/**
|
|
9
|
+
* **사람이 그때 적어 둔 말** — 연결된 시스템에서 온 자유 문장.
|
|
10
|
+
*
|
|
11
|
+
* ── 왜 이 자리가 필요한가 (2026-08-25) ────────────────────────────────────
|
|
12
|
+
* 재고 조정만은 **원인이 트윈의 모델 밖에 있다.** 다른 이동은 원인을 트윈이 스스로 압니다 —
|
|
13
|
+
* 꺼내 간 것은 작업 지시가 시켰고, 적치는 입고가 시켰습니다. 그런데 조정은 **사람이 판단한 것**이고,
|
|
14
|
+
* 그 이유는 그 사람이 적은 문장에만 있습니다(「실재고로 조정(192kg→198kg)」).
|
|
15
|
+
*
|
|
16
|
+
* 그 문장이 없으면 트윈은 「6kg 이 늘었다」까지만 알고 **왜인지 영원히 답하지 못합니다.**
|
|
17
|
+
*
|
|
18
|
+
* ── 왜 봉투에 두고 상태에 두지 않나 ──────────────────────────────────────
|
|
19
|
+
* 그 문장은 **지난 사건에 대한 사실**이고 지금 수량에 대한 사실이 아닙니다. 상태에 두면 조정 열 번에
|
|
20
|
+
* 문장 열 개가 쌓여 시간에 비례해 자랍니다. 지난 기록이 답하는 물음입니다.
|
|
21
|
+
*
|
|
22
|
+
* 그리고 EPCIS 사건 안에 넣지 않습니다 — 표준에 그 칸이 없고, 이름을 지어 넣으면 그 사건이
|
|
23
|
+
* 표준을 벗어납니다. 봉투는 우리 것이므로 여기가 맞고, 지난 기록에는 봉투가 그대로 남습니다.
|
|
24
|
+
*
|
|
25
|
+
* ── 커널은 읽지 않습니다 ─────────────────────────────────────────────────
|
|
26
|
+
* 자유 문장이므로 어떤 판단에도 쓰지 않습니다. 나르기만 합니다. 비어 있으면 이 칸을 만들지
|
|
27
|
+
* 않습니다 — 빈 문장은 「적지 않았다」와 다르게 보입니다.
|
|
28
|
+
*
|
|
29
|
+
* 표준 근거: ISA-95 가 거의 모든 타입에 두는 `Description`(DescriptionType). 사람의 글을 담는
|
|
30
|
+
* 표준 자리이고, EPCIS 핵심에는 없어 확장으로 갑니다.
|
|
31
|
+
*/
|
|
32
|
+
description?: string;
|
|
8
33
|
data: T;
|
|
9
34
|
}
|
|
10
35
|
/**
|
package/dist/face2-adapter.js
CHANGED
|
@@ -225,11 +225,18 @@ export function ingest(records, rules, opts) {
|
|
|
225
225
|
rejected.push({ record, errors });
|
|
226
226
|
continue;
|
|
227
227
|
}
|
|
228
|
+
/*
|
|
229
|
+
* 사람이 적어 둔 말은 **봉투에** 싣는다(§`CanonicalEnvelope.description`) — EPCIS 사건 안에 넣으면
|
|
230
|
+
* 그 사건이 표준을 벗어난다. 지난 기록에는 봉투가 그대로 남으므로 잃지 않는다.
|
|
231
|
+
* 비어 있으면 이 칸을 만들지 않는다 — 빈 문장은 「적지 않았다」와 다르게 보인다.
|
|
232
|
+
*/
|
|
233
|
+
const note = typeof record['description'] === 'string' ? String(record['description']).trim() : '';
|
|
228
234
|
accepted.push({
|
|
229
235
|
eventId: `${opts.tenantId}-ingest-${++seq}`,
|
|
230
236
|
eventType: `epcis.${ev.type}`,
|
|
231
237
|
eventTime: ev.eventTime,
|
|
232
238
|
tenantId: opts.tenantId,
|
|
239
|
+
...(note ? { description: note } : {}),
|
|
233
240
|
data: ev
|
|
234
241
|
});
|
|
235
242
|
}
|
|
@@ -267,8 +267,15 @@ export function ingestOperationalRecords(records, opts) {
|
|
|
267
267
|
const spec = SPECS[kind];
|
|
268
268
|
const r = record;
|
|
269
269
|
const errors = [];
|
|
270
|
-
/*
|
|
271
|
-
|
|
270
|
+
/*
|
|
271
|
+
* 모르는 이름은 거부한다 — 한 글자 틀린 필드가 오류 없이 사라지는 것을 막는다.
|
|
272
|
+
*
|
|
273
|
+
* 둘은 뺀다. **사실의 칸이 아니라 봉투의 칸**이다: `at` 은 그 사실이 일어난 시각이고,
|
|
274
|
+
* `description` 은 사람이 그때 적어 둔 말이다(§`CanonicalEnvelope.description`). 사실 칸으로
|
|
275
|
+
* 검사하면 명세마다 같은 두 줄을 적어야 하고, 한 곳을 빠뜨리면 그 통로만 거부한다.
|
|
276
|
+
*/
|
|
277
|
+
const ENVELOPE_FIELDS = ['at', 'description'];
|
|
278
|
+
const unknown = Object.keys(r).filter(k => !ENVELOPE_FIELDS.includes(k) && spec.fields[k] === undefined);
|
|
272
279
|
if (unknown.length)
|
|
273
280
|
errors.push(`${kind}: 계약에 없는 필드 — ${unknown.join(', ')}`);
|
|
274
281
|
for (const name of spec.required) {
|
|
@@ -357,11 +364,14 @@ export function ingestOperationalRecords(records, opts) {
|
|
|
357
364
|
rejected.push({ record, errors });
|
|
358
365
|
continue;
|
|
359
366
|
}
|
|
367
|
+
/* 사람이 적어 둔 말 — 봉투에 싣는다(§`CanonicalEnvelope.description`). 물류 쪽과 같은 자리다. */
|
|
368
|
+
const note = typeof r.description === 'string' ? String(r.description).trim() : '';
|
|
360
369
|
accepted.push({
|
|
361
370
|
eventId: `${opts.tenantId}-op-${kind}-${++seq}`,
|
|
362
371
|
eventType: spec.eventType,
|
|
363
372
|
eventTime: new Date(atMs).toISOString(),
|
|
364
373
|
tenantId: opts.tenantId,
|
|
374
|
+
...(note ? { description: note } : {}),
|
|
365
375
|
data
|
|
366
376
|
});
|
|
367
377
|
}
|
package/dist-cjs/index.cjs
CHANGED
|
@@ -3377,11 +3377,13 @@ function ingest(records, rules, opts) {
|
|
|
3377
3377
|
rejected.push({ record, errors });
|
|
3378
3378
|
continue;
|
|
3379
3379
|
}
|
|
3380
|
+
const note = typeof record["description"] === "string" ? String(record["description"]).trim() : "";
|
|
3380
3381
|
accepted.push({
|
|
3381
3382
|
eventId: `${opts.tenantId}-ingest-${++seq}`,
|
|
3382
3383
|
eventType: `epcis.${ev.type}`,
|
|
3383
3384
|
eventTime: ev.eventTime,
|
|
3384
3385
|
tenantId: opts.tenantId,
|
|
3386
|
+
...note ? { description: note } : {},
|
|
3385
3387
|
data: ev
|
|
3386
3388
|
});
|
|
3387
3389
|
}
|
|
@@ -9172,7 +9174,8 @@ function ingestOperationalRecords(records, opts) {
|
|
|
9172
9174
|
const spec = SPECS[kind];
|
|
9173
9175
|
const r = record;
|
|
9174
9176
|
const errors = [];
|
|
9175
|
-
const
|
|
9177
|
+
const ENVELOPE_FIELDS = ["at", "description"];
|
|
9178
|
+
const unknown = Object.keys(r).filter((k) => !ENVELOPE_FIELDS.includes(k) && spec.fields[k] === void 0);
|
|
9176
9179
|
if (unknown.length) errors.push(`${kind}: \uACC4\uC57D\uC5D0 \uC5C6\uB294 \uD544\uB4DC \u2014 ${unknown.join(", ")}`);
|
|
9177
9180
|
for (const name of spec.required) {
|
|
9178
9181
|
const v = r[name];
|
|
@@ -9256,11 +9259,13 @@ function ingestOperationalRecords(records, opts) {
|
|
|
9256
9259
|
rejected.push({ record, errors });
|
|
9257
9260
|
continue;
|
|
9258
9261
|
}
|
|
9262
|
+
const note = typeof r.description === "string" ? String(r.description).trim() : "";
|
|
9259
9263
|
accepted.push({
|
|
9260
9264
|
eventId: `${opts.tenantId}-op-${kind}-${++seq}`,
|
|
9261
9265
|
eventType: spec.eventType,
|
|
9262
9266
|
eventTime: new Date(atMs).toISOString(),
|
|
9263
9267
|
tenantId: opts.tenantId,
|
|
9268
|
+
...note ? { description: note } : {},
|
|
9264
9269
|
data
|
|
9265
9270
|
});
|
|
9266
9271
|
}
|
package/package.json
CHANGED