omc-core 0.4.35 → 0.4.37

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.
@@ -1,917 +0,0 @@
1
- import { createHash, randomUUID } from "node:crypto";
2
- import { canonicalCloudPivotBaselineFingerprint, canonicalCloudPivotEnvironmentFingerprint } from "./cloudpivot-fingerprints.js";
3
- import { canonicalFormalDiscoveryFingerprint } from "./formal-capability-discovery.js";
4
- import { CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH, decodeRequiredDataRuleRow, decodeDraftControl, decodePublishedControl } from "./cloudpivot-low-code.js";
5
- import { compileNativeOperations, runNativeConfigurationPackage } from "./cloudpivot-native-configuration.js";
6
- import { buildKnowledgePack } from "./knowledge-pack-builder.js";
7
- import { KnowledgePackRuntime } from "./knowledge-pack-runtime.js";
8
- import { createDeliveryPlanApproval, deliveryPlanApprovalHash, proposeDeliveryPlan } from "./two-stage-change-package.js";
9
- import { validateConfigurationIntent } from "./configuration-intent.js";
10
- import { SENSITIVE_SECRET_VALUE } from "./delivery-graph.js";
11
- import { appendApprovalHumanBlock } from "./approval-frame-readability.js";
12
- import { isTicket08TargetSchema } from "./ticket08-test-model-mutation.js";
13
- import { fieldFamilyMembers, activeFieldFamily } from "./families/registry.js";
14
- import { isTicket09TargetField, TICKET09_FIELD_FAMILY } from "./ticket09-test-field-mutation.js";
15
- import { TICKET11_FORM_DRAFT_ROUTE, decodeTicket11DraftControlPresence } from "./ticket11-test-form-draft.js";
16
- import { TICKET20_DATA_RULE_ROUTE } from "./ticket20-test-data-rule.js";
17
- /**
18
- * Ticket 03b: the required-rule demo member — the Ticket 20 data-rule
19
- * handoff binds the dataRuleType=4 row to this member's field — is the
20
- * ACTIVE family's registered rule-demo position (single source: the
21
- * family module src/families/<family>.ts).
22
- */
23
- function ticket12RuleDemoFieldCode(targetFieldCodes) {
24
- return targetFieldCodes[activeFieldFamily().ruleDemoTargetPosition - 1];
25
- }
26
- function ticket12RuleDemoMemberName() {
27
- return activeFieldFamily().members[activeFieldFamily().ruleDemoTargetPosition - 1].propertyTypeName;
28
- }
29
- /**
30
- * Ticket 12 (usable-model ladder, rung 4 — the ceiling) promotes exactly one
31
- * independently bounded CloudPivot `test` form mutation: the model-scoped
32
- * publication of the composite fixture's default form, completing the
33
- * structurally usable shape — model, published fields, published form —
34
- * verified at design-time depth through authoritative readback, the form
35
- * publish history surface, and the designer direct URL. The composite chain
36
- * runs the executable Ticket 08 model-create, Ticket 09 field-create,
37
- * Ticket 10 field-publish, and Ticket 11 form-draft capabilities first; the
38
- * form-publish package consumes the completed, behavior-validated form-draft
39
- * execution report plus fresh authoritative readbacks (published field
40
- * present with the published flag decoded; the default form present with the
41
- * draft control bound and published=false). The package is independently
42
- * immutable and independently dual-approved. No evidence is inferred from
43
- * the form-draft rung or any other rung; app publish, Environment release,
44
- * deployment, restart, Portal-facing operations, production, staging, tenant
45
- * administration, Redis, and runtime CRUD stay permanently rejected.
46
- *
47
- * Authoritative 8.6.26 contract (Stage 0 decompiled sources, research note
48
- * .scratch/omc-usable-model-ladder/research/form-schema-contract.md §8-12):
49
- * - publish: POST /api/api/app/bizsheet/publish with the echoed BizSheetVO
50
- * normalized exactly as the product's own pre-publish path
51
- * (AppFormController → BizFormController.java:824-970, @RequireAdmin,
52
- * schema lock, AppIntegrationFacadeImpl.java:2725-2746): the draft JSON
53
- * sides promoted to the published members, existDraft:false,
54
- * sendMessage:false (the controller unboxes it — null would NPE);
55
- * - the server flips published=true, copies draft*Json to published*Json,
56
- * republishes the schema store, and evicts the form cache
57
- * (BizFormServiceImpl.java:189-238) — the mechanism that discharges the
58
- * form-consistency-lag recorded on the Ticket 10 rung: after this rung's
59
- * explicit publication the authoritative form readback no longer lags;
60
- * - the binding constraint (BizFormServiceImpl.java:544-582): every
61
- * data-bound control key must resolve in the published schema store — the
62
- * fixture binds only the Ticket-10-published TEXT field;
63
- * - history surface (BizFormHistoryController.java:60-167): POST
64
- * /api/api/app/bizsheet/history/list {schemaCode, sheetCode, page, size}
65
- * decodes a version-DESC page whose entries carry version, publishRemarks
66
- * (mirrored from the row's remarks), and the publisher display name; GET
67
- * /api/api/app/bizsheet/history/checkVersion?schemaCode&sheetCode decodes
68
- * the newest version (data null when no history exists). PINNED LIVE
69
- * 2026-09-04: a design-time model-scoped publication writes NO history
70
- * rows — the controller is read-only across the engine, the publish flow
71
- * writes the EDIT_AND_PUBLISH_FORM system operation log instead, and the
72
- * manually published agent_test_customer also carries zero entries — so
73
- * the authoritative post-publish decode is a live version int with an
74
- * empty list (classification present, reason design-time-no-entries);
75
- * rows only enter through app-package import/export flows;
76
- * - success envelope: errcode 0 "发布表单成功" (940114), data = the new
77
- * version int;
78
- * - audit face: server-side LogOperationActionType.EDIT_AND_PUBLISH_FORM
79
- * with before/after data (BizFormController.java:902-908); no separate
80
- * audit read API is evidenced — the history surface above is the
81
- * authoritative publish-history read;
82
- * - publish-gated menu: apppackage/trees is the published application menu
83
- * projection; a model-scoped form publication is not an app publish, so
84
- * the live run records the read-only observation and never performs any
85
- * Portal-facing mutation;
86
- * - cleanup (variants A/B, §11): the model physical-delete cascade deletes
87
- * every form of the schema with no published-state branch
88
- * (AppIntegrationFacadeImpl.java:743-801) and the form history dies with
89
- * the model (removeBizModel → formHistoryFacade.deleteBySchemaCode);
90
- * variant A keeps the staged chain (Ticket 10 published-field cleanup,
91
- * then the Ticket 08 model physical delete) with form absence confirmed by
92
- * the 302024 envelope and history absence by checkVersion data null;
93
- * variant B stops, retains, and reports if the cascade contradicts the
94
- * decompile. Form-level /delete refuses default forms by design and is
95
- * never the cleanup path.
96
- */
97
- export const TICKET12_FORM_PUBLISH_ROUTE = "ticket12-test-form-publish";
98
- export const TICKET12_FORM_PUBLISH_CAPABILITY_ID = "cloudpivot.test.form-publish-8.6.26";
99
- export const TICKET12_FORM_CLEANUP_CAPABILITY_ID = "cloudpivot.test.form-publish-cascade-absence-8.6.26";
100
- export const TICKET12_FORM_PUBLISH_KNOWLEDGE_PACK_ID = "cloudpivot-8.6-ticket12-test-form-publish";
101
- export const TICKET12_TEST_ENVIRONMENT_NAME = "test";
102
- export const TICKET12_TEST_APPLICATION_CODE = "test";
103
- export const TICKET12_REFERENCE_EVIDENCE_VERSION = "8.6.26";
104
- export const TICKET12_FORM_PUBLISH_ENDPOINT = "/api/api/app/bizsheet/publish";
105
- export const TICKET12_FORM_READBACK_ENDPOINT = "/api/api/app/bizsheet/get";
106
- export const TICKET12_FORM_HISTORY_LIST_ENDPOINT = "/api/api/app/bizsheet/history/list";
107
- export const TICKET12_FORM_HISTORY_CHECK_VERSION_ENDPOINT = "/api/api/app/bizsheet/history/checkVersion";
108
- export const TICKET12_TREES_OBSERVATION_ENDPOINT = "/api/api/app/apppackage/trees";
109
- export const TICKET12_PUBLISH_REMARKS = "omc-ticket12-model-scoped-form-publication";
110
- export const TICKET12_PROHIBITED_MUTATION_TERMS = Object.freeze([
111
- "app-publish", "apppackage/publish", "deploy", "restart", "release", "redis", "tenant-admin", "runtime-crud",
112
- "model:", "view", "folder-create", "folder-delete", "portal",
113
- ]);
114
- const TICKET12_UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
115
- const SHA256 = /^[a-f0-9]{64}$/i;
116
- /** The named `test` environment and its dedicated test application are hard preconditions. */
117
- export function assertTicket12TestFormPublishEnvironment(settings) {
118
- if (settings.environmentName !== "test")
119
- throw new Error("Ticket 12 form publish is restricted to the named test environment; production and staging are rejected.");
120
- if (!settings.baseUrl.trim() || !/^https?:\/\/\S+$/i.test(settings.baseUrl.trim()))
121
- throw new Error("Ticket 12 form publish requires an absolute configured test environment endpoint.");
122
- if (settings.testApplicationCode !== "test")
123
- throw new Error("Ticket 12 form publish requires the dedicated test application to be test.");
124
- }
125
- export function ticket12DeliveryId(testRunId) { return `ticket12-form-publish-${testRunId}`; }
126
- /** The exact approved operation scope is the ledger's mutation+target key for the one publish step (same target family as the draft rung; the publication identity is carried by the capability, contract hash, operation id, and route). */
127
- export function ticket12FormPublishScope(targetSchemaCode, targetSheetCode) { return `cloudpivot:form:${targetSchemaCode}/${targetSheetCode}`; }
128
- /** Design-time designer direct URL; the published fixture form stays inspectable here. */
129
- export function ticket12DesignerDirectUrl(targetSchemaCode, targetSheetCode) { return `/admin/#/apps/model/${TICKET12_TEST_APPLICATION_CODE}/${targetSchemaCode}/form-design/${targetSheetCode}`; }
130
- export function buildTicket12FormCleanupContract(testRunId, targetSchemaCode, targetSheetCode, targetFieldCodes) {
131
- if (!TICKET12_UUID_V4.test(testRunId) || !isTicket08TargetSchema(targetSchemaCode) || targetSheetCode !== targetSchemaCode || targetFieldCodes.length !== TICKET09_FIELD_FAMILY.length || targetFieldCodes.some((code) => !isTicket09TargetField(code)) || new Set(targetFieldCodes).size !== TICKET09_FIELD_FAMILY.length)
132
- throw new Error("Ticket 12 form cleanup contract requires the exact host-owned testRunId, fixture schema, default sheet, and one distinct family field code per active family member.");
133
- return Object.freeze({
134
- capabilityId: TICKET12_FORM_CLEANUP_CAPABILITY_ID,
135
- testRunId,
136
- targetSchemaCode,
137
- targetSheetCode,
138
- targetFieldCodes,
139
- formDeleteEndpointRefusal: "bizsheet/delete-refuses-default-forms(BIZ_SHEET_DEFAULT,BizFormController.java:610-670);never-the-cleanup-path",
140
- variants: {
141
- modelCascade: "model-physical-delete-cascades-published-forms: staged ticket10-published-field-cleanup then ticket08-model-physical-delete; form absence by bizsheet/get non-success envelope(302024) and history absence by checkVersion data-null",
142
- stopAndRetain: "cascade-contradiction: stop, retain, and report; no form-level delete, no unpublish endpoint in scope; the ticket08 orphan backstop remains available",
143
- },
144
- absenceReadback: { method: "GET", endpoint: TICKET12_FORM_READBACK_ENDPOINT, expected: "non-success-envelope-recorded-errcode-302024" },
145
- historyAbsenceReadback: { method: "GET", endpoint: TICKET12_FORM_HISTORY_CHECK_VERSION_ENDPOINT, expected: "data-null-no-history" },
146
- ownership: "schema-sheet-and-field-bound-to-testRunId",
147
- replayPolicy: "absent-is-no-op",
148
- uncertainPolicy: "stop-retain-report-no-retry",
149
- });
150
- }
151
- /** Deterministic, run-independent contract identities pinned by the Knowledge Pack promotion. */
152
- export function ticket12FormPublishContractHash() { return digest(ticket12FormPublishContract()); }
153
- export function ticket12FormCleanupContractHash() { return digest(ticket12FormCleanupContractTemplate()); }
154
- function ticket12FormPublishContract() {
155
- return {
156
- capabilityId: TICKET12_FORM_PUBLISH_CAPABILITY_ID,
157
- operationKind: "form-publish",
158
- method: "POST",
159
- endpoint: CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH.endpoint,
160
- readbackEndpoint: CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH.readbackEndpoint,
161
- historyEndpoints: [...CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH.historyEndpoints],
162
- preflight: CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH.preflight,
163
- dto: "BizSheetVO:echoed-bizsheet-get-with-draft-sides-promoted-to-published;existDraft:false;sendMessage:false;publishRemarks-optional",
164
- controlBinding: "control-key===published-field-code",
165
- controlType: 1,
166
- bindingConstraint: "every-data-bound-control-key-must-resolve-in-the-published-schema-store(BizFormServiceImpl.java:544-582)",
167
- postPublishReadback: "published:true;existDraft:false;publishedViewJson/publishedAttributesJson-carry-the-configured-layout",
168
- lagResolution: "publishBizSchema-plus-deleteFormCache-inside-the-publish-call-discharge-the-form-consistency-lag-recorded-on-the-field-rungs",
169
- historySurface: "history/list-decodes-empty-by-design-for-design-time-publish(version-int-zero-entries;entries-only-from-app-package-import/export);checkVersion-decodes-newest-version-or-data-null",
170
- auditSurface: "server-side LogOperationActionType.EDIT_AND_PUBLISH_FORM with before/after data (BizFormController.java:902-908); no separate audit read API is evidenced",
171
- successEnvelope: "errcode-0-940114-data-new-version-int",
172
- scope: "model-scoped-form-publication-only-never-app-publish-never-environment-release",
173
- permission: "@RequireAdmin",
174
- transportMode: "serialized-server-form-publish-8.6.26",
175
- capability: CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH,
176
- evidence: [...CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH.evidence],
177
- requiredPermissions: ["configuration-write"],
178
- prohibited: [...TICKET12_PROHIBITED_MUTATION_TERMS],
179
- };
180
- }
181
- function ticket12FormCleanupContractTemplate() {
182
- return {
183
- capabilityId: TICKET12_FORM_CLEANUP_CAPABILITY_ID,
184
- operationKind: "published-form-cascade-absence-confirmation",
185
- formDeleteEndpointRefusal: "bizsheet/delete-refuses-default-forms;never-the-cleanup-path",
186
- variants: ["model-physical-delete-cascades-published-forms", "cascade-contradiction-stop-retain-report"],
187
- absenceReadback: `${TICKET12_FORM_READBACK_ENDPOINT}:non-success-envelope-recorded-errcode-302024`,
188
- historyAbsenceReadback: `${TICKET12_FORM_HISTORY_CHECK_VERSION_ENDPOINT}:data-null-no-history`,
189
- ownership: "schema-sheet-and-field-bound-to-testRunId",
190
- replayPolicy: "absent-is-no-op",
191
- uncertainPolicy: "stop-retain-report-no-retry",
192
- };
193
- }
194
- /** Package operations must be exactly one bounded default-form publish step for the bound target. */
195
- export function assertTicket12OperationsBounded(input) {
196
- if (input.operations.length !== 1)
197
- throw new Error("Ticket 12 packages must contain exactly one bounded operation.");
198
- const operation = input.operations[0];
199
- const identity = `${operation.id} ${operation.target} ${operation.path}`.toLowerCase();
200
- if (TICKET12_PROHIBITED_MUTATION_TERMS.some((term) => identity.includes(term)) || !operation.id.startsWith("form-publish:"))
201
- throw new Error(`Ticket 12 operation ${operation.id} is outside the bounded operation set; prohibited families (app publish, deployment, restart, release, redis, tenant administration, runtime CRUD, Portal-facing operations, model/view/folder writes) remain rejected.`);
202
- const expected = { id: `form-publish:${input.targetSchemaCode}/${input.targetSheetCode}/${input.targetFieldCodes.join("+")}`, target: `form:${input.targetSchemaCode}/${input.targetSheetCode}`, path: TICKET12_FORM_PUBLISH_ENDPOINT, transportMode: "serialized-server-form-publish-8.6.26" };
203
- if (operation.id !== expected.id || operation.path !== expected.path || operation.transportMode !== expected.transportMode || operation.target !== expected.target)
204
- throw new Error(`Ticket 12 operation ${operation.id} does not match the exact target binding for ${expected.target}.`);
205
- }
206
- /** Builds the signed, version-bound pack promoting exactly the single test form-publish capability. */
207
- export function buildTicket12FormPublishKnowledgePack(input) {
208
- const compiler = { id: "src/ticket12-test-form-publish.ts:createTicket12FormPublishPlanApproval", sha256: digest("omc-ticket12-compiler-v1") };
209
- const decoder = { id: "src/dsh-host-plugin.ts:createCloudPivotWriteTransport", sha256: digest("omc-ticket12-decoder-v1") };
210
- return buildKnowledgePack({
211
- packId: TICKET12_FORM_PUBLISH_KNOWLEDGE_PACK_ID,
212
- packVersion: "1.0.0",
213
- sourceVersion: TICKET12_REFERENCE_EVIDENCE_VERSION,
214
- sourceArtifacts: [{ id: "cloudpivot-8.6.26-serialized-form-publish-capability", sha256: digest(CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH) }],
215
- references: [
216
- { id: "omc-form-schema-contract-research", sha256: digest("omc-form-schema-contract-research") },
217
- { id: TICKET12_FORM_PUBLISH_ENDPOINT, sha256: digest(TICKET12_FORM_PUBLISH_ENDPOINT) },
218
- { id: TICKET12_FORM_READBACK_ENDPOINT, sha256: digest(TICKET12_FORM_READBACK_ENDPOINT) },
219
- { id: TICKET12_FORM_HISTORY_LIST_ENDPOINT, sha256: digest(TICKET12_FORM_HISTORY_LIST_ENDPOINT) },
220
- ],
221
- compilers: [compiler],
222
- decoders: [decoder],
223
- capabilities: [{
224
- id: TICKET12_FORM_PUBLISH_CAPABILITY_ID,
225
- status: "runtime-verified",
226
- promote: true,
227
- compilerRef: compiler.id,
228
- decoderRef: decoder.id,
229
- sourceEvidence: [...CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH.evidence, TICKET12_FORM_PUBLISH_ENDPOINT, TICKET12_FORM_READBACK_ENDPOINT, TICKET12_FORM_HISTORY_LIST_ENDPOINT, TICKET12_FORM_HISTORY_CHECK_VERSION_ENDPOINT],
230
- runtimeEvidence: ["omc-form-schema-contract-research", "cloudpivot.form-publish.serialized-server-8.6.26"],
231
- operationPromotions: [{
232
- id: "form-publish",
233
- status: "promoted",
234
- operationContractHash: ticket12FormPublishContractHash(),
235
- sourceRefs: [...CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH.evidence, TICKET12_FORM_PUBLISH_ENDPOINT, TICKET12_FORM_READBACK_ENDPOINT, TICKET12_FORM_HISTORY_LIST_ENDPOINT],
236
- versionFamily: "8.6",
237
- referenceVersion: TICKET12_REFERENCE_EVIDENCE_VERSION,
238
- requiredEvidence: ["cleanup", "discovery", "permission", "readback", "test", "write"],
239
- evidence: ["cleanup", "discovery", "permission", "readback", "test", "write"],
240
- blockedReasons: [],
241
- }],
242
- }],
243
- signerKeyId: input.signerKeyId,
244
- signingKey: input.signingKey,
245
- createdAt: input.createdAt,
246
- });
247
- }
248
- /** Loads the pack against CloudPivot 8.6.26 and pins the single executable capability and contract hash. */
249
- export function loadTicket12KnowledgePack(artifact, trustedKeys) {
250
- const runtime = new KnowledgePackRuntime(trustedKeys);
251
- const load = runtime.load(artifact, TICKET12_REFERENCE_EVIDENCE_VERSION);
252
- if (!load.accepted)
253
- throw new Error(`Ticket 12 Knowledge Pack is not authoritative: ${load.blockingReasons.join(", ")}.`);
254
- const active = runtime.active();
255
- const capabilities = active.capabilities;
256
- if (capabilities.length !== 1 || capabilities[0].id !== TICKET12_FORM_PUBLISH_CAPABILITY_ID)
257
- throw new Error("Ticket 12 Knowledge Pack must promote exactly the single test form-publish capability; evidence inference from the form-draft rung or to any other capability (app publish included) is rejected.");
258
- const hashes = capabilities[0].operationContractHashes;
259
- if (hashes.length !== 1 || hashes[0] !== ticket12FormPublishContractHash())
260
- throw new Error("Ticket 12 Knowledge Pack operation contract hash does not match the canonical form-publish contract.");
261
- return { runtime, packId: active.manifest.packId, contentDigest: active.manifest.contentSha256, executableCapabilities: capabilities.map(({ id }) => id) };
262
- }
263
- /**
264
- * Decodes the authoritative publish-history surface: the history/list page
265
- * (version DESC) plus the checkVersion newest version. "present" requires a
266
- * decodable list entry bound to the queried schema/sheet; "absent" means the
267
- * surface decoded but carries no entry and checkVersion returns data null.
268
- */
269
- export function decodeTicket12FormHistoryEvidence(input) {
270
- const query = { schemaCode: input.schemaCode, sheetCode: input.sheetCode };
271
- const listStatus = input.listHttpStatus ?? 200;
272
- const checkStatus = input.checkVersionHttpStatus ?? 200;
273
- const listEnvelope = input.listBody;
274
- const checkEnvelope = input.checkVersionBody;
275
- if (!listEnvelope || typeof listEnvelope !== "object" || Array.isArray(listEnvelope) || !checkEnvelope || typeof checkEnvelope !== "object" || Array.isArray(checkEnvelope))
276
- return Object.freeze({ classification: "blocked", reason: "malformed-response", query, newestVersion: null, entryCount: null });
277
- if (listStatus < 200 || listStatus >= 300 || checkStatus < 200 || checkStatus >= 300)
278
- return Object.freeze({ classification: "blocked", reason: "http-error", query, newestVersion: null, entryCount: null });
279
- if (listEnvelope.errcode !== 0 || checkEnvelope.errcode !== 0)
280
- return Object.freeze({ classification: "blocked", reason: "malformed-response", query, newestVersion: null, entryCount: null });
281
- const data = listEnvelope.data;
282
- const page = data && typeof data === "object" && !Array.isArray(data) ? data : undefined;
283
- const content = page && Array.isArray(page.content) ? page.content : undefined;
284
- if (!page || !content)
285
- return Object.freeze({ classification: "blocked", reason: "malformed-response", query, newestVersion: null, entryCount: null });
286
- const entries = content.filter((entry) => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry) && entry.schemaCode === input.schemaCode && (entry.code === input.sheetCode || entry.sheetCode === input.sheetCode));
287
- const checkVersionData = checkEnvelope.data;
288
- const newestFromCheck = typeof checkVersionData === "number" && Number.isInteger(checkVersionData) && checkVersionData > 0 ? checkVersionData : null;
289
- if (!entries.length) {
290
- if (checkVersionData === null || checkVersionData === undefined)
291
- return Object.freeze({ classification: "absent", reason: "no-history", query, newestVersion: null, entryCount: 0 });
292
- if (newestFromCheck === null)
293
- return Object.freeze({ classification: "blocked", reason: "malformed-response", query, newestVersion: null, entryCount: 0 });
294
- if (content.length > 0)
295
- return Object.freeze({ classification: "blocked", reason: "malformed-response", query, newestVersion: newestFromCheck, entryCount: 0 });
296
- // Pinned live 2026-09-04: a design-time model-scoped publication decodes as
297
- // a live version int with ZERO history/list entries. The engine has no
298
- // API-side write into the bizsheet history table (BizFormHistoryController
299
- // is read-only; the publish flow writes the EDIT_AND_PUBLISH_FORM system
300
- // operation log instead), history rows only enter through app-package
301
- // import/export flows, and the team's manually published agent_test_customer
302
- // also carries zero entries. An empty list plus a live version is the
303
- // authoritative post-publish history shape for this publish class.
304
- return Object.freeze({ classification: "present", reason: "design-time-no-entries", query, newestVersion: newestFromCheck, entryCount: 0 });
305
- }
306
- // The decompiled history surface sorts version DESC; any other order (or a
307
- // checkVersion disagreement with the decoded newest entry) is a malformed
308
- // response, never a falsely bound publication version.
309
- const versions = entries.map((entry) => (typeof entry.version === "number" && Number.isInteger(entry.version) && entry.version > 0 ? entry.version : null));
310
- if (versions.some((version) => version === null))
311
- return Object.freeze({ classification: "blocked", reason: "malformed-response", query, newestVersion: newestFromCheck, entryCount: entries.length });
312
- const ordered = versions.every((version, index) => index === 0 || versions[index - 1] > version);
313
- if (!ordered)
314
- return Object.freeze({ classification: "blocked", reason: "malformed-response", query, newestVersion: newestFromCheck, entryCount: entries.length });
315
- const version = versions[0];
316
- if (newestFromCheck !== null && newestFromCheck !== version)
317
- return Object.freeze({ classification: "blocked", reason: "malformed-response", query, newestVersion: newestFromCheck, entryCount: entries.length });
318
- const first = entries[0];
319
- return Object.freeze({
320
- classification: "present",
321
- reason: "history-decoded",
322
- query,
323
- newestVersion: version,
324
- entryCount: entries.length,
325
- newestEntry: {
326
- version,
327
- publishRemarks: typeof first.publishRemarks === "string" ? first.publishRemarks : typeof first.remarks === "string" ? first.remarks : null,
328
- createdName: typeof first.createdName === "string" ? first.createdName : null,
329
- },
330
- });
331
- }
332
- export function decodeTicket12TreesObservation(input) {
333
- const httpStatus = input.httpStatus ?? 200;
334
- const envelope = input.body;
335
- if (httpStatus < 200 || httpStatus >= 300 || !envelope || typeof envelope !== "object" || Array.isArray(envelope) || envelope.errcode !== 0 || !Array.isArray(envelope.data))
336
- return Object.freeze({ classification: "unavailable", appCode: input.appCode, schemaCode: input.schemaCode, schemaPresent: null, note: "read-only-observation-only-no-portal-facing-mutation;a-model-scoped-form-publication-is-not-an-app-publish" });
337
- const seen = [];
338
- const walk = (nodes) => nodes.some((node) => {
339
- if (!node || typeof node !== "object" || Array.isArray(node))
340
- return false;
341
- const record = node;
342
- const code = typeof record.code === "string" ? record.code : typeof record.schemaCode === "string" ? record.schemaCode : null;
343
- if (code === input.schemaCode)
344
- return true;
345
- if (code)
346
- seen.push(code);
347
- return Array.isArray(record.children) ? walk(record.children) : false;
348
- });
349
- const schemaPresent = walk(envelope.data);
350
- return Object.freeze({ classification: "observed", appCode: input.appCode, schemaCode: input.schemaCode, schemaPresent, note: "read-only-observation-only-no-portal-facing-mutation;a-model-scoped-form-publication-is-not-an-app-publish" });
351
- }
352
- /** Host-owned composite-chain evidence capture: consumes the completed form-draft + data-rule handoffs and proves the draft-configured, rule-bound, unpublished form pre-state. */
353
- export function captureTicket12FormPublishEvidence(input) {
354
- assertTicket12TestFormPublishEnvironment(input.settings);
355
- if (!TICKET12_UUID_V4.test(input.testRunId))
356
- throw new Error("Ticket 12 evidence capture requires the run's host-owned UUID v4 testRunId.");
357
- const handoff = input.handoff;
358
- const report = handoff.formDraftExecutionReport;
359
- const draftEvidence = handoff.formDraftEvidence;
360
- const ruleReport = handoff.dataRuleExecutionReport;
361
- const ruleEvidence = handoff.dataRuleEvidence;
362
- if (!handoff.formDraftPackageId || !SHA256.test(handoff.formDraftPackageHash) || !/[1-9a-f]/i.test(handoff.formDraftPackageHash) || report.route !== TICKET11_FORM_DRAFT_ROUTE || report.status !== "completed" || report.mutationExecuted !== true || report.behavior?.status !== "validated")
363
- throw new Error("Ticket 12 form publish requires the completed, behavior-validated form-draft handoff; serial writes never assume state.");
364
- if (!handoff.dataRulePackageId || !SHA256.test(handoff.dataRulePackageHash) || !/[1-9a-f]/i.test(handoff.dataRulePackageHash) || ruleReport.route !== TICKET20_DATA_RULE_ROUTE || ruleReport.status !== "completed" || ruleReport.mutationExecuted !== true || ruleReport.behavior?.status !== "validated")
365
- throw new Error("Ticket 12 form publish requires the completed, behavior-validated Ticket 20 data-rule handoff (issue 02a: the designer-native rule surface precedes the publication); serial writes never assume state.");
366
- if (report.testRunId !== input.testRunId || draftEvidence.testRunId !== input.testRunId || ruleReport.testRunId !== input.testRunId || ruleEvidence.testRunId !== input.testRunId)
367
- throw new Error("Ticket 12 composite chain requires the single run testRunId across the model, field, publish, form-draft, data-rule, and form-publish packages.");
368
- const targetSchemaCode = draftEvidence.targetSchemaCode;
369
- const targetFieldCodes = draftEvidence.targetFieldCodes;
370
- const targetSheetCode = draftEvidence.targetSheetCode;
371
- if (!isTicket08TargetSchema(targetSchemaCode) || report.targetSchemaCode !== targetSchemaCode || report.targetSheetCode !== targetSheetCode || report.targetFieldCodes.length !== targetFieldCodes.length || report.targetFieldCodes.some((fieldCode, index) => fieldCode !== targetFieldCodes[index]))
372
- throw new Error("Ticket 12 fixture family identity diverges from the completed form-draft handoff.");
373
- if (ruleEvidence.targetSchemaCode !== targetSchemaCode || ruleEvidence.targetFieldCodes.join("+") !== targetFieldCodes.join("+") || ruleEvidence.targetFieldCode !== ticket12RuleDemoFieldCode(targetFieldCodes))
374
- throw new Error("Ticket 12 fixture identity diverges from the completed Ticket 20 data-rule handoff; the publish consumes the same rule-bound family.");
375
- const modelPresence = input.modelPresence;
376
- if (modelPresence.classification !== "present" || modelPresence.query.schemaCode !== targetSchemaCode)
377
- throw new Error("Ticket 12 form publish requires the fixture model to be present in fresh authoritative readback.");
378
- targetFieldCodes.forEach((targetFieldCode, index) => {
379
- const member = TICKET09_FIELD_FAMILY[index];
380
- const publishedFieldPresence = input.publishedFieldPresence[index];
381
- if (publishedFieldPresence.classification !== "present" || publishedFieldPresence.reason !== "exact-presence" || publishedFieldPresence.query.schemaCode !== targetSchemaCode || publishedFieldPresence.query.propertyCode !== targetFieldCode || publishedFieldPresence.query.isPublish !== "true")
382
- throw new Error(`Ticket 12 evidence capture requires exact authenticated published-state presence for the ${member.propertyTypeName} handoff field; the publish ceiling only ever consumes published configuration.`);
383
- if (!publishedFieldPresence.field || publishedFieldPresence.field.code !== targetFieldCode || publishedFieldPresence.field.schemaCode !== targetSchemaCode || publishedFieldPresence.field.published !== true)
384
- throw new Error(`Ticket 12 evidence capture requires the ${member.propertyTypeName} field's published flag to decode from the authoritative published readback.`);
385
- });
386
- const formDraftState = input.formDraftState;
387
- if (formDraftState.classification !== "present" || formDraftState.reason !== "exact-presence" || formDraftState.query.schemaCode !== targetSchemaCode || formDraftState.query.sheetCode !== targetSheetCode || !formDraftState.form)
388
- throw new Error("Ticket 12 evidence capture requires the default form to be present in fresh authoritative readback.");
389
- if (formDraftState.form.published !== false || formDraftState.form.publishedViewJson !== null || formDraftState.form.publishedAttributesJson !== null || formDraftState.form.publishedActionsJson !== null || formDraftState.form.publishedHtmlJson !== null)
390
- throw new Error("Ticket 12 evidence capture requires the fixture form to be unpublished (published=false, every published JSON side null); the publish rung starts exactly from the draft-configured state.");
391
- if (formDraftState.form.existDraft !== true)
392
- throw new Error("Ticket 12 evidence capture requires existDraft=true on the draft-configured fixture form.");
393
- const formDraft = formDraftState.form;
394
- targetFieldCodes.forEach((targetFieldCode, index) => {
395
- const member = TICKET09_FIELD_FAMILY[index];
396
- const presence = decodeTicket11DraftControlPresence(formDraft, targetFieldCode);
397
- if (!presence.decodable)
398
- throw new Error("Ticket 12 evidence capture could not decode the form draft JSON; nothing ships on guessed schema JSON.");
399
- if (presence.layoutOccurrences !== 1 || !presence.control || presence.control.type !== member.controlType)
400
- throw new Error(`Ticket 12 evidence capture requires the ${member.propertyTypeName} handoff field's typed control to be bound exactly once in the draft layout; the publish consumes the completed form-draft configuration.`);
401
- });
402
- // Issue 02a: the publication consumes the designer-native rule surface
403
- // too — the required-rule row bound to the TIME field must decode from
404
- // the authoritative rule list before the form publishes (the panel
405
- // hydrates required from this row, never from control options strings).
406
- const requiredRuleState = input.requiredRuleState;
407
- if (requiredRuleState.classification !== "present" || requiredRuleState.query.schemaCode !== targetSchemaCode || requiredRuleState.query.dataRuleType !== 4)
408
- throw new Error("Ticket 12 evidence capture requires the authoritative required-rule (dataRuleType=4) list readback to decode.");
409
- const boundRequiredRow = requiredRuleState.rows.find((row) => decodeRequiredDataRuleRow(row, targetSchemaCode, ticket12RuleDemoFieldCode(targetFieldCodes)) !== undefined);
410
- if (!boundRequiredRow)
411
- throw new Error(`Ticket 12 evidence capture requires the completed Ticket 20 required-rule row bound to the ${ticket12RuleDemoMemberName()} field to decode from the authoritative rule list; the publish never ships without its designer-native required semantics.`);
412
- const authoritativeOrigin = input.discovery.authoritativeOrigin;
413
- const enterpriseId = input.discovery.enterpriseId;
414
- if (!authoritativeOrigin || !enterpriseId)
415
- throw new Error("Ticket 12 evidence capture requires authenticated environment fingerprint evidence.");
416
- const environmentFingerprint = canonicalCloudPivotEnvironmentFingerprint({ environment: TICKET12_TEST_ENVIRONMENT_NAME, authoritativeOrigin, applicationCode: TICKET12_TEST_APPLICATION_CODE, enterpriseId });
417
- if (environmentFingerprint !== draftEvidence.environmentFingerprint)
418
- throw new Error("Ticket 12 form publish is outside the form-draft handoff environment fingerprint.");
419
- const evidence = Object.freeze({
420
- route: TICKET12_FORM_PUBLISH_ROUTE,
421
- capabilityId: TICKET12_FORM_PUBLISH_CAPABILITY_ID,
422
- environmentName: TICKET12_TEST_ENVIRONMENT_NAME,
423
- applicationCode: TICKET12_TEST_APPLICATION_CODE,
424
- folder: draftEvidence.folder,
425
- targetSchemaCode,
426
- targetSheetCode,
427
- targetFieldCodes,
428
- testRunId: input.testRunId,
429
- environmentFingerprint,
430
- baselineFingerprint: canonicalCloudPivotBaselineFingerprint({ environmentFingerprint, applicationCode: TICKET12_TEST_APPLICATION_CODE, discovery: input.discovery }),
431
- discoveryFingerprint: canonicalFormalDiscoveryFingerprint(input.discovery),
432
- handoff,
433
- modelPresence,
434
- publishedFieldPresence: Object.freeze([...input.publishedFieldPresence]),
435
- formDraftState,
436
- requiredRuleState,
437
- publishRemarks: TICKET12_PUBLISH_REMARKS,
438
- cleanupContract: buildTicket12FormCleanupContract(input.testRunId, targetSchemaCode, targetSheetCode, targetFieldCodes),
439
- designerDirectUrl: ticket12DesignerDirectUrl(targetSchemaCode, targetSheetCode),
440
- capturedAt: new Date((input.now ?? Date.now)()).toISOString(),
441
- });
442
- if ([evidence.environmentFingerprint, evidence.baselineFingerprint, evidence.discoveryFingerprint].some((value) => !SHA256.test(value)))
443
- throw new Error("Ticket 12 evidence fingerprints are not canonical.");
444
- if (SENSITIVE_SECRET_VALUE.test(stable(evidence)))
445
- throw new Error("Ticket 12 evidence contains prohibited sensitive data.");
446
- return evidence;
447
- }
448
- export const TICKET12_EVIDENCE_DEFAULT_TTL_MS = 25 * 60_000;
449
- export const TICKET12_EVIDENCE_MAX_TTL_MS = 30 * 60_000;
450
- /** Single-use, TTL-bounded evidence store; consumed exactly once by plan creation. */
451
- export class Ticket12EvidenceStore {
452
- records = new Map();
453
- now;
454
- ttlMs;
455
- lastNow;
456
- constructor(options = {}) {
457
- this.now = options.now ?? Date.now;
458
- this.ttlMs = options.ttlMs ?? TICKET12_EVIDENCE_DEFAULT_TTL_MS;
459
- if (!Number.isFinite(this.ttlMs) || this.ttlMs < 1 || this.ttlMs > TICKET12_EVIDENCE_MAX_TTL_MS)
460
- throw new Error("Ticket 12 evidence TTL must be between 1ms and its safety maximum.");
461
- }
462
- capture(evidence) {
463
- validateTicket12Evidence(evidence);
464
- const evidenceId = `ticket12-evidence-${randomUUID()}`;
465
- const expiresAt = this.readClock() + this.ttlMs;
466
- const stored = Object.freeze({ ...evidence, evidenceArtifactId: evidenceId });
467
- this.records.set(evidenceId, { evidence: stored, expiresAt, consumed: false });
468
- return { evidenceId, expiresAt, evidence: stored };
469
- }
470
- consume(evidenceId) {
471
- const record = this.records.get(evidenceId);
472
- if (!record)
473
- throw new Error("Ticket 12 evidence artifact is missing or divergent.");
474
- if (record.consumed)
475
- throw new Error("Ticket 12 evidence has already been consumed.");
476
- if (record.expiresAt <= this.readClock())
477
- throw new Error("Ticket 12 evidence is stale or expired.");
478
- record.consumed = true;
479
- return record.evidence;
480
- }
481
- resolve(evidenceId) {
482
- const record = this.records.get(evidenceId);
483
- if (!record || !record.consumed)
484
- throw new Error("Ticket 12 evidence artifact is missing or has not been consumed by planning.");
485
- if (record.expiresAt <= this.readClock())
486
- throw new Error("Ticket 12 evidence artifact is stale or expired.");
487
- return record.evidence;
488
- }
489
- readClock() {
490
- const currentTime = this.now();
491
- if (!Number.isFinite(currentTime))
492
- throw new Error("Ticket 12 evidence clock is invalid; fail closed.");
493
- if (this.lastNow !== undefined && currentTime < this.lastNow)
494
- throw new Error("Ticket 12 evidence clock moved backwards; fail closed.");
495
- this.lastNow = currentTime;
496
- return currentTime;
497
- }
498
- }
499
- /**
500
- * Composes the exact evidenced BizSheetVO publish DTO: the authoritative
501
- * pre-state form echoed with the draft JSON sides promoted to the published
502
- * members (the product's own pre-publish normalization,
503
- * AppIntegrationFacadeImpl.java:2725-2746), existDraft=false, sendMessage=
504
- * false, and the run's publishRemarks marker. No publish-only property
505
- * mutation member is set.
506
- */
507
- export function buildTicket12FormPublishPayload(evidence) {
508
- validateTicket12Evidence(evidence);
509
- const pre = evidence.formDraftState.form;
510
- evidence.targetFieldCodes.forEach((fieldCode, index) => {
511
- const member = TICKET09_FIELD_FAMILY[index];
512
- const control = decodeDraftControl(pre.draftViewJson, pre.draftAttributesJson, fieldCode);
513
- if (!control || control.type !== member.controlType)
514
- throw new Error(`Ticket 12 payload composition requires the bound ${member.propertyTypeName} draft control to decode before promotion.`);
515
- });
516
- return {
517
- ...pre,
518
- schemaCode: evidence.targetSchemaCode,
519
- code: evidence.targetSheetCode,
520
- name: pre.name,
521
- sheetType: pre.sheetType ?? 0,
522
- published: false,
523
- existDraft: false,
524
- sendMessage: false,
525
- publishRemarks: evidence.publishRemarks,
526
- publishedViewJson: pre.draftViewJson,
527
- publishedAttributesJson: pre.draftAttributesJson,
528
- // Every draft side is promoted verbatim (the decompiled normalization
529
- // promotes the non-empty draft members); a null draft member normalizes
530
- // to the canonical empty value the configured reference form carries.
531
- publishedActionsJson: pre.draftActionsJson ?? "[]",
532
- publishedHtmlJson: pre.draftHtmlJson ?? "{}",
533
- draftViewJson: pre.draftViewJson,
534
- draftAttributesJson: pre.draftAttributesJson,
535
- ...(pre.draftActionsJson !== null ? { draftActionsJson: pre.draftActionsJson } : {}),
536
- ...(pre.draftHtmlJson !== null ? { draftHtmlJson: pre.draftHtmlJson } : {}),
537
- };
538
- }
539
- export function buildTicket12ConfigurationIntent(evidence) {
540
- validateTicket12Evidence(evidence);
541
- const target = `${evidence.targetSchemaCode}/${evidence.targetSheetCode}`;
542
- return {
543
- intentVersion: 1,
544
- targetFamily: "8.6",
545
- environmentBinding: { application: evidence.applicationCode, model: evidence.targetSchemaCode, baselineFingerprint: evidence.baselineFingerprint },
546
- sourceRequirement: "Ticket 12 maintainer test: publish the composite fixture's draft-configured default form (model-scoped form publication only, never an app publish and never an Environment release), completing the structurally usable shape — model, published fields, published form — with authoritative readback, publish-history decode, and the stated cascade cleanup contract.",
547
- resources: [
548
- { id: target, kind: "form", state: "update", properties: { schemaCode: evidence.targetSchemaCode, sheetCode: evidence.targetSheetCode, boundFamilyFields: [...evidence.targetFieldCodes], modelScopedPublication: true, publishRemarks: evidence.publishRemarks } },
549
- ...evidence.targetFieldCodes.map((fieldCode) => ({ id: `${evidence.targetSchemaCode}/${fieldCode}`, kind: "field", state: "existing", properties: { schemaCode: evidence.targetSchemaCode, published: true } })),
550
- ],
551
- relationships: evidence.targetFieldCodes.map((fieldCode) => ({ from: target, to: `${evidence.targetSchemaCode}/${fieldCode}`, kind: "bindsTo" })),
552
- lifecycle: [{ resourceId: target, transitions: ["publish"], order: 1, idempotent: false, dependencyChecks: ["completed-form-draft-handoff", "draft-bound-control-and-unpublished-form-preflight"], recoveryBoundary: `form:${target}` }],
553
- behavior: [{ id: "form-publication", kind: "structure", requiredCapabilityIds: [TICKET12_FORM_PUBLISH_CAPABILITY_ID], resourceIds: [target], obligations: ["the published readback decodes published=true with the configured layout on the published JSON sides", "the form-consistency lag recorded on the field rungs is discharged by this explicit publication", "the publish history decodes a versioned entry bound to the sheet", "the usable shape (model, published fields, published form) is confirmed by authoritative readback", "the designer direct URL stays inspectable"] }],
554
- acceptance: [{ id: "ticket12-form-publish-readback", scenario: "model-scoped-form-publication-usable-shape", actor: "omc-maintainer-opencode", assertions: ["the authoritative form readback decodes the published state and the published control binding", "the publish history surface decodes the pinned design-time publish shape (version int with zero entries) or a versioned entry when import/export created one", "the model and the published field remain authoritative-readback present after the publication"], readbackInvariants: [`${TICKET12_FORM_READBACK_ENDPOINT}?schemaCode=<model>&sheetCode=<sheet> decodes published=true existDraft=false`, `${TICKET12_FORM_HISTORY_LIST_ENDPOINT} decodes the pinned design-time publish shape (zero entries) or a versioned entry for the sheet`], outcome: "validated" }],
555
- cleanup: [{ id: "ticket12-form-cascade-cleanup", boundary: `ticket12:${evidence.testRunId}:form-publish-cascade-absence`, dependencyChecks: ["staged published-field cleanup", "model physical delete", "form absence readback", "history absence readback"], resources: [`form:${target}`] }],
556
- implementationConstraints: { nativePreferred: true, backendRequired: false, prohibitedPaths: ["form.online-js", "business-rule", "integration", "backend.extension"], approvalExceptions: [] },
557
- evidenceRefs: [TICKET12_FORM_PUBLISH_CAPABILITY_ID, TICKET12_FORM_PUBLISH_ENDPOINT, TICKET12_FORM_READBACK_ENDPOINT, TICKET12_FORM_HISTORY_LIST_ENDPOINT, ...CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH.evidence],
558
- unresolved: [],
559
- };
560
- }
561
- function ticket12FormPublishOperation(evidence) {
562
- const target = `form:${evidence.targetSchemaCode}/${evidence.targetSheetCode}`;
563
- return {
564
- id: `form-publish:${evidence.targetSchemaCode}/${evidence.targetSheetCode}/${evidence.targetFieldCodes.join("+")}`,
565
- method: "POST",
566
- path: TICKET12_FORM_PUBLISH_ENDPOINT,
567
- target,
568
- payload: buildTicket12FormPublishPayload(evidence),
569
- expectedReadback: `${target}:published`,
570
- evidence: [TICKET12_FORM_PUBLISH_CAPABILITY_ID, ...CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH.evidence, TICKET12_FORM_READBACK_ENDPOINT],
571
- transportMode: "serialized-server-form-publish-8.6.26",
572
- capability: CLOUDPIVOT_8_6_26_SERIALIZED_FORM_PUBLISH,
573
- };
574
- }
575
- /** Creates and proposes the immutable Ticket 12 Delivery Plan Approval for the single default-form publish step. */
576
- export function createTicket12FormPublishPlanApproval(input) {
577
- const evidence = validateTicket12Evidence(input.evidence);
578
- assertDigest(input.knowledgePackDigest, "knowledge pack digest");
579
- const operation = ticket12FormPublishOperation(evidence);
580
- assertTicket12OperationsBounded({ route: TICKET12_FORM_PUBLISH_ROUTE, operations: [operation], targetSchemaCode: evidence.targetSchemaCode, targetSheetCode: evidence.targetSheetCode, targetFieldCodes: evidence.targetFieldCodes });
581
- const intent = buildTicket12ConfigurationIntent(evidence);
582
- if (validateConfigurationIntent(intent).length)
583
- throw new Error("Ticket 12 Configuration Intent is invalid; planning is blocked.");
584
- const binding = {
585
- deliveryId: ticket12DeliveryId(evidence.testRunId),
586
- environment: TICKET12_TEST_ENVIRONMENT_NAME,
587
- baselineFingerprint: evidence.baselineFingerprint,
588
- environmentFingerprint: evidence.environmentFingerprint,
589
- discoveryFingerprint: evidence.discoveryFingerprint,
590
- ...(evidence.evidenceArtifactId ? { evidenceArtifactId: evidence.evidenceArtifactId } : {}),
591
- };
592
- const planHash = digest({ route: TICKET12_FORM_PUBLISH_ROUTE, capabilityId: TICKET12_FORM_PUBLISH_CAPABILITY_ID, target: `${evidence.targetSchemaCode}/${evidence.targetSheetCode}/${evidence.targetFieldCodes.join("+")}`, testRunId: evidence.testRunId, operation: { id: operation.id, readback: operation.expectedReadback }, familyFieldCodes: [...evidence.targetFieldCodes], formDraftHandoff: { packageId: evidence.handoff.formDraftPackageId, packageHash: evidence.handoff.formDraftPackageHash }, folder: evidence.folder, fingerprints: { baseline: evidence.baselineFingerprint, environment: evidence.environmentFingerprint, discovery: evidence.discoveryFingerprint }, cleanupContractHash: ticket12FormCleanupContractHash(), knowledgePackDigest: input.knowledgePackDigest, prohibited: [...TICKET12_PROHIBITED_MUTATION_TERMS] });
593
- const base = createDeliveryPlanApproval({
594
- binding,
595
- requirementHash: digest({ target: `${evidence.targetSchemaCode}/${evidence.targetSheetCode}`, formPublish: true }),
596
- clarificationHash: digest("ticket12-test-form-publish"),
597
- intentHash: digest(intent),
598
- decisionHash: digest(TICKET12_FORM_PUBLISH_ROUTE),
599
- graphHash: digest([operation.id]),
600
- riskHash: digest(TICKET12_RISKS),
601
- validationPlanHash: digest("authoritative-published-form-readback-history-decode-lag-resolution-and-usable-shape-triple"),
602
- cleanupPlanHash: ticket12FormCleanupContractHash(),
603
- allowedOperationScope: [ticket12FormPublishScope(evidence.targetSchemaCode, evidence.targetSheetCode)],
604
- planHash,
605
- applicationCode: TICKET12_TEST_APPLICATION_CODE,
606
- folderId: evidence.folder.id,
607
- folderName: evidence.folder.name,
608
- targets: [`${evidence.targetSchemaCode}/${evidence.targetSheetCode}`],
609
- });
610
- const approval = {
611
- ...base,
612
- route: TICKET12_FORM_PUBLISH_ROUTE,
613
- testRunId: evidence.testRunId,
614
- targetSchemaCode: evidence.targetSchemaCode,
615
- targetSheetCode: evidence.targetSheetCode,
616
- targetFieldCodes: evidence.targetFieldCodes,
617
- capabilityId: TICKET12_FORM_PUBLISH_CAPABILITY_ID,
618
- knowledgePackDigest: input.knowledgePackDigest,
619
- cleanupContractHash: ticket12FormCleanupContractHash(),
620
- environmentName: TICKET12_TEST_ENVIRONMENT_NAME,
621
- };
622
- const proposal = { ...approval, approvalHash: deliveryPlanApprovalHash(approval) };
623
- proposeDeliveryPlan(input.ledger, proposal);
624
- return { approval: proposal, operation, cleanupContract: evidence.cleanupContract, intent, binding };
625
- }
626
- const TICKET12_RISKS = [
627
- "Exactly one model-scoped default-form publication of the run's own composite fixture is in scope — model-scoped form publication only, never an app publish and never an Environment release; app publish, deployment, restart, release, Redis, tenant administration, Portal-facing operations, and runtime CRUD remain permanently rejected.",
628
- "The published form's cleanup follows the two-variant contract: the staged model physical delete cascades published forms with no published-state branch (decompile-evidenced), absence confirmed by the 302024 envelope and history absence; any cascade contradiction stops, retains, and reports — the form-level /delete refuses default forms by design and is never attempted.",
629
- ];
630
- /** Compiles the immutable one-step form-publish package bound to the approved plan, pack digest, and pinned contract hash. */
631
- export function prepareTicket12FormPublishPackage(input) {
632
- const evidence = validateTicket12Evidence(input.evidence);
633
- const approval = requireTicket12Approval(input.approval);
634
- const persisted = requirePersistedApprovedPlan(input.ledger, approval);
635
- assertTicket12BindingMatchesEvidence(persisted.binding, evidence);
636
- const scope = ticket12FormPublishScope(evidence.targetSchemaCode, evidence.targetSheetCode);
637
- if (!persisted.allowedOperationScope.includes(scope))
638
- throw new Error(`Ticket 12 package step is outside the approved operation scope: ${scope}.`);
639
- if (input.pinnedFormPublishContractHash !== ticket12FormPublishContractHash())
640
- throw new Error("Ticket 12 pinned form-publish contract hash does not match the canonical 8.6.26 capability contract.");
641
- assertDigest(input.knowledgePackDigest, "knowledge pack digest");
642
- if (input.knowledgePackDigest !== approval.knowledgePackDigest)
643
- throw new Error("Ticket 12 knowledge pack digest diverges from the approved plan binding.");
644
- const operation = ticket12FormPublishOperation(evidence);
645
- assertTicket12OperationsBounded({ route: TICKET12_FORM_PUBLISH_ROUTE, operations: [operation], targetSchemaCode: evidence.targetSchemaCode, targetSheetCode: evidence.targetSheetCode, targetFieldCodes: evidence.targetFieldCodes });
646
- const snapshotBase = { id: `snapshot:${operation.id}`, target: operation.target, identity: operation.target, recoveryBoundary: operation.target, state: "absent", baselineFingerprint: persisted.binding.baselineFingerprint };
647
- const snapshot = { ...snapshotBase, snapshotHash: digest(snapshotBase) };
648
- const pkg = compileNativeOperations({
649
- operations: [operation],
650
- binding: persisted.binding,
651
- planApproval: persisted,
652
- snapshotManifest: [snapshot],
653
- releasePlanHash: digest("ticket12-no-release"),
654
- recoveryPolicyHash: digest("ticket12-form-publish-step-only"),
655
- knowledgePack: { id: TICKET12_FORM_PUBLISH_KNOWLEDGE_PACK_ID, digest: input.knowledgePackDigest },
656
- capabilityEvidence: [TICKET12_FORM_PUBLISH_CAPABILITY_ID, "cloudpivot.form-publish.serialized-server-8.6.26", TICKET12_FORM_READBACK_ENDPOINT, `formDraftHandoff:${evidence.handoff.formDraftPackageId}`, `folder:${evidence.folder.id}`, `testRunId:${evidence.testRunId}`, `baselineFingerprint:${persisted.binding.baselineFingerprint}`],
657
- requiredPermissions: ["configuration-write"],
658
- packageId: `ticket12-form-publish-${digest(persisted.approvalId).slice(0, 32)}`,
659
- ledger: input.ledger,
660
- });
661
- input.ledger.createPackage(pkg);
662
- return { package: pkg, operations: [operation], planApproval: persisted, dryRun: ticket12DryRun(evidence, [operation]), evidence };
663
- }
664
- /** Read-only dry-run projection; never a CloudPivot write and never an app publish or Environment release operation. */
665
- function ticket12DryRun(evidence, operations) {
666
- const readbackOperations = [
667
- { id: `readback:form:${evidence.targetSchemaCode}:${evidence.targetSheetCode}`, method: "GET", path: TICKET12_FORM_READBACK_ENDPOINT, target: `form:${evidence.targetSchemaCode}/${evidence.targetSheetCode}`, payload: { schemaCode: evidence.targetSchemaCode, sheetCode: evidence.targetSheetCode }, expectedReadback: `form:${evidence.targetSchemaCode}/${evidence.targetSheetCode}:read`, evidence: ["BizFormController.java:174-230"] },
668
- { id: `readback:form-history:${evidence.targetSchemaCode}:${evidence.targetSheetCode}`, method: "GET", path: TICKET12_FORM_HISTORY_CHECK_VERSION_ENDPOINT, target: `form-history:${evidence.targetSchemaCode}/${evidence.targetSheetCode}`, payload: { schemaCode: evidence.targetSchemaCode, sheetCode: evidence.targetSheetCode }, expectedReadback: `form-history:${evidence.targetSchemaCode}/${evidence.targetSheetCode}:read`, evidence: ["BizFormHistoryController.java:143-167"] },
669
- { id: `observation:trees:${TICKET12_TEST_APPLICATION_CODE}`, method: "GET", path: TICKET12_TREES_OBSERVATION_ENDPOINT, target: `application:${TICKET12_TEST_APPLICATION_CODE}`, payload: { appCode: TICKET12_TEST_APPLICATION_CODE }, expectedReadback: `trees:${TICKET12_TEST_APPLICATION_CODE}:read-only-observation`, evidence: ["read-only publish-gated menu projection; never a Portal-facing mutation"] },
670
- ];
671
- const body = JSON.stringify({ execution: "read-only-dry-run", operations, readbackOperations, blocked: [], prohibitedActions: ["cloudpivot-write"] }, null, 2) + "\n";
672
- return { execution: "read-only-dry-run", operations, readbackOperations, blocked: [], prohibitedActions: ["cloudpivot-write"], artifact: { name: "cloudpivot-ticket12-form-publish-dry-run.json", body, sha256: digest(body), mimeType: "application/json" } };
673
- }
674
- export function formatTicket12DeliveryPlanApprovalFrame(approval) {
675
- const value = requireTicket12Approval(approval);
676
- return appendApprovalHumanBlock(`Approve Ticket 12 form publish Delivery Plan Approval ${value.approvalId} hash ${value.approvalHash}; plan hash ${value.planHash}; capability ${value.capabilityId}; environment test; application test; environment fingerprint ${value.binding.environmentFingerprint}; baseline fingerprint ${value.binding.baselineFingerprint}; folder ${value.folderId} (${value.folderName}); fixture model ${value.targetSchemaCode}; default sheet ${value.targetSheetCode}; bound published family fields ${value.targetFieldCodes.join(" + ")}; testRunId ${value.testRunId}; exact scope ${value.allowedOperationScope[0]}; one default-form publish step (POST ${TICKET12_FORM_PUBLISH_ENDPOINT} with the echoed BizSheetVO: the draft JSON sides promoted to the published members, existDraft=false, sendMessage=false) — model-scoped form publication only, never an app publish and never an Environment release — with authoritative readback, publish-history decode, lag-resolution proof, and the stated two-variant cascade cleanup contract.`, { capability: "ticket12-form-publish", kind: "delivery-plan", identities: [value.targetSchemaCode, value.targetSheetCode, ...value.targetFieldCodes], scope: [value.allowedOperationScope[0]] });
677
- }
678
- export function formatTicket12EnvironmentChangeApprovalFrame(input) {
679
- const value = requireTicket12Approval(input.approval);
680
- return appendApprovalHumanBlock(`Approve Ticket 12 form publish Environment Change Approval for package ${input.packageId} hash ${input.packageHash}; plan approval ${value.approvalId} hash ${value.approvalHash}; environment test; folder ${value.folderId} (${value.folderName}); fixture model ${value.targetSchemaCode}; default sheet ${value.targetSheetCode}; bound published family fields ${value.targetFieldCodes.join(" + ")}; testRunId ${value.testRunId}; exact scope ${value.allowedOperationScope[0]}; exactly one default-form publish step (model-scoped form publication only, never an app publish and never an Environment release) executed by the single Forge configuration writer lease with authoritative readback, publish-history decode, and the usable shape proven through authoritative readback.`, { capability: "ticket12-form-publish", kind: "environment-change", identities: [value.targetSchemaCode, value.targetSheetCode, ...value.targetFieldCodes], scope: [value.allowedOperationScope[0]] });
681
- }
682
- /**
683
- * Validates real publication behavior beyond HTTP 2xx: the published state
684
- * and control binding decode from the authoritative readback, the
685
- * field-rung-recorded form-consistency lag is discharged, the publish
686
- * history decodes, and the usable shape (model + published field + published
687
- * form) is confirmed through authoritative readback.
688
- */
689
- export function validateTicket12FormPublishBehavior(input) {
690
- const evidence = validateTicket12Evidence(input.evidence);
691
- const checks = [];
692
- const add = (id, ok, detail) => checks.push({ id, status: ok ? "validated" : "blocked", detail });
693
- const before = input.before;
694
- const beforeOk = before.classification === "present" && before.query.schemaCode === evidence.targetSchemaCode && before.query.sheetCode === evidence.targetSheetCode && Boolean(before.form) && before.form.published === false;
695
- add("pre-state-unpublished", beforeOk, beforeOk ? "the pre-publish authoritative form readback decoded the unpublished draft-configured default form." : "the pre-publish authoritative form readback did not decode the unpublished draft-configured default form.");
696
- const after = input.after;
697
- const afterOk = after.classification === "present" && after.query.schemaCode === evidence.targetSchemaCode && after.query.sheetCode === evidence.targetSheetCode && Boolean(after.form);
698
- add("published-state-decoded", afterOk && after.form.published === true, `the published flag decodes as ${String(after.form?.published)} from the authoritative post-publish readback.`);
699
- evidence.targetFieldCodes.forEach((fieldCode, fieldIndex) => {
700
- const member = TICKET09_FIELD_FAMILY[fieldIndex];
701
- // Ticket 03b: the per-type published-options decode contract (display
702
- // name, highlighted keys, pinned-key predicate) is the ACTIVE family's
703
- // registered member data.
704
- const registeredMember = fieldFamilyMembers()[fieldIndex];
705
- const suffix = member.propertyTypeName.toLowerCase();
706
- const publishedControl = afterOk ? decodePublishedControl(after.form.publishedViewJson, after.form.publishedAttributesJson, fieldCode) : undefined;
707
- const publishedBinding = afterOk && publishedControl?.key === fieldCode && publishedControl.type === member.controlType;
708
- add(`published-control-binding-${suffix}`, publishedBinding, publishedBinding ? `the published JSON sides carry the ${member.propertyTypeName} field's control exactly once with the ${registeredMember.control.controlDisplayName} binding.` : `the authoritative published readback did not decode the ${member.propertyTypeName} field's control on the published JSON sides after the publish returned success.`);
709
- const options = publishedControl?.options;
710
- // Issue 02a (type-matrix §9): the published options decode with visible
711
- // plus the always-readonly boolean (Date) — and WITHOUT any
712
- // requiredFormula/readonlyCondition condition strings; required lives on
713
- // the bizdatarule row, which the panel re-hydrates from.
714
- const noConditionStrings = options !== undefined && !("requiredFormula" in options) && !("readonlyCondition" in options) && !("displayFormula" in options);
715
- const optionsOk = registeredMember.publishedControlOptions.passes(options, noConditionStrings);
716
- add(`published-control-options-${suffix}`, optionsOk, `the published ${member.propertyTypeName} control options decode with the per-type pinned family keys (visible=${JSON.stringify(options?.visible)}${registeredMember.publishedControlOptions.highlightedKeys.map((key) => `, ${key}=${JSON.stringify(options?.[key])}`).join("")}) and WITHOUT any condition strings (requiredFormula/readonlyCondition absent — the designer-native rule row carries required).`);
717
- const draftControl = afterOk ? decodeDraftControl(after.form.draftViewJson, after.form.draftAttributesJson, fieldCode) : undefined;
718
- add(`draft-side-preserved-${suffix}`, Boolean(draftControl) && draftControl?.type === member.controlType, `the draft side still carries the configured ${member.propertyTypeName} control binding after the publication (the server writes draft*Json back unchanged).`);
719
- });
720
- add("exist-draft-consumed", after.form?.existDraft === false, `the existDraft flag decodes as ${String(after.form?.existDraft)} after the publication (the draft is consumed into the published side).`);
721
- const lagResolved = beforeOk && afterOk && before.form.published === false && after.form.published === true && after.form.publishedViewJson !== null && after.form.publishedAttributesJson !== null;
722
- add("form-consistency-lag-resolved", lagResolved, lagResolved ? "the form-consistency lag recorded on the Ticket 10 field rung is discharged by this rung's explicit model-scoped publication: the authoritative form readback no longer lags (published=true with the published JSON sides populated)." : "the authoritative form readback still lags the publication (published state or published JSON sides did not decode); the lag-resolution proof failed.");
723
- const history = input.history;
724
- const historyOk = history.classification === "present" && history.query.schemaCode === evidence.targetSchemaCode && history.query.sheetCode === evidence.targetSheetCode && history.newestVersion !== null && history.newestVersion >= 1;
725
- add("publish-history-decoded", historyOk, historyOk ? (history.entryCount === 0
726
- ? `the publish history surface decodes the pinned design-time shape: version ${history.newestVersion} with zero history/list entries (design-time model-scoped publication writes no bizsheet history rows; corroborated live by the manually published agent_test_customer also carrying zero entries).`
727
- : `the publish history decodes version ${history.newestVersion} (${history.entryCount} entr${history.entryCount === 1 ? "y" : "ies"}) with publishRemarks ${JSON.stringify(history.newestEntry?.publishRemarks)} by ${JSON.stringify(history.newestEntry?.createdName)}.`) : `the publish history surface did not decode for the fixture sheet (classification=${history.classification}).`);
728
- const remarksOk = historyOk && (history.entryCount === 0 || history.newestEntry?.publishRemarks === evidence.publishRemarks);
729
- add("publish-remarks-bound", remarksOk, historyOk && history.entryCount === 0
730
- ? "the pinned design-time publish shape carries no history entries, so no remarks exist to bind by design; this run's publication identity is bound by the immutable package, the dual approvals, and the testRunId chain instead."
731
- : remarksOk ? "the newest history entry carries this run's publishRemarks marker; the history is provably this run's publication." : `the newest history entry's remarks decode as ${JSON.stringify(history.newestEntry?.publishRemarks)} and do not bind this run's marker ${JSON.stringify(evidence.publishRemarks)}.`);
732
- const modelPresence = input.modelPresence;
733
- add("usable-shape-model", modelPresence.classification === "present" && modelPresence.query.schemaCode === evidence.targetSchemaCode, `the fixture model is ${modelPresence.classification} in the authoritative post-publish readback.`);
734
- input.publishedFieldPresence.forEach((publishedFieldPresence, fieldIndex) => {
735
- const member = TICKET09_FIELD_FAMILY[fieldIndex];
736
- add(`usable-shape-published-field-${member.propertyTypeName.toLowerCase()}`, publishedFieldPresence.classification === "present" && publishedFieldPresence.query.schemaCode === evidence.targetSchemaCode && publishedFieldPresence.query.propertyCode === evidence.targetFieldCodes[fieldIndex] && publishedFieldPresence.query.isPublish === "true" && publishedFieldPresence.field?.published === true, `the bound ${member.propertyTypeName} field remains present with the published flag decoded in the authoritative published-state readback.`);
737
- });
738
- const everyControlPublished = evidence.targetFieldCodes.every((_, fieldIndex) => checks.some((check) => check.id === `published-control-binding-${TICKET09_FIELD_FAMILY[fieldIndex].propertyTypeName.toLowerCase()}` && check.status === "validated"));
739
- add("usable-shape-published-form", everyControlPublished && after.form.published === true, "the structurally usable shape is complete: model, published family fields, and published form all confirmed through authoritative readback.");
740
- add("designer-direct-url", evidence.designerDirectUrl === ticket12DesignerDirectUrl(evidence.targetSchemaCode, evidence.targetSheetCode), `designer direct URL ${evidence.designerDirectUrl} stays inspectable.`);
741
- const observation = input.treesObservation;
742
- add("publish-gated-menu-observation", observation === undefined || observation.classification === "observed" || observation.classification === "unavailable", observation
743
- ? `read-only apppackage/trees observation recorded: schema ${observation.schemaCode} ${observation.schemaPresent === null ? "unavailable" : observation.schemaPresent ? "present" : "absent"} in the publish-gated menu projection; a model-scoped form publication is not an app publish and no Portal-facing mutation was performed.`
744
- : "the read-only publish-gated menu observation was not part of this validation.");
745
- const blocked = checks.find((check) => check.status === "blocked");
746
- return blocked ? { status: "blocked", reason: `Ticket 12 behavior validation failed: ${blocked.detail}`, checks } : { status: "validated", checks };
747
- }
748
- /** Execution boundary: named test environment, route-bound package steps, active approvals, no replay of terminal or uncertain packages. */
749
- export function assertTicket12ExecutionBoundary(input) {
750
- if (input.environmentName !== "test")
751
- throw new Error("Ticket 12 execution is restricted to the named test environment; production and staging are rejected.");
752
- const { projection } = input;
753
- if (input.steps.length !== 1 || !input.steps[0].id.startsWith("form-publish:"))
754
- throw new Error(`Ticket 12 execution boundary rejected package ${input.packageId}: its steps are not the single form-publish: operation bound to the ${input.route} route.`);
755
- if (projection.status === "approved" && projection.approvals.plan === "approved" && projection.approvals.environment === "approved")
756
- return;
757
- if (projection.status === "completed")
758
- throw new Error(`Ticket 12 package ${input.packageId} is already terminal completed; replay is rejected.`);
759
- if (projection.status === "uncertain")
760
- throw new Error(`Ticket 12 package ${input.packageId} is uncertain; reconcile by authoritative readback before any replay.`);
761
- if (projection.status === "in_progress")
762
- throw new Error(`Ticket 12 package ${input.packageId} is already running; concurrent execution is rejected.`);
763
- const pending = [...projection.blockers];
764
- if (projection.approvals.plan !== "approved")
765
- pending.push("Delivery Plan Approval is required before package execution.");
766
- if (projection.approvals.environment !== "approved")
767
- pending.push("Environment Change Approval is required before mutation.");
768
- throw new Error(`Ticket 12 execution boundary rejected package ${input.packageId}: status is ${projection.status} (blocked); ${[...new Set(pending)].join("; ")}.`);
769
- }
770
- /** Executes the approved one-step default-form publish package through the single OMC Host write transport, then validates the published behavior, history, lag resolution, and the usable shape. */
771
- export async function executeTicket12FormPublishPackage(input) {
772
- assertTicket12TestFormPublishEnvironment(input.settings);
773
- if (typeof input.transport.serializedServerFormPublish !== "function")
774
- throw new Error("Ticket 12 execution requires the OMC Host serialized form-publish transport; bypass transports are rejected.");
775
- const projection = input.ledger.project(input.prepared.package.packageId);
776
- assertTicket12ExecutionBoundary({ projection, environmentName: input.settings.environmentName, packageId: input.prepared.package.packageId, route: TICKET12_FORM_PUBLISH_ROUTE, steps: input.prepared.package.steps });
777
- if (input.environmentApproval.packageId !== input.prepared.package.packageId || input.environmentApproval.packageHash !== input.prepared.package.packageHash)
778
- throw new Error("Ticket 12 Environment Change Approval does not match the prepared package.");
779
- const evidence = input.prepared.evidence;
780
- const preflight = await input.readFormState();
781
- if (preflight.classification !== "present" || !preflight.form || preflight.form.published !== evidence.formDraftState.form.published || preflight.form.publishedViewJson !== evidence.formDraftState.form.publishedViewJson || preflight.form.publishedAttributesJson !== evidence.formDraftState.form.publishedAttributesJson || preflight.form.publishedActionsJson !== evidence.formDraftState.form.publishedActionsJson || preflight.form.publishedHtmlJson !== evidence.formDraftState.form.publishedHtmlJson)
782
- throw new Error(`Ticket 12 execution requires the form pre-state to match the approved evidence; ${input.prepared.package.steps[0].target} diverges from the approved handoff.`);
783
- for (const [fieldIndex, fieldCode] of evidence.targetFieldCodes.entries()) {
784
- const preflightPresence = decodeTicket11DraftControlPresence(preflight.form, fieldCode);
785
- if (!preflightPresence.decodable || preflightPresence.layoutOccurrences !== 1 || !preflightPresence.control || preflightPresence.control.type !== TICKET09_FIELD_FAMILY[fieldIndex].controlType)
786
- throw new Error(`Ticket 12 execution requires the draft control binding to match the approved evidence before the publish; ${fieldCode} is not the completed form-draft configuration.`);
787
- }
788
- const result = await runNativeConfigurationPackage({
789
- package: input.prepared.package,
790
- gate: {
791
- mode: "approved",
792
- planApproval: { status: "approved", approvalHash: input.prepared.planApproval.approvalHash },
793
- environmentApproval: { status: "approved", packageHash: input.environmentApproval.packageHash },
794
- lease: { owner: "configuration-agent", environment: TICKET12_TEST_ENVIRONMENT_NAME },
795
- baselineFingerprint: input.prepared.package.binding.baselineFingerprint,
796
- snapshots: input.prepared.package.snapshotManifest,
797
- package: input.prepared.package,
798
- },
799
- operations: input.prepared.operations,
800
- ledger: input.ledger,
801
- planApproval: input.prepared.planApproval,
802
- transport: input.transport,
803
- credentials: input.credentials,
804
- authoritativeOrigin: input.authoritativeOrigin,
805
- testApplicationCode: TICKET12_TEST_APPLICATION_CODE,
806
- }, input.signal);
807
- const mutationExecuted = result.steps.some((step) => step.status === "committed" || step.status === "uncertain");
808
- const blockers = [...result.blockers];
809
- let status = ticket12ExecutionStatus(result.status);
810
- let nextAction = result.nextAction;
811
- let behavior;
812
- let treesObservation;
813
- if (result.status === "completed") {
814
- treesObservation = input.readTreesObservation ? await input.readTreesObservation().catch(() => undefined) : undefined;
815
- behavior = validateTicket12FormPublishBehavior({
816
- evidence,
817
- before: preflight,
818
- after: await input.readFormState(),
819
- history: await input.readFormHistory(),
820
- modelPresence: await input.readModelEvidence(),
821
- publishedFieldPresence: await Promise.all(TICKET09_FIELD_FAMILY.map((member) => input.readPublishedFieldEvidence(member.propertyTypeName))),
822
- ...(treesObservation ? { treesObservation } : {}),
823
- });
824
- if (behavior.status !== "validated") {
825
- status = "blocked";
826
- blockers.push(behavior.reason ?? "Ticket 12 behavior validation failed.");
827
- nextAction = "reconcile-behavior-retain-and-report-resource";
828
- }
829
- }
830
- return { reportType: "omc.ticket12.test-form-publish-execution", schemaVersion: 1, packageId: result.packageId, packageHash: result.packageHash, route: TICKET12_FORM_PUBLISH_ROUTE, testRunId: evidence.testRunId, targetSchemaCode: evidence.targetSchemaCode, targetSheetCode: evidence.targetSheetCode, targetFieldCodes: evidence.targetFieldCodes, status, mutationExecuted, steps: result.steps, blockers, nextAction, ...(behavior ? { behavior } : {}), ...(treesObservation ? { treesObservation } : {}) };
831
- }
832
- /**
833
- * Closes the stated two-variant cascade cleanup contract: after the staged
834
- * cleanup (published-field cleanup, then the model physical delete), the
835
- * authoritative bizsheet/get readback must be the 302024 non-success envelope
836
- * for the fixture and the history checkVersion must decode data null. A form
837
- * still decoding after the cascade contradicts the decompiled contract —
838
- * variant B: stop, retain, and report.
839
- */
840
- export function confirmTicket12FormCascadeAbsence(input) {
841
- const evidence = validateTicket12Evidence(input.evidence);
842
- const readback = input.formReadback;
843
- if (readback.classification !== "absent" || readback.reason !== "form-absence" || readback.query.schemaCode !== evidence.targetSchemaCode || readback.query.sheetCode !== evidence.targetSheetCode)
844
- throw new Error(`Ticket 12 form cascade cleanup contract is not closed (variant B): the bizsheet/get readback does not confirm published-form absence after the model physical delete (classification=${readback.classification}, errcode=${String(readback.errcode ?? "n/a")}); stop, retain, and report.`);
845
- const history = input.historyReadback;
846
- if (history && (history.classification !== "absent" || history.query.schemaCode !== evidence.targetSchemaCode || history.query.sheetCode !== evidence.targetSheetCode))
847
- throw new Error(`Ticket 12 history cascade cleanup contract is not closed (variant B): the checkVersion readback does not confirm history absence after the model physical delete (classification=${history.classification}); stop, retain, and report.`);
848
- }
849
- function ticket12ExecutionStatus(status) {
850
- if (status === "completed" || status === "uncertain" || status === "partial")
851
- return status;
852
- return "blocked";
853
- }
854
- function requireTicket12Approval(approval) {
855
- const value = approval;
856
- if (value.route !== TICKET12_FORM_PUBLISH_ROUTE || value.capabilityId !== TICKET12_FORM_PUBLISH_CAPABILITY_ID || value.environmentName !== "test" || value.applicationCode !== "test" || value.targets?.length !== 1 || !value.folderId || !value.folderName || !value.testRunId || !value.targetSchemaCode || !value.targetSheetCode || !Array.isArray(value.targetFieldCodes) || value.targetFieldCodes.length !== TICKET09_FIELD_FAMILY.length || value.targetFieldCodes.some((code) => !isTicket09TargetField(code)) || new Set(value.targetFieldCodes).size !== TICKET09_FIELD_FAMILY.length)
857
- throw new Error(`Ticket 12 approval frame is not bound to the exact ${TICKET12_FORM_PUBLISH_ROUTE} route, family targets, folder, and testRunId.`);
858
- return value;
859
- }
860
- function requirePersistedApprovedPlan(ledger, approval) {
861
- if (approval.status !== "approved")
862
- throw new Error("Ticket 12 package preparation requires the approved exact Ticket 12 Delivery Plan Approval.");
863
- const persisted = ledger.findPlanApproval(approval.approvalId);
864
- if (!persisted || persisted.status !== "approved" || persisted.approvalHash !== approval.approvalHash)
865
- throw new Error("Ticket 12 package preparation requires the exact authoritative approved Delivery Plan Approval.");
866
- return persisted;
867
- }
868
- function assertTicket12BindingMatchesEvidence(binding, evidence) {
869
- const expected = {
870
- deliveryId: ticket12DeliveryId(evidence.testRunId),
871
- environment: TICKET12_TEST_ENVIRONMENT_NAME,
872
- baselineFingerprint: evidence.baselineFingerprint,
873
- environmentFingerprint: evidence.environmentFingerprint,
874
- discoveryFingerprint: evidence.discoveryFingerprint,
875
- ...(evidence.evidenceArtifactId ? { evidenceArtifactId: evidence.evidenceArtifactId } : {}),
876
- };
877
- if (stable(binding) !== stable(expected))
878
- throw new Error("Ticket 12 plan approval binding is outside the evidence baseline, environment, discovery, or delivery binding.");
879
- }
880
- function validateTicket12Evidence(evidence) {
881
- if (!evidence || evidence.route !== TICKET12_FORM_PUBLISH_ROUTE || evidence.capabilityId !== TICKET12_FORM_PUBLISH_CAPABILITY_ID)
882
- throw new Error("Ticket 12 evidence is not the host-owned form publish route.");
883
- if (evidence.environmentName !== "test" || evidence.applicationCode !== "test")
884
- throw new Error("Ticket 12 evidence is outside the named test environment and dedicated test application.");
885
- if (!isTicket08TargetSchema(evidence.targetSchemaCode))
886
- throw new Error("Ticket 12 evidence fixture model is not the host-owned Ticket 08 schema.");
887
- if (evidence.targetSheetCode !== evidence.targetSchemaCode)
888
- throw new Error("Ticket 12 evidence default sheet is not bound to the fixture schema.");
889
- if (!Array.isArray(evidence.targetFieldCodes) || evidence.targetFieldCodes.length !== TICKET09_FIELD_FAMILY.length || evidence.targetFieldCodes.some((code) => !isTicket09TargetField(code)) || new Set(evidence.targetFieldCodes).size !== TICKET09_FIELD_FAMILY.length)
890
- throw new Error("Ticket 12 evidence family field codes are not the distinct host-owned Ticket 09 field codes (one per active family member).");
891
- if ([evidence.environmentFingerprint, evidence.baselineFingerprint, evidence.discoveryFingerprint].some((value) => !SHA256.test(value)))
892
- throw new Error("Ticket 12 evidence fingerprints are not canonical.");
893
- if (evidence.modelPresence.classification !== "present" || evidence.modelPresence.query.schemaCode !== evidence.targetSchemaCode)
894
- throw new Error("Ticket 12 evidence does not carry the authoritative fixture model presence handoff.");
895
- evidence.targetFieldCodes.forEach((fieldCode, index) => {
896
- const presence = evidence.publishedFieldPresence[index];
897
- if (presence?.classification !== "present" || presence.query.schemaCode !== evidence.targetSchemaCode || presence.query.propertyCode !== fieldCode || presence.query.isPublish !== "true" || presence.field?.published !== true)
898
- throw new Error("Ticket 12 evidence does not carry exact authenticated published family field presence.");
899
- });
900
- if (evidence.formDraftState.classification !== "present" || evidence.formDraftState.query.schemaCode !== evidence.targetSchemaCode || evidence.formDraftState.query.sheetCode !== evidence.targetSheetCode || !evidence.formDraftState.form || evidence.formDraftState.form.published !== false)
901
- throw new Error("Ticket 12 evidence does not carry the exact authenticated unpublished draft-configured form pre-state.");
902
- if (evidence.requiredRuleState.classification !== "present" || evidence.requiredRuleState.query.schemaCode !== evidence.targetSchemaCode || evidence.requiredRuleState.query.dataRuleType !== 4 || !evidence.requiredRuleState.rows.some((row) => decodeRequiredDataRuleRow(row, evidence.targetSchemaCode, ticket12RuleDemoFieldCode(evidence.targetFieldCodes)) !== undefined))
903
- throw new Error(`Ticket 12 evidence does not carry the exact authenticated required-rule presence for the ${ticket12RuleDemoMemberName()} family field (the Ticket 20 handoff).`);
904
- if (!evidence.folder.id || !evidence.folder.name)
905
- throw new Error("Ticket 12 evidence folder binding is missing.");
906
- return evidence;
907
- }
908
- function assertDigest(value, label) {
909
- if (typeof value !== "string" || !SHA256.test(value) || !/[1-9a-f]/i.test(value))
910
- throw new Error(`Ticket 12 ${label} is invalid.`);
911
- }
912
- function digest(value) { return createHash("sha256").update(stable(value)).digest("hex"); }
913
- function stable(value) { return JSON.stringify(sort(value)); }
914
- function sort(value) { if (Array.isArray(value))
915
- return value.map(sort); if (value && typeof value === "object")
916
- return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => [key, sort(item)])); return value; }
917
- //# sourceMappingURL=ticket12-test-form-publish.js.map