forked from 1b-agent/fieldcraft-upstream
Docs: crash reports, the log file, Report a Bug and privacy (#107)
docs/crash-reports.md: what is kept where, what a bug report carries (and only when ticked), the CLI and commands for agents; README's privacy note; the control protocol's new prompt answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
e06c85eb9e
commit
b19277ae7a
3 files changed
+95
-1
No files matched your search
@@ -50,7 +50,7 @@ commands (files, undo, `model.info`) leave the ribbon where it is.
|
||||
| `ui.select` | `kind` (`set`, `material`, `section`, `step`, `boundary_condition`, `load`, `reference_point`, `coupling`, `fluid_domain`), `name`; nothing to deselect | selects a definition as a browser click does; its properties (with Edit and Delete) show in the context panel |
|
||||
| `ui.select` (viewport) | any of `filter`, `box_mode`, `mode`, `clear`, `at`, `box`, `geometry`, `nodes`, `elements`, `faces` (and no `kind`) | changes the viewport's selection (see [Selection](#selection)); returns `ui.selection`'s reply |
|
||||
| `ui.selection` | — | the viewport's selection: `filter`, `box_mode` (box selection on), `count`, `capped`, `summary`, `items`, `params` (the selection as a set's members), `hover` (what a click would pick under the pointer) |
|
||||
| `ui.prompt` | `answer`: for `unsaved` `save`, `discard` or `cancel`; for `design` `new` (a new model with the design), `keep` (the design over the current model) or `cancel`; for `replace_mesh` `replace` (runs the form, replacing the mesh) or `cancel` (the form stays open); for `delete` (the item menu's Delete… or the Delete key: `{delete: question, kind, name, users, allowed}`) `delete` (with a datum's partitions when it has any; refused when `allowed` is false) or `cancel`; for `recover` `recover` (with `id` from `file.recovery.list`) or `close`; for `samples` `open` (with `name`) or `close` | answers the window's question (`ui.inspect`'s `prompt`) |
|
||||
| `ui.prompt` | `answer`: for `unsaved` `save`, `discard` or `cancel`; for `design` `new` (a new model with the design), `keep` (the design over the current model) or `cancel`; for `replace_mesh` `replace` (runs the form, replacing the mesh) or `cancel` (the form stays open); for `delete` (the item menu's Delete… or the Delete key: `{delete: question, kind, name, users, allowed}`) `delete` (with a datum's partitions when it has any; refused when `allowed` is false) or `cancel`; for `recover` `recover` (with `id` from `file.recovery.list`) or `close`; for `samples` `open` (with `name`) or `close`; for `crashed` (the start after a crash: `{crashed: [reports]}`) `report` (opens Report a Bug for the newest) or `close`; for `report_bug` (`{report_bug: draft}`) `set` (any of `title`, `observed`, `share_session`, `include_model`; replies with the draft) or `close` — the browser opens only from a click (docs/crash-reports.md) | answers the window's question (`ui.inspect`'s `prompt`) |
|
||||
| `ui.item` | `kind` (`body`, `surface`, or a definition kind as `ui.select` takes it, `datum`, `partition`), `name`, `action`: `edit`, `hide`, `show`, `isolate`, `show_all`, `delete`, or `activate`/`deactivate` with `step` | an item menu's entry, as a right click on the item and a click on the entry: runs the same command (`delete` opens the delete prompt, answered with `ui.prompt`) |
|
||||
| `ui.dialog` | `params?` (JSON object, fills the form), `use_selection?`, `run?`, `submit?`, `cancel?` | drives the open command form, in that order; `use_selection` is the form's Target row (see [Selection](#selection)); `run` returns the command's result and closes the form on success; `submit` is the form's OK button: a mesher that would replace a body's mesh first asks (`prompt` `replace_mesh`, with the question and what else goes: sets listing the old labels, solved results), and meshers run in the background (`busy`); a form opened by another form's **Create …** button (a reference field with nothing to pick) goes back to that form on `run` (with the new item picked) or `cancel` |
|
||||
| `ui.click` | `x`, `y` (screen points), `button?`: `left`/`right`/`middle`, `shift?`, `ctrl?`, `alt?`, `double?` | real pointer input; in the viewport a click selects what is under it (Shift adds, Ctrl/Cmd adds or removes, a click on nothing clears the selection), and a click on a results plot also probes the nearest node of the face under it (`solve.probe`; `ui.inspect` shows the values) |
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# Crash reports, the log file and Report a Bug
|
||||
|
||||
## Privacy
|
||||
|
||||
FieldCraft sends nothing anywhere on its own: no analytics, no background telemetry, no
|
||||
automatic crash upload. Crash reports and the log stay on this computer. The only way anything
|
||||
leaves it is **Help › Report a Bug** (or **Report It…** after a crash), which opens a GitHub issue
|
||||
form in your browser; you read it there and submit it, or not.
|
||||
|
||||
What a bug report carries:
|
||||
|
||||
| Always (you can edit it) | Only with **Share my session** | Only with **Include the model file** as well |
|
||||
|---|---|---|
|
||||
| the version and OS, what happened (the last error by default), for a crash its message, place and backtrace top; your home folder is shown as `~` | the commands that built the model (`fieldcraft-session.json`, replayable with `fieldcraft-cli run`); they can name your files | the model (`model.fieldcraft`), which you attach yourself |
|
||||
|
||||
The form shows exactly what will be filled in before you click **Open GitHub Issue**. GitHub
|
||||
refuses long new-issue links, so a session that does not fit goes out as a file instead: it is
|
||||
saved to `bug-reports/<time>/` in the data folder below and copied to the clipboard, and the issue
|
||||
text says to attach or paste it. The model is always a file you attach.
|
||||
|
||||
## Where things are
|
||||
|
||||
The app's data folder holds `recovery/`, `crashes/`, `logs/` and `bug-reports/`:
|
||||
|
||||
| System | Folder |
|
||||
|---|---|
|
||||
| macOS | `~/Library/Application Support/FieldCraft` |
|
||||
| Linux | `~/.local/share/fieldcraft` (or `$XDG_DATA_HOME/fieldcraft`) |
|
||||
| Windows | `%LOCALAPPDATA%\FieldCraft` |
|
||||
|
||||
Runs driven by automation (`--control`, or `CI` set) use `fieldcraft-automation/` in the
|
||||
temporary folder instead, so test runs never reach your folders. `FIELDCRAFT_CRASH_DIR` moves the
|
||||
crash folder, `FIELDCRAFT_RECOVERY_DIR` the recovery folder. The browser build keeps no crash
|
||||
folder and logs to the browser console.
|
||||
|
||||
## The log file
|
||||
|
||||
`logs/fieldcraft.log`: one line per record, `time LEVEL [pid] target: message`. Past 2 MB it
|
||||
becomes `fieldcraft.log.1` and a new one starts. Warnings and errors also go to the standard
|
||||
error stream.
|
||||
|
||||
## Crash reports
|
||||
|
||||
`crashes/<YYYYMMDD-HHMMSS>-<signature>/`:
|
||||
|
||||
- `report.json` (`"format": "fieldcraft-crash/1"`): `kind` (`command_panic`: a command hit an
|
||||
internal error, caught, the model left unchanged; `recovered_panic`: one caught inside a command;
|
||||
`panic`: an internal error outside commands; `unclean_exit`: the app ended without a clean exit
|
||||
— an abort, a stack overflow, a crash in a graphics driver, the process being killed — found at
|
||||
the next start), `message`, `location`, `thread`, `backtrace`, `app`, `system`, `command`,
|
||||
`recent_commands` (up to 32), `last_activity` (the last control request, such as
|
||||
`control ui.capture`), `base`, `count`, `first_seen`, `last_seen`, `notes`
|
||||
- `model.fieldcraft`: the model the replay starts from
|
||||
- `replay.json`: `{"commands": [{command, params}, …]}`
|
||||
- `log.txt`: the crashed run's lines of the log
|
||||
|
||||
The next start after a crash asks "FieldCraft closed unexpectedly": **Report It…** opens Report a
|
||||
Bug for that report.
|
||||
|
||||
### For agents
|
||||
|
||||
| From | List | One report | Replay |
|
||||
|---|---|---|---|
|
||||
| Command (MCP `execute`, control channel, scripts) | `diagnostics.crash_reports` | `diagnostics.crash_report {id}` | |
|
||||
| CLI | `fieldcraft-cli crashes [--json]` | `fieldcraft-cli crashes show <id>` | `fieldcraft-cli crashes replay <id>` |
|
||||
|
||||
`crashes replay` opens the report's model, runs its commands (files they write can only go to a
|
||||
scratch folder) and says whether the same internal error happens again. `crashes dir` prints the
|
||||
folder, `crashes clear [<id>]` deletes reports. `diagnostics.bug_report` returns the draft (link,
|
||||
fields, attachments) without opening anything; over the control channel `ui.start
|
||||
diagnostics.bug_report` opens the form, `ui.prompt {"answer": "set", …}` sets its fields, and
|
||||
`ui.inspect` shows the draft. Only a click opens the browser.
|
||||
|
||||
**Check that reporting works:** with `FIELDCRAFT_CRASH_TEST=1`, `diagnostics.crash_test {mode}`
|
||||
crashes on purpose: `panic`, `recovered` or `abort` (reported at the next start).
|
||||
|
||||
### How it stays cheap and small
|
||||
|
||||
The app keeps a journal of the window's top-level commands (`crashes/sessions/*.jsonl`, at most
|
||||
512 KB, two small writes per command that changes the model, none for commands that only read),
|
||||
restarted from each autosave and each model opened. A clean exit deletes it; it is locked while its
|
||||
app runs, so a journal nobody holds belongs to an app that died. A crash is identified by its
|
||||
place and message, numbers ignored: repeats only raise `count`. At most 5 new reports per run,
|
||||
20 reports, 100 MB, 90 days; a model over 20 MB is not copied. Tests, the CLI and the browser build
|
||||
never install the hook.
|
||||
|
||||
Adapted from SolidCraft's crash reports (MIT OR Apache-2.0, see ATTRIBUTION.md).
|
||||
Reference in new issue
Block a user