WillTools 2026-09-09 -- clean snapshot of the development repo for review
ci / test (push) Successful in 6m14s
ci / test (push) Successful in 6m14s
History-free snapshot of the private development repository at 77a82eb. Code, docs and the public catalogue only: no plant or job knowledge layers, no client, job or producer names (tools/scrub.py clean against the widened term list; a second word-level grep clean). The intro deck is left out because its slide images cannot be checked for job drawings.
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
# Snapshot tool — how it works, and how to run it
|
||||
|
||||
The snapshot tool makes a **timestamped, detached copy of the model**, opens a
|
||||
Revit onto that copy on its own (nobody in front of it), runs a batch inside it,
|
||||
and closes — so the engineer's own model and session are never tied up.
|
||||
|
||||
It is two halves:
|
||||
|
||||
1. **`SnapshotClose` pushbutton** (Tools panel, runs *inside* the live Revit).
|
||||
Its one irreplaceable job is **Phase A: hand over the model's IDENTITY.**
|
||||
Only the open document can cheaply report a cloud model's **region + GUIDs**,
|
||||
and without those nothing else can find the model again. Phase A also indexes
|
||||
the model as it stands (this is where the reinforce feature registry is
|
||||
refreshed) and journals what it did. It then writes a **request file** (the
|
||||
cached identity) and **spawns the detached host cycle** — it does *not* make
|
||||
the copy itself.
|
||||
2. **`tools/snapshot_cycle.py`** (plain host CPython, detached — Claude can start
|
||||
it, no Revit needs to be open in front of anyone). Five steps:
|
||||
`DETACH → close-sandbox → open-sandbox → run batch → CLOSE`, each journalled.
|
||||
|
||||
## Why a copy is made by SaveAs, not "Detach from Central"
|
||||
|
||||
A **cloud** model cannot be opened detached: any `DetachFromCentralOption` on a
|
||||
cloud `ModelPath` raises *"Detach option is not valid for cloud model,"* Autodesk
|
||||
says **SaveAs is the way**, and the UI greys the checkbox out. So the cycle's
|
||||
"detach" is a **SaveAs to a timestamped copy** under `snapshot.detached_dir`.
|
||||
|
||||
## The one rule that makes it usable: identity is captured once, from a live press
|
||||
|
||||
A cloud model is **only identifiable from a session that has it open** — the
|
||||
region and GUIDs live in the open document. So:
|
||||
|
||||
- **You must press `SnapshotClose` once from a live session that has the model
|
||||
open.** That press captures the cloud GUIDs and caches them (the request file).
|
||||
- **After that, the cycle can run with NO live session** — it reopens the model
|
||||
from the cached GUIDs. This is the path to **auto-running snapshots** with
|
||||
nobody in front of Revit: identity cached once → every later cycle is headless.
|
||||
|
||||
If the identity was never cached (e.g. the press was interrupted), the cycle
|
||||
**cannot start** and says so — a cloud model with only a display path and no
|
||||
GUIDs can't be located. Fix: open the model and press `SnapshotClose` once more.
|
||||
|
||||
## Running the cycle by hand (after the identity is cached)
|
||||
|
||||
```
|
||||
python tools/snapshot_cycle.py \
|
||||
--fresh-detach \ # write a new timestamped copy first
|
||||
--job "<job folder under WILLTOOLS_JOBS>" \
|
||||
--request <the request file the button cached> \ # OR --source <path>, OR
|
||||
# snapshot.source_cloud in job knowledge
|
||||
--revit 2024 \ # PIN the year — the machine has several Revits;
|
||||
# omitting this is what silently no-fired before
|
||||
--revit-exe "C:/Program Files/Autodesk/Revit 2024/Revit.exe" \
|
||||
--pyrevit "C:/Users/<you>/AppData/Roaming/pyRevit-Master/bin/pyrevit.exe" \
|
||||
--dry-run # print the whole plan and do NOTHING — always dry-run first
|
||||
```
|
||||
|
||||
Drop `--dry-run` to actually run. Useful flags: `--run "<host cmd>"` (the batch,
|
||||
default `snapshot.batch`), `--keep-open`, `--wait-minutes`, `--use <file>` (skip
|
||||
the detach and cycle onto an existing copy).
|
||||
|
||||
### Job-knowledge keys the cycle reads (`WILLTOOLS_JOBS/<job>/knowledge.yaml`)
|
||||
|
||||
```
|
||||
snapshot:
|
||||
detached_dir: <where timestamped copies are written> # REQUIRED, or --detached-dir
|
||||
source_cloud: {region: ..., project_guid: ..., model_guid: ...} # optional: lets the
|
||||
# cycle run with no live press ever, once you have the GUIDs
|
||||
```
|
||||
|
||||
## Journal — every run is recorded, silence is never success
|
||||
|
||||
`<job>/snapshots.jsonl` gets a line on **every** exit path (this was a real
|
||||
bug once: a day the cycle never fired looked exactly like a day it worked, so a
|
||||
missing run is now reported in capitals at the top of the report). Phase A also
|
||||
journals `phase-a-snapshot` (piece count, timing, provenance) and
|
||||
`phase-a-update-stats` (the reinforce feature-ID diff).
|
||||
|
||||
## Known failure modes
|
||||
|
||||
- **`snapshot.detached_dir is not set`** → set it in job knowledge, or `--detached-dir`.
|
||||
- **"a fresh detach needs to know WHICH model to copy"** → identity not cached;
|
||||
press `SnapshotClose` once from the live model (see the identity rule above).
|
||||
- **Silent no-fire in ~16 s** → historically a missing `--revit=<year>` with
|
||||
several Revit versions installed; **always pin `--revit`.** The cycle now
|
||||
resolves the year from the exe and journals on every exit, so this is loud now.
|
||||
|
||||
## Toward fully automatic
|
||||
|
||||
Once `snapshot.source_cloud` (the GUIDs) is stored in the job knowledge — captured
|
||||
once from a live press — the cycle needs no Revit open in front of anyone and no
|
||||
request file, so it can be scheduled/auto-run headlessly. That is the intended
|
||||
end state.
|
||||
Reference in New Issue
Block a user