pm-csv 2026.10.22 → 2026.10.24

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.
@@ -0,0 +1,260 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync, writeFileSync } from "node:fs";
3
+ import { getWorkspaceContracts, PmCliError } from "@unbrained/pm-cli/sdk";
4
+ import { IMPORT_COLUMNS, parseCSV, stripBOM, resolveDelimiter, parseFieldMap, resolveImportFieldMap, validateFieldMapTargets, checkMapSourcesPresent, validateParsedCSV, strictValidationIssues, normalizeStatus, importParsedCSV, readBoolOption } from "./index.js";
5
+ /** Expected SDK/CLI refusal with an actionable remedy and semantic usage exit code. */
6
+ export class TableSchemaRefusal extends PmCliError {
7
+ /** Stable category for automated refusal handling. */
8
+ code;
9
+ /** Concrete recovery action required before retrying. */
10
+ remedy;
11
+ constructor(code, remedy) {
12
+ super(`${code}: ${remedy}`, 2, { code, required: remedy, nextSteps: [remedy] });
13
+ this.code = code;
14
+ this.remedy = remedy;
15
+ }
16
+ }
17
+ /** Reject malformed quoting before using the existing parser; inspect only record separators outside quotes. */
18
+ function readTable(text, delimiter) {
19
+ if (Buffer.byteLength(text) > 8 * 1024 * 1024 || delimiter.length !== 1 || /["\r\n\uFEFF]/.test(delimiter)) {
20
+ throw new TableSchemaRefusal("csv_table_invalid", "Use at most 8 MiB of UTF-8 CSV and a single delimiter other than quotes or newlines.");
21
+ }
22
+ const source = stripBOM(text);
23
+ let state = "start";
24
+ const endings = new Set();
25
+ for (let index = 0; index < source.length; index++) {
26
+ const char = source[index];
27
+ if (state === "quoted") {
28
+ if (char === '"') {
29
+ if (source[index + 1] === '"')
30
+ index++;
31
+ else
32
+ state = "after";
33
+ }
34
+ continue;
35
+ }
36
+ if (char === delimiter)
37
+ state = "start";
38
+ else if (char === "\n" || char === "\r") {
39
+ if (char === "\r") {
40
+ if (source[++index] !== "\n")
41
+ throw new TableSchemaRefusal("csv_table_invalid", "Use LF or CRLF record separators; bare CR is unsupported.");
42
+ endings.add("crlf");
43
+ }
44
+ else
45
+ endings.add("lf");
46
+ state = "start";
47
+ }
48
+ else if (char === '"' && state === "start")
49
+ state = "quoted";
50
+ else if (char === '"' || state === "after") {
51
+ throw new TableSchemaRefusal("csv_table_invalid", "Quote complete fields and double embedded quotes; remove characters after closing quotes.");
52
+ }
53
+ else
54
+ state = "plain";
55
+ }
56
+ if (state === "quoted" || endings.size > 1)
57
+ throw new TableSchemaRefusal("csv_table_invalid", "Close every quoted field and use one consistent record separator.");
58
+ const table = parseCSV(source, delimiter);
59
+ const headers = table[0];
60
+ if (!headers?.length || headers.length > 128 || table.length > 10001 ||
61
+ headers.some(header => !header.trim() || header.length > 128) ||
62
+ new Set(headers.map(header => header.trim().toLowerCase())).size !== headers.length ||
63
+ table.some(row => row.length !== headers.length || row.every(cell => !cell.trim()))) {
64
+ throw new TableSchemaRefusal("csv_table_invalid", "Provide 1-128 distinct nonempty headers, at most 10000 data rows, matching row widths and no empty records.");
65
+ }
66
+ return { table, dialect: { delimiter, quote: '"', bom: text.startsWith("\uFEFF"), eol: [...endings][0] ?? "none" } };
67
+ }
68
+ /** Infer a conservative lexical domain over the complete column, never a sample. */
69
+ function inferDomain(values) {
70
+ const nonempty = values.map(value => value.trim()).filter(Boolean);
71
+ const kind = nonempty.length === 0 ? "empty" : nonempty.every(value => /^[+-]?\d+$/.test(value)) ? "integer"
72
+ : nonempty.every(value => /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(value)) ? "decimal"
73
+ : nonempty.every(value => /^(true|false)$/i.test(value)) ? "boolean" : "text";
74
+ return { kind, nullable: nonempty.length < values.length };
75
+ }
76
+ /** Canonical SHA-256 contract identity. Key ordering is reconstructed by the schema reader. */
77
+ function revision(base) {
78
+ return createHash("sha256").update(JSON.stringify(base)).digest("hex");
79
+ }
80
+ /** Read native target enums without activating extensions or invoking git. */
81
+ async function targetContract(pmRoot) {
82
+ const contracts = await getWorkspaceContracts(pmRoot, { noExtensions: true });
83
+ return { types: contracts.types.sort(), statuses: contracts.statuses.sort() };
84
+ }
85
+ /** Project only explicitly mapped columns; ignored canonical-looking headers cannot acquire meaning. */
86
+ function mappedTable(table, columns) {
87
+ const selected = columns.map((column, index) => ({ ...column, index })).filter(column => column.field !== null);
88
+ return [selected.map(column => column.field), ...table.slice(1).map(row => selected.map(column => row[column.index]))];
89
+ }
90
+ /** Reuse strict import checks, then check mapped type/status destinations against the SDK contract. */
91
+ function validateMapping(table, columns, target) {
92
+ const projected = mappedTable(table, columns);
93
+ const report = validateParsedCSV(projected[0], projected.slice(1), {});
94
+ if (strictValidationIssues(report).length || table.slice(1).some(row => columns.some((column, index) => {
95
+ const value = row[index].trim();
96
+ return value !== "" && ((column.field === "type" && !target.types.includes(value)) ||
97
+ (column.field === "status" && !target.statuses.includes(normalizeStatus(value))));
98
+ })))
99
+ throw new TableSchemaRefusal("csv_table_invalid", "Correct missing titles, unsupported types/statuses, priorities outside 0-4 or ambiguous pm mappings, then describe again.");
100
+ }
101
+ /** Produce bounded summary counts without returning table contents. */
102
+ function receipt(schema, rows) {
103
+ const mapped = schema.columns.filter(column => column.field !== null).length;
104
+ return { version: 1, revision: schema.revision, rows, columns: schema.columns.length, mapped, ignored: schema.columns.length - mapped };
105
+ }
106
+ /** Describe and propose a reusable schema without writing tracker state or artifacts. */
107
+ export async function describeTable(pmRoot, text, options = {}) {
108
+ const delimiter = resolveDelimiter(options.delimiter);
109
+ const { table, dialect } = readTable(text, delimiter);
110
+ const headers = table[0].map(header => header.trim().toLowerCase());
111
+ const explicit = options.fieldMap ?? {};
112
+ if (validateFieldMapTargets(explicit).length || checkMapSourcesPresent(headers, explicit).length) {
113
+ throw new TableSchemaRefusal("csv_table_invalid", "Map existing normalized source headers to supported CSV import fields.");
114
+ }
115
+ const { fieldMap } = resolveImportFieldMap(headers, explicit, options.autoMap ?? false);
116
+ const columns = table[0].map((name, index) => {
117
+ const field = fieldMap[headers[index]] ?? headers[index];
118
+ return { name, domain: inferDomain(table.slice(1).map(row => row[index])), field: IMPORT_COLUMNS.includes(field) ? field : null };
119
+ });
120
+ const target = await targetContract(pmRoot);
121
+ validateMapping(table, columns, target);
122
+ const base = { version: 1, dialect, columns, target };
123
+ const schema = { ...base, revision: revision(base) };
124
+ return { schema, receipt: receipt(schema, table.length - 1) };
125
+ }
126
+ /** Narrow an unknown JSON artifact before accessing nested properties. */
127
+ function record(value) {
128
+ return value !== null && typeof value === "object" && !Array.isArray(value);
129
+ }
130
+ /** Validate artifact version, bounds, mapping shape and canonical identity. Unknown versions fail closed. */
131
+ export function parseTableSchema(value) {
132
+ const invalid = new TableSchemaRefusal("csv_schema_invalid", "Use an unchanged version 1 schema produced by csv schema describe; create a new artifact for intentional changes.");
133
+ if (!record(value) || value.version !== 1 || typeof value.revision !== "string" || !record(value.dialect) ||
134
+ !record(value.target) || !Array.isArray(value.columns) || value.columns.length < 1 || value.columns.length > 128)
135
+ throw invalid;
136
+ const { dialect, target } = value;
137
+ if (typeof dialect.delimiter !== "string" || dialect.delimiter.length !== 1 || /["\r\n\uFEFF]/.test(dialect.delimiter) ||
138
+ dialect.quote !== '"' || typeof dialect.bom !== "boolean" || !["lf", "crlf", "none"].includes(String(dialect.eol)) ||
139
+ !Array.isArray(target.types) || !Array.isArray(target.statuses) ||
140
+ [...target.types, ...target.statuses].some(entry => typeof entry !== "string"))
141
+ throw invalid;
142
+ const columns = value.columns.map((column) => {
143
+ if (!record(column) || typeof column.name !== "string" || !column.name.trim() || column.name.length > 128 ||
144
+ !record(column.domain) || !["empty", "integer", "decimal", "boolean", "text"].includes(String(column.domain.kind)) ||
145
+ typeof column.domain.nullable !== "boolean" || (column.field !== null && !IMPORT_COLUMNS.includes(column.field)))
146
+ throw invalid;
147
+ return { name: column.name, domain: { kind: column.domain.kind, nullable: column.domain.nullable }, field: column.field };
148
+ });
149
+ const fields = columns.flatMap(column => column.field === null ? [] : [column.field]);
150
+ if (new Set(columns.map(column => column.name.trim().toLowerCase())).size !== columns.length ||
151
+ new Set(fields).size !== fields.length || !fields.includes("title"))
152
+ throw invalid;
153
+ const base = { version: 1, dialect: { delimiter: dialect.delimiter, quote: '"', bom: dialect.bom, eol: dialect.eol },
154
+ columns, target: { types: [...target.types], statuses: [...target.statuses] } };
155
+ if (revision(base) !== value.revision)
156
+ throw invalid;
157
+ return { ...base, revision: value.revision };
158
+ }
159
+ /** Enforce a saved mapping against the full new table before any tracker mutation. */
160
+ export async function previewTable(pmRoot, text, saved) {
161
+ const schema = parseTableSchema(saved);
162
+ const { table, dialect } = readTable(text, schema.dialect.delimiter);
163
+ if (JSON.stringify(dialect) !== JSON.stringify(schema.dialect) || JSON.stringify(table[0]) !== JSON.stringify(schema.columns.map(column => column.name))) {
164
+ throw new TableSchemaRefusal("csv_schema_changed", "Review changed headers, order or dialect; run csv schema describe into a new artifact and explicitly approve its mappings.");
165
+ }
166
+ for (const [index, column] of schema.columns.entries()) {
167
+ const next = inferDomain(table.slice(1).map(row => row[index]));
168
+ if ((!column.domain.nullable && next.nullable) || (next.kind !== "empty" && column.domain.kind !== "text" && next.kind !== column.domain.kind &&
169
+ !(column.domain.kind === "decimal" && next.kind === "integer"))) {
170
+ throw new TableSchemaRefusal("csv_domain_changed", "Review changed value domains or new empty cells; describe the revised table into a new schema before importing.");
171
+ }
172
+ }
173
+ if (JSON.stringify(await targetContract(pmRoot)) !== JSON.stringify(schema.target)) {
174
+ throw new TableSchemaRefusal("csv_target_changed", "Review tracker type/status changes and describe a new table schema against the current tracker.");
175
+ }
176
+ validateMapping(table, schema.columns, schema.target);
177
+ return receipt(schema, table.length - 1);
178
+ }
179
+ /** Negotiate a captured UTF-8 table then use the existing import mutation/upsert core.
180
+ * Preview never runs mutation hooks. Import retains legacy partial-write semantics on row failures.
181
+ */
182
+ export async function importNegotiatedTable(pmRoot, text, saved, options = {}) {
183
+ const schema = parseTableSchema(saved);
184
+ const { dryRun, keyField } = options;
185
+ const summary = await previewTable(pmRoot, text, schema);
186
+ if (dryRun)
187
+ return { ...summary, imported: 0, updated: 0, skipped: 0 };
188
+ const { table } = readTable(text, schema.dialect.delimiter);
189
+ const result = importParsedCSV(pmRoot, mappedTable(table, schema.columns), { delimiter: schema.dialect.delimiter, fieldMap: {}, dryRun: false, keyField });
190
+ if (result.errors.length)
191
+ throw new TableSchemaRefusal("csv_table_import_failed", `Inspect tracker state and import policies before retrying: imported=${result.imported}, updated=${result.updated}, skipped=${result.skipped}, errors=${result.errors.length}. Use csv import --atomic when rollback is required.`);
192
+ return { ...summary, imported: result.imported, updated: result.updated, skipped: result.skipped };
193
+ }
194
+ /** Read UTF-8 input and optional JSON contract without leaking IO paths in refusals. */
195
+ function readInputs(file, schemaFile) {
196
+ try {
197
+ if (!file)
198
+ throw new Error("missing input");
199
+ const bytes = readFileSync(file);
200
+ const text = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
201
+ return { text, saved: schemaFile === undefined ? undefined : JSON.parse(readFileSync(schemaFile, "utf8")) };
202
+ }
203
+ catch {
204
+ throw new TableSchemaRefusal("csv_schema_io", "Provide readable UTF-8 CSV and, for preview/import, a readable versioned JSON schema.");
205
+ }
206
+ }
207
+ /** Register native host-rendered TOON/JSON commands; full artifacts are written only on explicit request. */
208
+ export function registerTableSchemaCommands(api) {
209
+ api.registerCommand({
210
+ name: "csv schema describe", description: "Describe a bounded UTF-8 table and propose a versioned pm mapping without tracker writes.",
211
+ arguments: [{ name: "file", required: true, description: "UTF-8 CSV input" }],
212
+ flags: [
213
+ { long: "--delimiter", value_name: "char", description: "Delimiter or comma|semicolon|tab|pipe (default comma)" },
214
+ { long: "--map", value_name: "mapping", description: "Normalized Source=field pairs" },
215
+ { long: "--auto-map", description: "Propose existing unambiguous import aliases" },
216
+ { long: "--output", value_name: "file", description: "Exclusively create reusable JSON schema; never overwrite" },
217
+ ],
218
+ async run(ctx) {
219
+ const { text } = readInputs(ctx.args[0]);
220
+ let fieldMap;
221
+ try {
222
+ fieldMap = parseFieldMap(ctx.options["map"]);
223
+ }
224
+ catch {
225
+ throw new TableSchemaRefusal("csv_table_invalid", "Use --map Source=title,Rank=priority with supported import fields.");
226
+ }
227
+ const described = await describeTable(ctx.pm_root, text, { delimiter: ctx.options["delimiter"], fieldMap, autoMap: readBoolOption(ctx.options, "auto-map", "autoMap") });
228
+ const output = ctx.options["output"];
229
+ if (output) {
230
+ try {
231
+ writeFileSync(output, `${JSON.stringify(described.schema, null, 2)}\n`, { flag: "wx", mode: 0o600 });
232
+ }
233
+ catch {
234
+ throw new TableSchemaRefusal("csv_schema_io", "Choose a new writable schema filename; existing artifacts are preserved.");
235
+ }
236
+ }
237
+ return { ...described.receipt, saved: Boolean(output) };
238
+ },
239
+ });
240
+ for (const action of ["preview", "import"])
241
+ api.registerCommand({
242
+ name: `csv schema ${action}`, description: `${action === "preview" ? "Check" : "Import"} a table using an unchanged saved schema; refuse drift before writes.`,
243
+ arguments: [{ name: "file", required: true, description: "UTF-8 table matching the saved dialect" }],
244
+ flags: [
245
+ { long: "--schema", value_name: "file", description: "Required version 1 JSON schema" },
246
+ { long: "--dry-run", description: "Read-only negotiation; no item or history writes" },
247
+ { long: "--key", value_name: "field", description: "Existing import upsert key (import only)" },
248
+ ],
249
+ async run(ctx) {
250
+ const schemaFile = ctx.options["schema"];
251
+ const keyField = ctx.options["key"];
252
+ if (!schemaFile || (keyField !== undefined && !IMPORT_COLUMNS.includes(keyField))) {
253
+ throw new TableSchemaRefusal("csv_schema_invalid", "Provide --schema saved.json and, optionally, a supported import field for --key.");
254
+ }
255
+ const { text, saved } = readInputs(ctx.args[0], schemaFile);
256
+ return { ...await importNegotiatedTable(ctx.pm_root, text, saved, { dryRun: action === "preview" || readBoolOption(ctx.options, "dry-run", "dryRun"), keyField }) };
257
+ },
258
+ });
259
+ }
260
+ //# sourceMappingURL=table-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-schema.js","sourceRoot":"","sources":["../table-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,qBAAqB,EACjG,uBAAuB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,sBAAsB,EAC1F,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAOvE,uFAAuF;AACvF,MAAM,OAAO,kBAAmB,SAAQ,UAAU;IAChD,sDAAsD;IAC7C,IAAI,CAAmB;IAChC,yDAAyD;IAChD,MAAM,CAAS;IACxB,YAAY,IAAsB,EAAE,MAAc;QAChD,KAAK,CAAC,GAAG,IAAI,KAAK,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAChF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAmCD,gHAAgH;AAChH,SAAS,SAAS,CAAC,IAAY,EAAE,SAAiB;IAChD,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3G,MAAM,IAAI,kBAAkB,CAAC,mBAAmB,EAAE,sFAAsF,CAAC,CAAC;IAC5I,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,KAAK,GAA2C,OAAO,CAAC;IAC5D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAiB,CAAC;IACzC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvB,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACjB,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;oBAAE,KAAK,EAAE,CAAC;;oBAClC,KAAK,GAAG,OAAO,CAAC;YACvB,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,IAAI,KAAK,SAAS;YAAE,KAAK,GAAG,OAAO,CAAC;aACnC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YACxC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAClB,IAAI,MAAM,CAAC,EAAE,KAAK,CAAC,KAAK,IAAI;oBAAE,MAAM,IAAI,kBAAkB,CAAC,mBAAmB,EAAE,2DAA2D,CAAC,CAAC;gBAC7I,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACtB,CAAC;;gBAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACzB,KAAK,GAAG,OAAO,CAAC;QAClB,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,IAAI,KAAK,KAAK,OAAO;YAAE,KAAK,GAAG,QAAQ,CAAC;aAC1D,IAAI,IAAI,KAAK,GAAG,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YAC3C,MAAM,IAAI,kBAAkB,CAAC,mBAAmB,EAAE,2FAA2F,CAAC,CAAC;QACjJ,CAAC;;YAAM,KAAK,GAAG,OAAO,CAAC;IACzB,CAAC;IACD,IAAI,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC;QAAE,MAAM,IAAI,kBAAkB,CAAC,mBAAmB,EAAE,mEAAmE,CAAC,CAAC;IACnK,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,CAAC,OAAO,EAAE,MAAM,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK;QAChE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC;QAC7D,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM;QACnF,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QACxF,MAAM,IAAI,kBAAkB,CAAC,mBAAmB,EAAE,6GAA6G,CAAC,CAAC;IACnK,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,EAAE,CAAC;AACvH,CAAC;AAED,oFAAoF;AACpF,SAAS,WAAW,CAAC,MAAgB;IACnC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnE,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QAC1G,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,gCAAgC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;YACnF,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAChF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;AAC7D,CAAC;AAED,+FAA+F;AAC/F,SAAS,QAAQ,CAAC,IAAmC;IACnD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzE,CAAC;AAED,8EAA8E;AAC9E,KAAK,UAAU,cAAc,CAAC,MAAc;IAC1C,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9E,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;AAChF,CAAC;AAED,wGAAwG;AACxG,SAAS,WAAW,CAAC,KAAiB,EAAE,OAA+B;IACrE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;IAChH,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAM,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1H,CAAC;AAED,uGAAuG;AACvG,SAAS,eAAe,CAAC,KAAiB,EAAE,OAA+B,EAAE,MAA6B;IACxG,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACvE,IAAI,sBAAsB,CAAC,MAAM,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QACrG,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;QAChC,OAAO,KAAK,KAAK,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAChF,CAAC,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,kBAAkB,CAAC,mBAAmB,EAAE,2HAA2H,CAAC,CAAC;AACtL,CAAC;AAED,uEAAuE;AACvE,SAAS,OAAO,CAAC,MAAmB,EAAE,IAAY;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;IAC7E,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;AAC1I,CAAC;AAED,yFAAyF;AACzF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc,EAAE,IAAY,EAAE,OAAO,GAAyB,EAAE;IAClG,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;IACxC,IAAI,uBAAuB,CAAC,QAAQ,CAAC,CAAC,MAAM,IAAI,sBAAsB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;QACjG,MAAM,IAAI,kBAAkB,CAAC,mBAAmB,EAAE,wEAAwE,CAAC,CAAC;IAC9H,CAAC;IACD,MAAM,EAAE,QAAQ,EAAE,GAAG,qBAAqB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC,CAAC;IACxF,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC3C,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;QACzD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,QAAQ,CAAC,KAAmB,CAAC,CAAC,CAAC,CAAC,KAAmB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAChK,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;IAC5C,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,CAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAC/D,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACrD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;AAChE,CAAC;AAED,0EAA0E;AAC1E,SAAS,MAAM,CAAC,KAAc;IAC5B,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,MAAM,OAAO,GAAG,IAAI,kBAAkB,CAAC,oBAAoB,EAAE,mHAAmH,CAAC,CAAC;IAClL,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;QACrG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG;QAAE,MAAM,OAAO,CAAC;IACpI,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAClC,IAAI,OAAO,OAAO,CAAC,SAAS,KAAK,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;QAClH,OAAO,CAAC,KAAK,KAAK,GAAG,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAClH,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;QAC/D,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC;QAAE,MAAM,OAAO,CAAC;IAClG,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAe,EAAkC,EAAE;QACpF,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG;YACrG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClH,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAmB,CAAC,CAAC;YAAE,MAAM,OAAO,CAAC;QAClJ,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAA2B,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAA0B,EAAE,CAAC;IACxK,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtF,IAAI,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM;QACxF,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,MAAM,OAAO,CAAC;IACvF,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,CAAU,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,GAAY,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,GAAoC,EAAE;QACrK,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAa,EAAE,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAa,EAAE,EAAE,CAAC;IAC1G,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,QAAQ;QAAE,MAAM,OAAO,CAAC;IACrD,OAAO,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;AAC/C,CAAC;AAED,sFAAsF;AACtF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAc,EAAE,IAAY,EAAE,KAAc;IAC7E,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACrE,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACzJ,MAAM,IAAI,kBAAkB,CAAC,oBAAoB,EAAE,4HAA4H,CAAC,CAAC;IACnL,CAAC;IACD,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QACvD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChE,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI;YACzI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,EAAE,CAAC;YACpE,MAAM,IAAI,kBAAkB,CAAC,oBAAoB,EAAE,iHAAiH,CAAC,CAAC;QACxK,CAAC;IACH,CAAC;IACD,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACnF,MAAM,IAAI,kBAAkB,CAAC,oBAAoB,EAAE,iGAAiG,CAAC,CAAC;IACxJ,CAAC;IACD,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACtD,OAAO,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAc,EAAE,IAAY,EAAE,KAAc,EAAE,OAAO,GAAgD,EAAE;IACjJ,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACrC,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACzD,IAAI,MAAM;QAAE,OAAO,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IACvE,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC3J,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,kBAAkB,CAAC,yBAAyB,EAAE,uEAAuE,MAAM,CAAC,QAAQ,aAAa,MAAM,CAAC,OAAO,aAAa,MAAM,CAAC,OAAO,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,sDAAsD,CAAC,CAAC;IACtT,OAAO,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;AACrG,CAAC;AAED,wFAAwF;AACxF,SAAS,UAAU,CAAC,IAAwB,EAAE,UAAmB;IAC/D,IAAI,CAAC;QACH,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAY,EAAE,CAAC;IACzH,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,IAAI,kBAAkB,CAAC,eAAe,EAAE,uFAAuF,CAAC,CAAC;IAAC,CAAC;AACrJ,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,2BAA2B,CAAC,GAAiB;IAC3D,GAAG,CAAC,eAAe,CAAC;QAClB,IAAI,EAAE,qBAAqB,EAAE,WAAW,EAAE,2FAA2F;QACrI,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC;QAC7E,KAAK,EAAE;YACL,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,uDAAuD,EAAE;YACjH,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,+BAA+B,EAAE;YACtF,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,6CAA6C,EAAE;YAClF,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,0DAA0D,EAAE;SAClH;QACD,KAAK,CAAC,GAAG,CAAC,GAAG;YACX,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,IAAI,QAAgC,CAAC;YACrC,IAAI,CAAC;gBAAC,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAuB,CAAC,CAAC;YAAC,CAAC;YAC3E,MAAM,CAAC;gBAAC,MAAM,IAAI,kBAAkB,CAAC,mBAAmB,EAAE,oEAAoE,CAAC,CAAC;YAAC,CAAC;YAClI,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,WAAW,CAAuB,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;YAC/L,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAuB,CAAC;YAC3D,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,CAAC;oBAAC,aAAa,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBAAC,CAAC;gBAC7G,MAAM,CAAC;oBAAC,MAAM,IAAI,kBAAkB,CAAC,eAAe,EAAE,0EAA0E,CAAC,CAAC;gBAAC,CAAC;YACtI,CAAC;YACD,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1D,CAAC;KACF,CAAC,CAAC;IACH,KAAK,MAAM,MAAM,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAU;QAAE,GAAG,CAAC,eAAe,CAAC;YACvE,IAAI,EAAE,cAAc,MAAM,EAAE,EAAE,WAAW,EAAE,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,uEAAuE;YAC9J,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC;YACpG,KAAK,EAAE;gBACL,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,gCAAgC,EAAE;gBACvF,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,kDAAkD,EAAE;gBACtF,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,0CAA0C,EAAE;aAChG;YACD,KAAK,CAAC,GAAG,CAAC,GAAG;gBACX,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAuB,CAAC;gBAC/D,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAA2B,CAAC;gBAC9D,IAAI,CAAC,UAAU,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;oBAClF,MAAM,IAAI,kBAAkB,CAAC,oBAAoB,EAAE,kFAAkF,CAAC,CAAC;gBACzI,CAAC;gBACD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;gBAC5D,OAAO,EAAE,GAAG,MAAM,qBAAqB,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,KAAK,SAAS,IAAI,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;YACtK,CAAC;SACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,76 @@
1
+ # pm-cli 2026.10.20 compatibility
2
+
3
+ Dependabot [PR 177](https://github.com/unbraind/pm-csv/pull/177) updates the
4
+ development host from 2026.10.15 to 2026.10.20. Its original Node 22 and Node 26
5
+ CI jobs failed three tests. The priority-99 row errors in those logs are
6
+ deliberately injected invalid inputs, not unexpected update failures.
7
+
8
+ | Failure | Root cause | Adaptation |
9
+ | --- | --- | --- |
10
+ | Malformed SDK journal identities | The SDK now distinguishes `transaction_journal_invalid` from a valid journal that mismatches the plan. pm-csv depended on the older combined diagnostic and decoded bindings before validating the schema and transaction identity. | Validate both identities before using bindings or entering the coordinator; throw a host-recognized `CommandError`. Keep the original plan-mismatch refusal and prove every fixture byte stays unchanged. |
11
+ | Partial create/update command and importer failures | The tests read `priority` from default brief list rows. `--all` selects statuses, independently of projection, on the new host. | Request `--full` in the verification reads. Keep the exact error counts, continuation, priority and absence assertions. Production complete-list readers already request `--output-include full` and certify completeness. |
12
+ | Legacy CLI parity without git | The same brief-row assumption in a real CLI verification read. | Request `--full`; retain both command spellings, streaming and buffered imports, a PATH without git, dry-run snapshots and nonzero failure assertions. |
13
+
14
+ ## Version evidence
15
+
16
+ Read release notes for 2026.10.17 through 2026.10.20. There is no v2026.10.16
17
+ release; v2026.10.17 covers the source range starting at v2026.10.15.
18
+
19
+ - [2026.10.17](https://github.com/unbraind/pm-cli/releases/tag/v2026.10.17)
20
+ adds SDK bulk creation. Its
21
+ [implementation](https://github.com/unbraind/pm-cli/commit/94757af3016420bfda6b6fc1905be7814ee2ea1d)
22
+ separates invalid journals from plan mismatches in
23
+ `src/sdk/workspace-transaction.ts`.
24
+ - [2026.10.18](https://github.com/unbraind/pm-cli/releases/tag/v2026.10.18)
25
+ documents GH-1489, keeping all-status selection independent of projection.
26
+ - [2026.10.19](https://github.com/unbraind/pm-cli/releases/tag/v2026.10.19)
27
+ adds encoding aliases; [2026.10.20](https://github.com/unbraind/pm-cli/releases/tag/v2026.10.20)
28
+ preserves JSON row facts and compacts default brief TOON envelopes. Neither
29
+ promises priority in a brief list row.
30
+
31
+ Real installed-host probes in fresh non-git trackers confirmed:
32
+
33
+ | Host | Default `list --all --json` priority | With `--full` | Bad journal schema |
34
+ | --- | --- | --- | --- |
35
+ | 2026.10.15 | 2 | 2 | journal does not match the supplied plan |
36
+ | 2026.10.20 | omitted | 2 | journal is invalid (schema version or transaction id does not match the journal file) |
37
+
38
+ Both hosts rejected priority 99 with exit 2 and accepted priority 2. No upstream
39
+ regression was established by these failures, so no new upstream issue draft
40
+ is needed.
41
+
42
+ ## Regression proof
43
+
44
+ The focused command is:
45
+
46
+ ```sh
47
+ npm run build && npm run build:test && node --test --test-name-pattern="malformed SDK journal|partial create/update|legacy CSV CLI" test/atomic-update.test.ts test/commands.test.ts test/legacy-import-cli.test.ts
48
+ ```
49
+
50
+ It passes 3/3 with the pinned host on PATH. The journal test covers malformed
51
+ step shapes, missing/unsupported schemas and missing/foreign transaction ids in
52
+ source and built code. It asserts refusal before coordinator entry and compares
53
+ all fixture file bytes, including item history and the journal itself.
54
+
55
+ Reverting only `loadAtomicBindings` to the PR's original implementation and
56
+ rebuilding makes the journal regression fail 0/1 at the behavioral assertion
57
+ `invalid journal identity must refuse before coordinator entry` (`true !== false`).
58
+ Restoring the function makes it pass. No refusal expectation was weakened.
59
+
60
+ ## Lease fencing assessment (no pin or workaround change)
61
+
62
+ [pm-cli 2026.10.23](https://github.com/unbraind/pm-cli/releases/tag/v2026.10.23)
63
+ includes [GH-1549](https://github.com/unbraind/pm-cli/issues/1549), implemented in
64
+ [PR 1550](https://github.com/unbraind/pm-cli/pull/1550). Native item mutations
65
+ fence their commit against lease takeover and changed item bytes. The public
66
+ `acquireLockLease` primitive also lets extensions fence their own commits.
67
+
68
+ A real unguarded SDK probe with a one-second lease and a newer writer committing
69
+ after expiry overwrote the newer title on 2026.10.20. The same probe on
70
+ 2026.10.23 refused the stale writer and preserved the newer title. This supports
71
+ removing the callback-only `csv_lease_expired` mitigation for native mutation
72
+ paths once the supported host floor is raised and SDK/CLI takeover regressions
73
+ are migrated to the host's typed refusal. Extension-provided lock overrides
74
+ still own their fencing contract; the upstream implementation cannot fence
75
+ those providers automatically. The current peer floor and development pin still
76
+ need the mitigation, so `lease-guard.ts` remains unchanged.
@@ -0,0 +1,49 @@
1
+ # Public tracker validation
2
+
3
+ Source: public `unbraind/pm-csv`, main commit
4
+ `d5dbdb0a52e3e25ee79d95b98cf0b7585cd5602d`.
5
+
6
+ A Git archive of `.agents/pm` was extracted to a non-git scratch directory, then
7
+ all source files and directories were made read-only. The SDK certified all
8
+ 120 items through `listAllComplete`; 24 titles/priorities were selected. Every
9
+ sixth input priority was changed to 9 to exercise deterministic rejection. The
10
+ separate destination was a disposable non-git tracker. Git was absent from
11
+ `PATH` during every import/retry.
12
+
13
+ | Measurement | Result |
14
+ | --- | ---: |
15
+ | Public items read with completeness proof | 120 |
16
+ | Selected input rows | 24 |
17
+ | Initial imported / rejected | 20 / 4 |
18
+ | Corrected rejected rows imported | 4 |
19
+ | Unchanged corrected rows replayed / newly imported | 4 / 0 |
20
+ | Original successful histories unchanged | 20 / 20 |
21
+ | Initial imported cell lineage records | 40 |
22
+ | Disallowed columns excluded | 1 / 1 |
23
+ | Exact-byte artifact checksums verified | 2 / 2 |
24
+ | Initial JSON receipt | 129 bytes |
25
+ | Import, correction, replay and integrity checks | 10,166 ms |
26
+ | Read-only source snapshot unchanged | yes |
27
+
28
+ Reproduce using a read-only public tracker copy:
29
+
30
+ ```sh
31
+ node scripts/validate-row-lineage.ts "$PUBLIC_TRACKER_COPY"
32
+ ```
33
+
34
+ The script hashes the entire source before and after, checks its read-only
35
+ permissions, certifies complete SDK reads, creates a fresh non-git target,
36
+ validates the import and corrected retry, verifies successful history bytes,
37
+ checks file checksums and excluded-column sentinels, and prints aggregate JSON.
38
+ It removes only its disposable target. No public source item content is included
39
+ in this report. Timing measures this run and does not establish throughput.
40
+
41
+ Behavioral revert proofs (`node --test --test-name-pattern='cell lineage excludes' test/lineage.test.ts`):
42
+
43
+ - Reverting only `importLineage`'s rejected-row filter to include successful rows
44
+ failed the receipt/retry assertion (2 rejected instead of 1).
45
+ - Reverting only that function's allowed-column projection to copy raw rows
46
+ failed the excluded-column sentinel assertion.
47
+
48
+ Both controls were restored. The regular targeted suite passes with the
49
+ production implementation; CI supplies the full npm and Bun release evidence.
@@ -0,0 +1,87 @@
1
+ # Row lineage and rejected-row retry
2
+
3
+ `pm csv bundle input.csv --columns title,priority --output first-bundle`
4
+ imports a bounded UTF-8 CSV and creates three private files:
5
+
6
+ - `manifest.json`: version 1, SHA-256 source and mapping revision, one logical
7
+ record number per row (header is record 1), one-based source column numbers,
8
+ permitted source headers and destination fields, source-cell and observed
9
+ persisted-value hashes, stable row keys, outcomes and item IDs.
10
+ - `rejected.csv`: only rejected rows, the explicitly allowed fields, and an
11
+ opaque `_csv_key` column. It never includes successful rows or other columns.
12
+ - `checksums.json`: SHA-256 of the exact bytes of the other two files.
13
+
14
+ Correct values in `rejected.csv`, keep its `_csv_key` cells unchanged, then run:
15
+
16
+ ```sh
17
+ pm csv bundle first-bundle/rejected.csv --columns title,priority --output retry-bundle
18
+ ```
19
+
20
+ Successful original rows are absent from the retry input. Native SDK explicit
21
+ item IDs and an import fingerprint tag make unchanged retries idempotent,
22
+ including recovery after a process interruption before artifact export. Changed
23
+ values for a previously committed key refuse with `identity_conflict`; use
24
+ `pm update` for intentional changes. Do not delete provenance tags. Different
25
+ input files without retained retry keys represent separate imports. This command
26
+ creates items; use `csv apply` for edits to existing tracker items.
27
+
28
+ Example input (the `internal` column is excluded from both import and artifacts):
29
+
30
+ ```csv
31
+ Summary,priority,internal
32
+ Accepted task,2,exclude this column
33
+ ,9,exclude this column too
34
+ ```
35
+
36
+ ```sh
37
+ pm csv bundle input.csv --map Summary=title --columns title,priority --output first-bundle
38
+ # receipt: rows=2 imported=1 replayed=0 rejected=1 manifest=<sha256>
39
+ # In rejected.csv, supply the title and change priority to an integer from 0 to 4.
40
+ ```
41
+
42
+ The host renders the small receipt in its normal TOON format; `--json` returns
43
+ JSON. Large per-cell details stay in the manifest. A nonempty rejection count is
44
+ partial success, so automation must check `rejected` before continuing. Structural
45
+ and I/O refusals are typed `LineageRefusal` errors with `code`, `remedy`, exit code
46
+ 2 and SDK recovery context. Per-row codes and remedies live in the manifest;
47
+ raw SDK errors and disallowed cell values are never copied into diagnostics.
48
+
49
+ Supported fields are `title`, `body`, `type`, `status`, `priority`, `tags`,
50
+ `assignee`, `sprint`, `release`. `--columns` is an explicit disclosure policy:
51
+ only those fields are imported or exported. Missing/ambiguous mappings and
52
+ unknown policy fields refuse before writes. Values are trimmed and native SDK
53
+ schema, lifecycle and governance rules apply. Terminal states needing a reason
54
+ or custom type requirements may be rejected; choose supported input values or
55
+ use the native lifecycle commands. Row width, missing titles and invalid
56
+ priorities reject the row. There are at most 1000 data rows per call.
57
+
58
+ Hash rules: `lineageDigest(value)` is SHA-256 of UTF-8 `JSON.stringify(value)`.
59
+ The source digest hashes the entire parsed table, including excluded columns,
60
+ without exporting their values or names. The mapping revision hashes
61
+ `[1, mapping]`, including ordered permitted headers/columns/fields. Each source
62
+ cell is hashed before trimming; each persisted value is hashed from the native
63
+ item document observed after import/replay (missing values use JSON null).
64
+ Hashes are integrity checks, not encryption or a signature. Preserve the
65
+ original manifest for the original observation if the tracker later changes.
66
+ The manifest digest hashes all fields except `digest`; `rejectedDigest` hashes
67
+ the parsed retry table. File checksums additionally detect byte-level changes.
68
+ Correcting retry cells intentionally changes checksums and creates a new manifest.
69
+ A retry manifest describes its own input coordinates and mapping revision; the
70
+ stable row key links back to the previous manifest.
71
+
72
+ SDK example:
73
+
74
+ ```ts
75
+ import { importLineage, parseCSV } from "pm-csv";
76
+ const bundle = await importLineage(pmRoot, parseCSV(csvText), {
77
+ columns: ["title", "priority"], fieldMap: { Summary: "title" }, author: "csv-agent",
78
+ });
79
+ console.log(bundle.receipt);
80
+ // Persist bundle.manifest and serializeCSV(bundle.rejected, ",") as private artifacts.
81
+ ```
82
+
83
+ No Git command is needed: native SDK create, schema validation, locks, history
84
+ and explicit IDs own tracker behavior. Keep the output directory private. The
85
+ CLI reserves a new directory before mutation, refuses existing directories, and
86
+ never overwrites artifacts. If final writes fail, retain partial files and rerun
87
+ unchanged input into a fresh directory; stable keys recover committed rows.