From 14ba2e653be532e5d8bc1949de809861799336f8 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Sun, 25 Oct 2026 20:02:22 -0400 Subject: [PATCH] docs: describe the settings shared through the nest server Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 3 +- docs/automatic-nesting.md | 3 +- docs/machine-cutting-defaults.md | 3 +- docs/nest-storage.md | 8 ++++ docs/shared-settings.md | 76 ++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 docs/shared-settings.md diff --git a/AGENTS.md b/AGENTS.md index 8e6c6468..c25c16b8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,7 +38,7 @@ Releases: follow [the release procedure](docs/releasing.md) and `scripts/Publish - `OpenNest.Engine`: whole-job API in `Jobs/`, interactive proposals via `PlateFillService`, fill strategies, best-fit pairs, packing, sequencing and rapid planning. `INestingEngine.Solve(NestJob)` returns stock IDs/poses; boundary adapters map drawings and materialize results. `NestJobRunner` validates its candidates before committing demand/stock accounting. Do not assume arbitrary plug-in output or interactive paths received that validation. Job identity is reference-based, not drawing-name-based. - Built-in whole-job engines live in `OpenNest.Engine/NestingEngines//`, named for the jobs they suit; see [nesting engines](docs/nesting-engines.md). A change must beat that engine's current benchmark result with every layout valid. External plug-ins implement `INestingEngine` with a public parameterless constructor and load from `Engines/` beside the host; keep their projects out of this solution. - `OpenNest.IO`: ACadSharp import/export and ZIP-based `.nest` persistence; depends on Core only (an IO.Tests guard enforces it). Best fits persist only when callers pass `BestFitCacheStore.Shared` as `NestReader`/`NestWriter.BestFitStore`. All DXF-to-Drawing conversion goes through `CadImporter`: `Import` + `BuildDrawing` for editable/reporting flows, `ImportDrawing` for headless callers. Preserve source offsets, entity IDs, suppressed entities and bends. Bend repair is opt-in, requires explicit source units and may not alter cut geometry or unrelated marks. -- `OpenNest`: WinForms UI (`Forms/`, `Controls/PlateView`, `Actions/`). `OpenNest.Data` holds cross-platform persistence; new-nest defaults live in `%APPDATA%\OpenNest\defaults.json`. Posts live in `Posts/OpenNest.Posts./` and deploy to the desktop output's `Posts/` directory. +- `OpenNest`: WinForms UI (`Forms/`, `Controls/PlateView`, `Actions/`). `OpenNest.Data` holds cross-platform persistence; new-nest defaults live in `%APPDATA%\OpenNest\defaults.json` (in Database mode, the server's shared copy once it holds one). Posts live in `Posts/OpenNest.Posts./` and deploy to the desktop output's `Posts/` directory. - `OpenNest.Console`, `OpenNest.Mcp`, `OpenNest.Api`: front ends; `OpenNest.Benchmark`: whole-job engine comparisons; `OpenNest.Gpu`: GPU evaluators; `OpenNest.Training`: ML data collection. Benchmark timing comparisons require `--parallel 1`; validate layouts and fulfillment, not just elapsed time. ## Geometry and ownership safeguards @@ -66,6 +66,7 @@ Read the relevant contract before changing its behavior: - [Automatic cutoffs and sequencing](docs/automatic-scrap-cutoffs.md) - [Pre-post verification](docs/post-verification.md) - [Machine cutting defaults](docs/machine-cutting-defaults.md): the nest's machine supplies leads, kerf and cut-off settings for plates without their own parameters +- [Shared settings](docs/shared-settings.md): in Database mode machines, post settings, clamps and nest defaults come from the server once it holds them; offline uses the last copy read, read-only - [Cut-time estimates](docs/cut-time-estimates.md): simulator/Calculate Cut Time acceleration planner and placeholder machine limits - [Cincinnati CL](docs/cincinnati-post-output.md) and [CI Fiber](docs/cincinnati-ci-fiber-post-output.md) - [Fill verification](docs/performance/fill-verification.md): opt-in benchmarks, frozen oracles, Debug-only counters and predictor initialization. Zero Release counters do not prove work removal. diff --git a/docs/automatic-nesting.md b/docs/automatic-nesting.md index c0a6c0ff..7ff28ec2 100644 --- a/docs/automatic-nesting.md +++ b/docs/automatic-nesting.md @@ -67,7 +67,8 @@ end along Y. **Nest > Clamps...** edits the current nest's rail as a list, and **Plate > Edit Clamps** edits it on the plate view (below). **OK** applies it to every plate of the nest (**Cancel** discards the edits); removing every center removes the clamps. **Load Machine Defaults** only fills the dialog. **Save as Machine Defaults** writes -`%APPDATA%\OpenNest\clamps.json` immediately, with the clamps, their units and +`%APPDATA%\OpenNest\clamps.json` (or, in Database mode once the server holds them, the +[shared clamp settings](shared-settings.md)) immediately, with the clamps, their units and whether new nests receive them; Cancel does not undo that write. The dialog refuses to open while nesting or a plate action is running. diff --git a/docs/machine-cutting-defaults.md b/docs/machine-cutting-defaults.md index 07d03be6..7c9ddc2f 100644 --- a/docs/machine-cutting-defaults.md +++ b/docs/machine-cutting-defaults.md @@ -2,7 +2,8 @@ A nest's assigned machine (`Nest.Machine`, see [nest file format](nest-file-format.md)) supplies the starting lead-ins, lead-outs, kerf and cut-off settings for the nest's -material and thickness, from that machine's Tools > Machine Configuration entry. +material and thickness, from that machine's Tools > Machine Configuration entry (in +Database mode, the server's [shared machines](shared-settings.md) once it holds them). `MachineCuttingDefaults` (OpenNest.Data) holds the mapping; the desktop applies it. ## Lookup diff --git a/docs/nest-storage.md b/docs/nest-storage.md index 4f4f90dc..02970577 100644 --- a/docs/nest-storage.md +++ b/docs/nest-storage.md @@ -981,6 +981,14 @@ position, unique per drawing) and rebuilds `release_nest_items` with a nullable other table changes. A server older than v11 refuses to open a v11 database, so rolling back needs the pre-upgrade backup. +## Shared settings endpoints + +`/api/settings` holds the machines, post settings, clamp settings and nest defaults every +workstation shares in Database mode; see [shared settings](shared-settings.md) for the +endpoints and how the desktop uses them. Schema v13 adds the empty `shared_settings` and +`shared_setting_revisions` tables; no other table changes. A server older than v13 refuses +to open a v13 database, so rolling back needs the pre-upgrade backup. + ## Storage `OpenNest.Server.NestDatabase` uses SQLite (`Microsoft.Data.Sqlite`) with diff --git a/docs/shared-settings.md b/docs/shared-settings.md new file mode 100644 index 00000000..699a6e5f --- /dev/null +++ b/docs/shared-settings.md @@ -0,0 +1,76 @@ +# Shared settings + +In Database mode ([nest storage](nest-storage.md)) the nest server holds one copy of the +settings that decide what a nest gets and what a post writes, so every workstation in the +building nests and posts the same way: + +| Kind | Key | What it holds | This PC's own copy | +|---|---|---|---| +| `machine` | machine id | A Tools > Machine Configuration entry: materials, grades, thicknesses, leads, kerf, cut-offs, motion limits, plate sizes, support grid | `%APPDATA%\OpenNest\Machines\.json` | +| `post` | post type name, e.g. `OpenNest.Posts.CincinnatiCIFiber.CIFiberPostProcessor` | A post's settings, as its JSON file holds them | `.json` beside the post DLL in `Posts\` | +| `clamps` | `default` | Machine clamp defaults (Save as Machine Defaults) | `%APPDATA%\OpenNest\clamps.json` | +| `nest-defaults` | `default` | Tools > Nest Defaults: units, sheet size, quadrant, spacing, default machine | `%APPDATA%\OpenNest\defaults.json` | + +File mode, the console, MCP and API front ends use only this PC's copies. + +## Which copy is used + +Each kind is read from the server once the server holds it, and from this PC's copy until +then: machines as a whole (the server's machines replace this PC's as soon as it holds +one), posts per post, clamps and nest defaults as single documents. Saves go where the +settings were read, so editing a kind the server does not hold yet changes only this PC. + +When the desktop opens in Database mode and the server lacks any of this PC's machines (all +of them, when it holds none), post settings, clamp settings or nest defaults, it lists them +and offers to upload them. The first workstation to answer Yes seeds the server; a document +the server already holds is never replaced, so later workstations only add what is missing +(a post installed on just one PC, for example). Declining keeps that PC on its own copies and +asks again at the next start. + +## Freshness, offline and conflicts + +The desktop keeps the last copy it read in `%APPDATA%\OpenNest\SharedSettings\.json` +and re-reads the server when that copy is more than two minutes old, every time it posts +and when Tools > Machine Configuration opens. A request gives up after five seconds. + +While the server cannot be reached, the last copy read is used (this PC's own settings when +none has been read yet), the user is told once per session, and nothing shared can be +changed: saves fail with the reason. The desktop retries the server at most once a minute. + +Every document carries a revision. A save sends the revision it read; when someone else +saved first the server refuses it and the desktop takes their copy: + +- Post settings: the post stops, the other workstation's settings are loaded, and posting + again shows them. Posting without changing the settings dialog never saves a revision, + even though the Cincinnati post records the material library the nest selected. +- Machine Configuration: the unsaved machines stay pending; reopen the window to see the + other changes. +- Clamps, nest defaults, support grid: the save reports the conflict. + +The window title of Tools > Machine Configuration says whether it edits the shared machines, +this PC's (not shared yet), or a read-only copy. + +## Server + +`/api/settings` (schema v13) stores each document's current revision in `shared_settings` +and every revision, deletions included, in `shared_setting_revisions`, with who saved it +(the Windows user name) and when. The history has no endpoint; read it from the database to +trace or recover a change. + +| Method | Path | Body | Result | +|---|---|---|---| +| GET | `/api/settings` | — | Every current document: `[{ "kind", "key", "revision", "json", "savedAt", "savedBy" }]` | +| GET | `/api/settings/{kind}/{key}` | — | The document, or 404 | +| POST | `/api/settings/{kind}/{key}` | `{ "json", "savedBy" }` | 201 created; 200 when the same JSON is stored; 409 with the stored document otherwise | +| PUT | `/api/settings/{kind}/{key}` | `{ "json", "savedBy" }`, `If-Match: ""` | The document (same JSON is a no-op); 404 when not stored; 409 with the current document when stale | +| DELETE | `/api/settings/{kind}/{key}?savedBy=` | `If-Match: ""` | 204; 404 when not stored; 409 when stale | + +The server checks the key against the kind (a machine id, a post type name of letters, +digits and `._-+`, or `default`), that `json` is a JSON object of at most 512 K characters, +and that a machine's JSON is a machine configuration with the key's id. It cannot check a +post's settings beyond that; the desktop only sends what the post serialized. Recreating a +deleted document continues its revision count. Kinds a client does not know are ignored, so +a newer server can share more. + +A post takes part by implementing `IJsonConfigPostProcessor` (`SerializeConfig`, +`LoadConfig`); a configurable post without it keeps using only its own file.