@things-factory/ops-master 10.1.37 → 10.1.38

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.
Files changed (58) hide show
  1. package/dist-client/bootstrap.js +8 -22
  2. package/dist-client/bootstrap.js.map +1 -1
  3. package/dist-client/master-change-policy-axes.d.ts +17 -0
  4. package/dist-client/master-change-policy-axes.js +17 -0
  5. package/dist-client/master-change-policy-axes.js.map +1 -1
  6. package/dist-client/master-change-policy-panel.d.ts +10 -0
  7. package/dist-client/master-change-policy-panel.js +79 -20
  8. package/dist-client/master-change-policy-panel.js.map +1 -1
  9. package/dist-client/tsconfig.tsbuildinfo +1 -1
  10. package/dist-server/index.js +10 -0
  11. package/dist-server/index.js.map +1 -1
  12. package/dist-server/service/index.d.ts +2 -1
  13. package/dist-server/service/index.js +1 -0
  14. package/dist-server/service/index.js.map +1 -1
  15. package/dist-server/service/master-axis.d.ts +14 -3
  16. package/dist-server/service/master-axis.js +16 -15
  17. package/dist-server/service/master-axis.js.map +1 -1
  18. package/dist-server/service/master-change-policy.d.ts +9 -0
  19. package/dist-server/service/master-change-policy.js +21 -0
  20. package/dist-server/service/master-change-policy.js.map +1 -1
  21. package/dist-server/service/material/material-revision-resolver.d.ts +7 -2
  22. package/dist-server/service/material/material-revision-resolver.js +18 -0
  23. package/dist-server/service/material/material-revision-resolver.js.map +1 -1
  24. package/dist-server/service/material/material-revision-service.d.ts +32 -2
  25. package/dist-server/service/material/material-revision-service.js +129 -0
  26. package/dist-server/service/material/material-revision-service.js.map +1 -1
  27. package/dist-server/service/material/material-revision.d.ts +7 -5
  28. package/dist-server/service/material/material-revision.js +2 -2
  29. package/dist-server/service/material/material-revision.js.map +1 -1
  30. package/dist-server/service/recipe/index.d.ts +1 -1
  31. package/dist-server/service/recipe/recipe-revision-resolver.d.ts +7 -2
  32. package/dist-server/service/recipe/recipe-revision-resolver.js +18 -0
  33. package/dist-server/service/recipe/recipe-revision-resolver.js.map +1 -1
  34. package/dist-server/service/recipe/recipe-revision-service.d.ts +33 -2
  35. package/dist-server/service/recipe/recipe-revision-service.js +139 -0
  36. package/dist-server/service/recipe/recipe-revision-service.js.map +1 -1
  37. package/dist-server/service/recipe/recipe-revision.d.ts +8 -6
  38. package/dist-server/service/recipe/recipe-revision.js +2 -2
  39. package/dist-server/service/recipe/recipe-revision.js.map +1 -1
  40. package/dist-server/service/revision-baseline.d.ts +63 -0
  41. package/dist-server/service/revision-baseline.js +72 -0
  42. package/dist-server/service/revision-baseline.js.map +1 -0
  43. package/dist-server/service/test-spec/test-spec-revision-resolver.d.ts +7 -2
  44. package/dist-server/service/test-spec/test-spec-revision-resolver.js +18 -0
  45. package/dist-server/service/test-spec/test-spec-revision-resolver.js.map +1 -1
  46. package/dist-server/service/test-spec/test-spec-revision-service.d.ts +37 -2
  47. package/dist-server/service/test-spec/test-spec-revision-service.js +122 -0
  48. package/dist-server/service/test-spec/test-spec-revision-service.js.map +1 -1
  49. package/dist-server/service/test-spec/test-spec-revision.d.ts +7 -5
  50. package/dist-server/service/test-spec/test-spec-revision.js +2 -2
  51. package/dist-server/service/test-spec/test-spec-revision.js.map +1 -1
  52. package/dist-server/tsconfig.tsbuildinfo +1 -1
  53. package/package.json +4 -5
  54. package/translations/en.json +5 -1
  55. package/translations/ja.json +5 -1
  56. package/translations/ko.json +5 -1
  57. package/translations/ms.json +5 -1
  58. package/translations/zh.json +5 -1
@@ -46,8 +46,8 @@ export declare class RecipeRevisionResolver {
46
46
  route: string | null;
47
47
  effectiveFrom: Date;
48
48
  reason: string;
49
- creator: import("@things-factory/auth-base").User;
50
- creatorId: string;
49
+ creator: import("@things-factory/auth-base").User | null;
50
+ creatorId: string | null;
51
51
  createdAt: Date;
52
52
  frozenAt: Date | null;
53
53
  contentHash: string | null;
@@ -56,4 +56,9 @@ export declare class RecipeRevisionResolver {
56
56
  }>;
57
57
  createRecipeDraft(content: RecipeDraftContent, recipeId: string, name: string, baseRevisionId: string, context: ResolverContext): Promise<import("./recipe-revision").RecipeRevision>;
58
58
  editRecipeDraft(revisionId: string, editGeneration: number, content: RecipeDraftContent, context: ResolverContext): Promise<import("./recipe-revision").RecipeRevision>;
59
+ /** 비규제 사업장의 저장 한 번 — 초안과 발행이 한 트랜잭션이다. 승인제면 거절되고 아무것도 안 남는다. */
60
+ saveAndPublishRecipe(content: RecipeDraftContent, recipeId: string, name: string, baseRevisionId: string, context: ResolverContext): Promise<{
61
+ revision: import("./recipe-revision").RecipeRevision;
62
+ plan: import("./recipe-revision").RecipePlan;
63
+ }>;
59
64
  }
@@ -22,6 +22,11 @@ let RecipeRevisionResolver = class RecipeRevisionResolver {
22
22
  const { tx, domain, user } = context.state;
23
23
  return (0, recipe_revision_service_1.editRecipeDraft)(tx, domain.id, user.id, revisionId, editGeneration, content);
24
24
  }
25
+ /** 비규제 사업장의 저장 한 번 — 초안과 발행이 한 트랜잭션이다. 승인제면 거절되고 아무것도 안 남는다. */
26
+ async saveAndPublishRecipe(content, recipeId, name, baseRevisionId, context) {
27
+ const { tx, domain, user } = context.state;
28
+ return (0, recipe_revision_service_1.saveAndPublishRecipe)(tx, domain.id, user.id, { recipeId, name, baseRevisionId, content });
29
+ }
25
30
  };
26
31
  exports.RecipeRevisionResolver = RecipeRevisionResolver;
27
32
  tslib_1.__decorate([
@@ -69,6 +74,19 @@ tslib_1.__decorate([
69
74
  tslib_1.__metadata("design:paramtypes", [String, Number, Object, Object]),
70
75
  tslib_1.__metadata("design:returntype", Promise)
71
76
  ], RecipeRevisionResolver.prototype, "editRecipeDraft", null);
77
+ tslib_1.__decorate([
78
+ (0, type_graphql_1.Directive)('@privilege(category: "ops-master", privilege: "mutation", domainOwnerGranted: true)'),
79
+ (0, type_graphql_1.Directive)('@transaction'),
80
+ (0, type_graphql_1.Mutation)(() => shell_1.ScalarObject),
81
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('content', () => shell_1.ScalarObject)),
82
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('recipeId', () => String, { nullable: true })),
83
+ tslib_1.__param(2, (0, type_graphql_1.Arg)('name', () => String, { nullable: true })),
84
+ tslib_1.__param(3, (0, type_graphql_1.Arg)('baseRevisionId', () => String, { nullable: true })),
85
+ tslib_1.__param(4, (0, type_graphql_1.Ctx)()),
86
+ tslib_1.__metadata("design:type", Function),
87
+ tslib_1.__metadata("design:paramtypes", [Object, String, String, String, Object]),
88
+ tslib_1.__metadata("design:returntype", Promise)
89
+ ], RecipeRevisionResolver.prototype, "saveAndPublishRecipe", null);
72
90
  exports.RecipeRevisionResolver = RecipeRevisionResolver = tslib_1.__decorate([
73
91
  (0, type_graphql_1.Resolver)(),
74
92
  (0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
@@ -1 +1 @@
1
- {"version":3,"file":"recipe-revision-resolver.js","sourceRoot":"","sources":["../../../server/service/recipe/recipe-revision-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Int, Mutation, Query, Resolver, UseMiddleware } from 'type-graphql'\nimport { getRepository, ScalarObject, SpeakRefusals } from '@things-factory/shell'\nimport { RecipeDefinition } from './recipe-definition'\nimport { createRecipeDraft, editRecipeDraft, publishUnregulatedRecipe, recipeRevisionOverview } from './recipe-revision-service'\n\nimport { RecipeDraftContent } from './recipe-revision-content'\n\n@Resolver()\n@UseMiddleware(SpeakRefusals)\nexport class RecipeRevisionResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async publishRecipeDraft(@Arg('revisionId') revisionId: string, @Arg('editGeneration', () => Int) editGeneration: number, @Ctx() context: ResolverContext) {\n const { tx, domain, user } = context.state\n return publishUnregulatedRecipe(tx, domain.id, user.id, revisionId, editGeneration)\n }\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(() => ScalarObject)\n async recipeRevisions(@Arg('recipeId') recipeId: string, @Ctx() context: ResolverContext) {\n return recipeRevisionOverview(getRepository(RecipeDefinition).manager, context.state.domain.id, recipeId)\n }\n\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async createRecipeDraft(\n @Arg('content', () => ScalarObject) content: RecipeDraftContent,\n @Arg('recipeId', () => String, { nullable: true }) recipeId: string,\n @Arg('name', () => String, { nullable: true }) name: string,\n @Arg('baseRevisionId', () => String, { nullable: true }) baseRevisionId: string,\n @Ctx() context: ResolverContext\n ) {\n const { tx, domain, user } = context.state\n return createRecipeDraft(tx, domain.id, user.id, { recipeId, name, baseRevisionId, content })\n }\n\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async editRecipeDraft(\n @Arg('revisionId') revisionId: string,\n @Arg('editGeneration', () => Int) editGeneration: number,\n @Arg('content', () => ScalarObject) content: RecipeDraftContent,\n @Ctx() context: ResolverContext\n ) {\n const { tx, domain, user } = context.state\n return editRecipeDraft(tx, domain.id, user.id, revisionId, editGeneration, content)\n }\n}\n"]}
1
+ {"version":3,"file":"recipe-revision-resolver.js","sourceRoot":"","sources":["../../../server/service/recipe/recipe-revision-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Int, Mutation, Query, Resolver, UseMiddleware } from 'type-graphql'\nimport { getRepository, ScalarObject, SpeakRefusals } from '@things-factory/shell'\nimport { RecipeDefinition } from './recipe-definition'\nimport { saveAndPublishRecipe, createRecipeDraft, editRecipeDraft, publishUnregulatedRecipe, recipeRevisionOverview } from './recipe-revision-service'\n\nimport { RecipeDraftContent } from './recipe-revision-content'\n\n@Resolver()\n@UseMiddleware(SpeakRefusals)\nexport class RecipeRevisionResolver {\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async publishRecipeDraft(@Arg('revisionId') revisionId: string, @Arg('editGeneration', () => Int) editGeneration: number, @Ctx() context: ResolverContext) {\n const { tx, domain, user } = context.state\n return publishUnregulatedRecipe(tx, domain.id, user.id, revisionId, editGeneration)\n }\n @Directive('@privilege(category: \"ops-master\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(() => ScalarObject)\n async recipeRevisions(@Arg('recipeId') recipeId: string, @Ctx() context: ResolverContext) {\n return recipeRevisionOverview(getRepository(RecipeDefinition).manager, context.state.domain.id, recipeId)\n }\n\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async createRecipeDraft(\n @Arg('content', () => ScalarObject) content: RecipeDraftContent,\n @Arg('recipeId', () => String, { nullable: true }) recipeId: string,\n @Arg('name', () => String, { nullable: true }) name: string,\n @Arg('baseRevisionId', () => String, { nullable: true }) baseRevisionId: string,\n @Ctx() context: ResolverContext\n ) {\n const { tx, domain, user } = context.state\n return createRecipeDraft(tx, domain.id, user.id, { recipeId, name, baseRevisionId, content })\n }\n\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async editRecipeDraft(\n @Arg('revisionId') revisionId: string,\n @Arg('editGeneration', () => Int) editGeneration: number,\n @Arg('content', () => ScalarObject) content: RecipeDraftContent,\n @Ctx() context: ResolverContext\n ) {\n const { tx, domain, user } = context.state\n return editRecipeDraft(tx, domain.id, user.id, revisionId, editGeneration, content)\n }\n\n /** 비규제 사업장의 저장 한 번 — 초안과 발행이 한 트랜잭션이다. 승인제면 거절되고 아무것도 안 남는다. */\n @Directive('@privilege(category: \"ops-master\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Mutation(() => ScalarObject)\n async saveAndPublishRecipe(\n @Arg('content', () => ScalarObject) content: RecipeDraftContent,\n @Arg('recipeId', () => String, { nullable: true }) recipeId: string,\n @Arg('name', () => String, { nullable: true }) name: string,\n @Arg('baseRevisionId', () => String, { nullable: true }) baseRevisionId: string,\n @Ctx() context: ResolverContext\n ) {\n const { tx, domain, user } = context.state\n return saveAndPublishRecipe(tx, domain.id, user.id, { recipeId, name, baseRevisionId, content })\n }\n}\n"]}
@@ -79,6 +79,22 @@ export declare function resolveRecipe(manager: EntityManager, domainId: string,
79
79
  plan: RecipePlan;
80
80
  segment: RecipeSegment;
81
81
  }>;
82
+ /**
83
+ * **개정본이 하나도 없는 제조법**마다 지금 서 있는 행을 첫 개정본으로 적는다 — 기준선(2026-09-24).
84
+ * 규칙은 검사 명세의 `standTestSpecificationBaselines` 와 같다. 제조법만의 것 둘:
85
+ *
86
+ * - 옛 행의 줄에는 `lineKey` 가 없다. **자리로 붙인다** — `input-1` · `output-1`. plant 시드가 쓰는 규칙과
87
+ * 같고, 줄의 차례가 뜻을 가지는 모델이라 자리에서 온 키는 내용을 바꾸지 않는다.
88
+ * - 품목 · 공정 · 경로는 이름으로 가리킨다. **쓰기 전에 전부 대조한다** — 줄을 쓰다가 거절되면 반쯤 쓴
89
+ * 개정본이 트랜잭션에 남는다. 없는 것을 가리키는 행은 세우지 않고 까닭을 남긴다.
90
+ */
91
+ export declare function standRecipeBaselines(manager: EntityManager, domainId: string, at: Date, edition: string): Promise<{
92
+ stood: number;
93
+ unreadable: {
94
+ name: string;
95
+ problem: string;
96
+ }[];
97
+ }>;
82
98
  /** Replay reads verify the captured digest too, not only the currently effective schedule. */
83
99
  export declare function recipeRevisionForBasis(manager: EntityManager, domainId: string, basis: RecipeBasis): Promise<RecipeRevision>;
84
100
  /** Must run inside the transaction that writes the execution result. */
@@ -127,8 +143,8 @@ export declare function recipeRevisionOverview(manager: EntityManager, domainId:
127
143
  route: string | null;
128
144
  effectiveFrom: Date;
129
145
  reason: string;
130
- creator: import("@things-factory/auth-base").User;
131
- creatorId: string;
146
+ creator: import("@things-factory/auth-base").User | null;
147
+ creatorId: string | null;
132
148
  createdAt: Date;
133
149
  frozenAt: Date | null;
134
150
  contentHash: string | null;
@@ -145,3 +161,18 @@ export declare function effectiveRecipe(manager: EntityManager, domainId: string
145
161
  inputs: import("./recipe-revision-content").RecipeLineContent[];
146
162
  outputs: import("./recipe-revision-content").RecipeLineContent[];
147
163
  }>;
164
+ /**
165
+ * **비규제 사업장의 「저장」 한 번** — 초안을 만들고 바로 발행한다, 한 트랜잭션에서(ADR-0086 09-22 보탬).
166
+ * 비규제면 사람이 누를 것은 저장 하나다. 두 걸음(초안 저장 → 발행)이 구조상 필연인 것처럼 보이게 하지 않는다.
167
+ * 이 축이 승인제면 발행이 `MASTER_APPROVAL_REQUIRED` 로 거절되고, 같은 트랜잭션이라 초안도 함께 물러난다 —
168
+ * 반쯤 저장된 것이 남지 않는다. 개정본 · 적용계획 · 구간은 두 걸음 때와 똑같이 선다.
169
+ */
170
+ export declare function saveAndPublishRecipe(manager: EntityManager, domainId: string, actorId: string, asked: {
171
+ recipeId?: string;
172
+ name?: string;
173
+ baseRevisionId?: string;
174
+ content: RecipeDraftContent;
175
+ }): Promise<{
176
+ revision: RecipeRevision;
177
+ plan: RecipePlan;
178
+ }>;
@@ -11,10 +11,12 @@ exports.bindRecipeApproval = bindRecipeApproval;
11
11
  exports.publishRecipeRevision = publishRecipeRevision;
12
12
  exports.publishUnregulatedRecipe = publishUnregulatedRecipe;
13
13
  exports.resolveRecipe = resolveRecipe;
14
+ exports.standRecipeBaselines = standRecipeBaselines;
14
15
  exports.recipeRevisionForBasis = recipeRevisionForBasis;
15
16
  exports.captureRecipeBasis = captureRecipeBasis;
16
17
  exports.recipeRevisionOverview = recipeRevisionOverview;
17
18
  exports.effectiveRecipe = effectiveRecipe;
19
+ exports.saveAndPublishRecipe = saveAndPublishRecipe;
18
20
  const node_crypto_1 = require("node:crypto");
19
21
  const typeorm_1 = require("typeorm");
20
22
  const shell_1 = require("@things-factory/shell");
@@ -499,6 +501,8 @@ async function resolveRecipe(manager, domainId, recipeId, businessTime, knownAt
499
501
  if (currentLock(manager).lock)
500
502
  query.setLock('pessimistic_write');
501
503
  const segments = await query.getMany();
504
+ if (!segments.length)
505
+ await refuseBeforeBaseline(manager, domainId, recipeId, at);
502
506
  if (segments.length !== 1)
503
507
  refuse(segments.length ? 'AMBIGUOUS_EFFECTIVITY' : 'NO_EFFECTIVE_REVISION');
504
508
  const selected = await revision(manager, domainId, segments[0].revisionId);
@@ -506,6 +510,130 @@ async function resolveRecipe(manager, domainId, recipeId, businessTime, knownAt
506
510
  refuse('REVISION_INTEGRITY_FAILURE');
507
511
  return { revision: selected, plan, segment: segments[0] };
508
512
  }
513
+ /** 기준선보다 앞선 시각은 모른다고 말한다 — 검사 명세의 같은 자리를 보라(2026-09-24). */
514
+ async function refuseBeforeBaseline(manager, domainId, recipeId, at) {
515
+ const first = await manager.findOneBy(recipe_revision_1.RecipePlan, {
516
+ domain: { id: domainId }, recipe: { id: recipeId }, generation: 1, releaseKind: 'baseline'
517
+ });
518
+ if (!first)
519
+ return;
520
+ const recorded = await manager.findOneBy(recipe_revision_1.RecipeRevision, { domain: { id: domainId }, id: first.publishedRevisionId });
521
+ if (recorded && at < recorded.effectiveFrom)
522
+ throw new shell_1.Refusal('BEFORE_BASELINE', { baselineAt: recorded.effectiveFrom.toISOString() }, `This master was first recorded at ${recorded.effectiveFrom.toISOString()}; nothing is known about it before then.`);
523
+ }
524
+ /**
525
+ * **개정본이 하나도 없는 제조법**마다 지금 서 있는 행을 첫 개정본으로 적는다 — 기준선(2026-09-24).
526
+ * 규칙은 검사 명세의 `standTestSpecificationBaselines` 와 같다. 제조법만의 것 둘:
527
+ *
528
+ * - 옛 행의 줄에는 `lineKey` 가 없다. **자리로 붙인다** — `input-1` · `output-1`. plant 시드가 쓰는 규칙과
529
+ * 같고, 줄의 차례가 뜻을 가지는 모델이라 자리에서 온 키는 내용을 바꾸지 않는다.
530
+ * - 품목 · 공정 · 경로는 이름으로 가리킨다. **쓰기 전에 전부 대조한다** — 줄을 쓰다가 거절되면 반쯤 쓴
531
+ * 개정본이 트랜잭션에 남는다. 없는 것을 가리키는 행은 세우지 않고 까닭을 남긴다.
532
+ */
533
+ async function standRecipeBaselines(manager, domainId, at, edition) {
534
+ transaction(manager);
535
+ const roots = await manager
536
+ .createQueryBuilder(recipe_definition_1.RecipeDefinition, 'recipe')
537
+ .leftJoin(recipe_revision_1.RecipeRevision, 'rev', 'rev.recipe_id = recipe.id AND rev.domain_id = recipe.domain_id')
538
+ .where('recipe.domain_id = :domainId', { domainId })
539
+ .andWhere('rev.id IS NULL')
540
+ .getMany();
541
+ const outcome = { stood: 0, unreadable: [] };
542
+ if (!roots.length)
543
+ return outcome;
544
+ const policy = await (0, master_change_policy_1.masterChangePolicy)(manager, domainId, 'recipeDefinition');
545
+ const where = { where: { domain: { id: domainId } } };
546
+ const materials = new Set((await manager.find(material_definition_1.MaterialDefinition, where)).map(one => one.name));
547
+ const operations = new Set((await manager.find(operation_definition_1.OperationDefinition, where)).map(one => one.name));
548
+ const routes = new Map((await manager.find(route_definition_1.RouteDefinition, where)).map(one => [one.name, one]));
549
+ const keyed = (rows, side) => Array.isArray(rows) ? rows.map((row, index) => ({ ...row, lineKey: row?.lineKey ?? `${side}-${index + 1}` })) : rows;
550
+ for (const root of roots) {
551
+ if (root.planGeneration !== 0) {
552
+ outcome.unreadable.push({ name: root.name, problem: 'plan without revision' });
553
+ continue;
554
+ }
555
+ let read;
556
+ try {
557
+ read = (0, recipe_revision_content_1.recipeContentValues)({
558
+ materialDefinitionName: root.materialDefinitionName,
559
+ description: root.description ?? null,
560
+ route: root.route ?? null,
561
+ inputs: keyed(root.inputs, 'input'),
562
+ outputs: keyed(root.outputs, 'output')
563
+ });
564
+ }
565
+ catch (error) {
566
+ outcome.unreadable.push({ name: root.name, problem: error?.message ?? String(error) });
567
+ continue;
568
+ }
569
+ const route = read.route ? routes.get(read.route) : null;
570
+ const missing = [
571
+ ...(materials.has(read.materialDefinitionName) ? [] : [`material ${read.materialDefinitionName}`]),
572
+ ...(read.route && !route ? [`route ${read.route}`] : []),
573
+ ...[...read.inputs, ...read.outputs].filter(line => !materials.has(line.material)).map(line => `material ${line.material}`),
574
+ ...read.inputs
575
+ .filter(line => line.operation && (!operations.has(line.operation) || !route?.steps.includes(line.operation)))
576
+ .map(line => `operation ${line.operation} in route ${read.route ?? '(none)'}`)
577
+ ];
578
+ if (missing.length) {
579
+ outcome.unreadable.push({ name: root.name, problem: 'points at what this domain does not have: ' + [...new Set(missing)].join(', ') });
580
+ continue;
581
+ }
582
+ const validFrom = root.effectiveStart && root.effectiveStart > at ? root.effectiveStart : at;
583
+ const validTo = root.effectiveEnd ?? null;
584
+ const { inputs, outputs, ...header } = read;
585
+ const saved = await manager.save(recipe_revision_1.RecipeRevision, manager.create(recipe_revision_1.RecipeRevision, {
586
+ ...header,
587
+ effectiveFrom: validFrom,
588
+ reason: `baseline: the row as it stood, recorded by ${edition}`,
589
+ ...await headerReferences(manager, domainId, read),
590
+ policy: { id: policy.id },
591
+ domain: { id: domainId },
592
+ recipe: { id: root.id },
593
+ baseRevision: null,
594
+ baseGeneration: 0,
595
+ revisionNumber: 1,
596
+ editGeneration: 0,
597
+ creator: null,
598
+ createdAt: at,
599
+ frozenAt: at,
600
+ contentHash: null,
601
+ activityInstanceId: null
602
+ }));
603
+ await saveLines(manager, domainId, root.id, saved.id, inputs, outputs);
604
+ const stood = await revision(manager, domainId, saved.id);
605
+ const contentHash = recipeSubmissionHash(stood);
606
+ await manager.update(recipe_revision_1.RecipeRevision, { id: stood.id, domain: { id: domainId } }, { contentHash });
607
+ const plan = await manager.save(recipe_revision_1.RecipePlan, manager.create(recipe_revision_1.RecipePlan, {
608
+ domain: { id: domainId },
609
+ recipe: { id: root.id },
610
+ generation: 1,
611
+ recordedAt: at,
612
+ activityInstanceId: null,
613
+ submissionHash: contentHash,
614
+ approver: null,
615
+ publisher: null,
616
+ releaseKind: 'baseline',
617
+ publishedRevision: { id: stood.id },
618
+ policy: { id: policy.id }
619
+ }));
620
+ if (!validTo || validTo > validFrom) {
621
+ await manager.save(recipe_revision_1.RecipeSegment, manager.create(recipe_revision_1.RecipeSegment, {
622
+ domain: { id: domainId },
623
+ recipe: { id: root.id },
624
+ plan: { id: plan.id },
625
+ revision: { id: stood.id },
626
+ validFrom,
627
+ validTo
628
+ }));
629
+ }
630
+ const advanced = await manager.update(recipe_definition_1.RecipeDefinition, { id: root.id, domain: { id: domainId }, planGeneration: 0 }, { planGeneration: 1 });
631
+ if (advanced.affected !== 1)
632
+ refuse('PLAN_CONFLICT');
633
+ outcome.stood++;
634
+ }
635
+ return outcome;
636
+ }
509
637
  /** Replay reads verify the captured digest too, not only the currently effective schedule. */
510
638
  async function recipeRevisionForBasis(manager, domainId, basis) {
511
639
  if (basis.domainId !== domainId)
@@ -601,4 +729,15 @@ async function effectiveRecipe(manager, domainId, recipe, at = new Date()) {
601
729
  effectiveEnd: selected.segment.validTo ?? undefined
602
730
  });
603
731
  }
732
+ /**
733
+ * **비규제 사업장의 「저장」 한 번** — 초안을 만들고 바로 발행한다, 한 트랜잭션에서(ADR-0086 09-22 보탬).
734
+ * 비규제면 사람이 누를 것은 저장 하나다. 두 걸음(초안 저장 → 발행)이 구조상 필연인 것처럼 보이게 하지 않는다.
735
+ * 이 축이 승인제면 발행이 `MASTER_APPROVAL_REQUIRED` 로 거절되고, 같은 트랜잭션이라 초안도 함께 물러난다 —
736
+ * 반쯤 저장된 것이 남지 않는다. 개정본 · 적용계획 · 구간은 두 걸음 때와 똑같이 선다.
737
+ */
738
+ async function saveAndPublishRecipe(manager, domainId, actorId, asked) {
739
+ const draft = await createRecipeDraft(manager, domainId, actorId, asked);
740
+ const plan = await publishUnregulatedRecipe(manager, domainId, actorId, draft.id, draft.editGeneration);
741
+ return { revision: await revision(manager, domainId, draft.id, false), plan };
742
+ }
604
743
  //# sourceMappingURL=recipe-revision-service.js.map