pm-csv 2026.10.23 → 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.
- package/CHANGELOG.md +16 -0
- package/README.md +20 -0
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -8
- package/dist/index.js.map +1 -1
- package/dist/table-schema.d.ts +80 -0
- package/dist/table-schema.d.ts.map +1 -0
- package/dist/table-schema.js +260 -0
- package/dist/table-schema.js.map +1 -0
- package/docs/compatibility-2026.10.20.md +76 -0
- package/docs/table-schema.md +123 -0
- package/manifest.json +1 -1
- package/package.json +8 -6
|
@@ -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":"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"}
|
|
@@ -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,123 @@
|
|
|
1
|
+
# Versioned table schema negotiation
|
|
2
|
+
|
|
3
|
+
A saved version 1 schema binds a UTF-8 table's delimiter, doubled-double-quote
|
|
4
|
+
escaping, BOM presence, record separator, exact ordered headers, full-column
|
|
5
|
+
value domains and proposed pm mappings. It also binds the target types and
|
|
6
|
+
statuses resolved by the native pm SDK. A renamed, reordered, added or removed
|
|
7
|
+
column cannot reuse that mapping. Describe the changed input into a **new**
|
|
8
|
+
artifact and review the mapping before using it.
|
|
9
|
+
|
|
10
|
+
```csv
|
|
11
|
+
Summary;priority;body
|
|
12
|
+
"Document; negotiation";2;"Quote ""safely"""
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pm csv schema describe backlog.csv --delimiter semicolon --auto-map --output backlog.schema.json --json
|
|
17
|
+
pm csv schema preview backlog.csv --schema backlog.schema.json --json
|
|
18
|
+
pm csv schema import backlog.csv --schema backlog.schema.json --dry-run --json
|
|
19
|
+
pm csv schema import backlog.csv --schema backlog.schema.json --key title --json
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`describe` proposes the existing import aliases only when `--auto-map` is
|
|
23
|
+
explicit. Alternatively use `--map Summary=title,Rank=priority`. Input map keys
|
|
24
|
+
follow the existing lowercase/trimmed header convention. The saved artifact
|
|
25
|
+
preserves the original exact header spelling, whitespace and order. A field
|
|
26
|
+
outside the supported CSV import surface has `field: null` and is excluded
|
|
27
|
+
from import. Renaming an ignored column still requires review.
|
|
28
|
+
|
|
29
|
+
Without `--output`, describe returns a compact count/revision receipt. With
|
|
30
|
+
`--output`, it exclusively creates a private JSON artifact (mode 0600), never
|
|
31
|
+
overwriting an existing file. Review its `columns[].field` proposals in that
|
|
32
|
+
file; cell values and input paths are absent. The host renders receipts in
|
|
33
|
+
TOON by default and JSON with global `--json`. Receipts stay constant in size
|
|
34
|
+
as row counts grow: version, revision, row/column/mapped/ignored counts, plus
|
|
35
|
+
save or import counts. No row previews are returned.
|
|
36
|
+
|
|
37
|
+
## Typed SDK
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { readFileSync } from "node:fs";
|
|
41
|
+
import {
|
|
42
|
+
describeTable, previewTable, importNegotiatedTable, TableSchemaRefusal,
|
|
43
|
+
} from "pm-csv";
|
|
44
|
+
import type { TableSchema, TableReceipt } from "pm-csv";
|
|
45
|
+
|
|
46
|
+
const tracker = ".agents/pm";
|
|
47
|
+
const text = readFileSync("backlog.csv", "utf8");
|
|
48
|
+
const { schema } = await describeTable(tracker, text, {
|
|
49
|
+
delimiter: ";", fieldMap: { summary: "title" },
|
|
50
|
+
});
|
|
51
|
+
const saved: TableSchema = schema;
|
|
52
|
+
const preview: TableReceipt = await previewTable(tracker, text, saved);
|
|
53
|
+
try {
|
|
54
|
+
await importNegotiatedTable(tracker, text, saved, { keyField: "title" });
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error instanceof TableSchemaRefusal) {
|
|
57
|
+
console.error(error.code, error.remedy);
|
|
58
|
+
} else throw error;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use `parseTableSchema(unknown)` to validate an artifact before reuse. Unsupported
|
|
63
|
+
versions, malformed shapes and changed revisions refuse. The SHA-256 revision
|
|
64
|
+
hashes canonical JSON in the order `version,dialect,columns,target`, with
|
|
65
|
+
dialect keys `delimiter,quote,bom,eol`, column keys `name,domain,field`, domain
|
|
66
|
+
keys `kind,nullable` and target keys `types,statuses`. Top-level JSON key order
|
|
67
|
+
does not matter. This checksum detects accidental edits; it is not an
|
|
68
|
+
authentication signature. Only use reviewed artifacts from trusted sources.
|
|
69
|
+
|
|
70
|
+
## Domains and refusals
|
|
71
|
+
|
|
72
|
+
Domains inspect **all** cells, never a sample. After trimming, nonempty values
|
|
73
|
+
are classified as integer, decimal, boolean (`true`/`false`, case insensitive),
|
|
74
|
+
text or empty. `nullable` records whether empty cells were observed. Text allows
|
|
75
|
+
arbitrary new strings; decimal permits an integer subset. New empty cells in a
|
|
76
|
+
nonnullable column and other domain widening require a new schema. An all-empty
|
|
77
|
+
column cannot silently become populated. Domains describe lexical input and
|
|
78
|
+
do not promise preservation of whitespace or numerical formatting: negotiated
|
|
79
|
+
import retains existing CSV coercion and trimming semantics.
|
|
80
|
+
|
|
81
|
+
| Code | Remedy |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `csv_table_invalid` | Correct quoting, row widths, mappings, title, priority, type or status. |
|
|
84
|
+
| `csv_schema_invalid` | Restore a valid unchanged version 1 artifact or describe a new one. |
|
|
85
|
+
| `csv_schema_changed` | Review dialect/header/order changes and explicitly adopt a new schema. |
|
|
86
|
+
| `csv_domain_changed` | Review changed domains/nullability and describe again. |
|
|
87
|
+
| `csv_target_changed` | Review changed target types/statuses and describe again. |
|
|
88
|
+
| `csv_schema_io` | Supply readable UTF-8 inputs or a new writable output filename. |
|
|
89
|
+
| `csv_table_import_failed` | Inspect reported counts and tracker policies before retrying. |
|
|
90
|
+
|
|
91
|
+
All package refusals extend the SDK's `PmCliError`, expose `code` and `remedy`,
|
|
92
|
+
and exit 2 with structured context/next steps. Normal SDK tracker-read errors
|
|
93
|
+
retain their native SDK error contract. Schema refusal messages never echo raw
|
|
94
|
+
cell values; mutation diagnostics retain the existing importer's behavior.
|
|
95
|
+
|
|
96
|
+
## Boundaries
|
|
97
|
+
|
|
98
|
+
The negotiated protocol accepts at most 8 MiB, 128 columns (distinct normalized
|
|
99
|
+
headers of at most 128 characters) and 10000 data rows. It rejects malformed
|
|
100
|
+
quotes, mixed LF/CRLF record separators, bare CR, blank records, ragged rows,
|
|
101
|
+
unknown statuses and invalid priorities. Embedded line endings inside quoted
|
|
102
|
+
cells are preserved by parsing/serialization and do not define record dialect.
|
|
103
|
+
The shared import parser retains an explicit final `""` record even without a
|
|
104
|
+
trailing newline. Quoted and unquoted empty records are validated and refused;
|
|
105
|
+
a single terminating LF or CRLF does not invent an additional record.
|
|
106
|
+
Delimiter aliases are comma, semicolon, tab and pipe. Quoting style may change
|
|
107
|
+
between equivalent valid encodings; escaping rules remain fixed.
|
|
108
|
+
|
|
109
|
+
Describe, preview and import dry-run do not mutate tracker documents, history
|
|
110
|
+
or settings and need no git. Preview checks the table contract and pm field
|
|
111
|
+
values; it does not plan dedup outcomes or execute per-item mutation hooks.
|
|
112
|
+
Import negotiates the complete captured text before calling the existing CSV
|
|
113
|
+
create/update core, so changing the source file afterward cannot change that
|
|
114
|
+
operation's input. The SDK also captures caller-owned schemas and options before
|
|
115
|
+
asynchronous tracker reads. Native history, locking, schema validation, key semantics and
|
|
116
|
+
mutation policies remain authoritative. Negotiation is not a target-schema
|
|
117
|
+
lock: a concurrent policy change can still refuse a row during import.
|
|
118
|
+
|
|
119
|
+
Negotiated import retains legacy partial-write semantics on mutation failures;
|
|
120
|
+
its refusal reports counts. It does not offer atomic resume or compensation.
|
|
121
|
+
The separate `csv import --atomic` command remains available for that workflow.
|
|
122
|
+
Core schema evolution changes tracker contracts; this protocol describes input
|
|
123
|
+
tables. Spreadsheet edit sessions and cell lineage remain separate protocols.
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pm-csv",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.24",
|
|
4
4
|
"description": "CSV importer and exporter for pm-cli",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -68,12 +68,12 @@
|
|
|
68
68
|
"@babel/eslint-parser": "8.0.7",
|
|
69
69
|
"@babel/plugin-syntax-typescript": "8.0.3",
|
|
70
70
|
"@types/node": "26.6.5",
|
|
71
|
-
"@unbrained/pm-cli": "2026.10.
|
|
71
|
+
"@unbrained/pm-cli": "2026.10.20",
|
|
72
72
|
"eslint": "10.13.0",
|
|
73
73
|
"jiti": "2.7.0",
|
|
74
|
-
"jscpd": "5.4.
|
|
75
|
-
"pm-changelog": "2026.10.
|
|
76
|
-
"pm-ops": "2026.10.
|
|
74
|
+
"jscpd": "5.4.2",
|
|
75
|
+
"pm-changelog": "2026.10.20",
|
|
76
|
+
"pm-ops": "2026.10.20",
|
|
77
77
|
"typescript": "7.0.2",
|
|
78
78
|
"yaml": "2.9.1"
|
|
79
79
|
},
|
|
@@ -118,10 +118,12 @@
|
|
|
118
118
|
"docs/atomic-compensation.md",
|
|
119
119
|
"docs/spreadsheet-roundtrip.md",
|
|
120
120
|
"docs/row-lineage.md",
|
|
121
|
+
"docs/table-schema.md",
|
|
121
122
|
"CHANGELOG.md"
|
|
122
123
|
],
|
|
123
124
|
"examples": [
|
|
124
|
-
"README.md"
|
|
125
|
+
"README.md",
|
|
126
|
+
"docs/table-schema.md"
|
|
125
127
|
]
|
|
126
128
|
},
|
|
127
129
|
"publishConfig": {
|