|
1 | | -# Tasks — preparing for the FEM work |
2 | | - |
3 | | -The executable breakdown sitting between `FEM.md` (the plan) and doing it. |
4 | | -`DIRECTION.md` holds the architectural position; the review that produced this |
5 | | -list found the two do not collide. |
6 | | - |
7 | | -## The review finding that matters |
8 | | - |
9 | | -The direction research landed on **keep the document as the artifact**, and |
10 | | -`FEM.md` §12.1 already assumes exactly that: a cache key over source-affecting |
11 | | -events, `sources_all` / `sensors_all` as the partition, `set_rollback` and |
12 | | -`undo` as free FEM navigation. Had the answer been code-as-truth, all of §12.1 |
13 | | -would need rewriting to a trace hash. It does not. |
14 | | - |
15 | | -**So the open direction question blocks nothing below.** One positive |
16 | | -interaction rather than a dependency: parameterised instancing would give FEM a |
17 | | -library of validated assemblies and sweeps over instance parameters. |
18 | | - |
19 | | -## Ordering |
20 | | - |
21 | | -- **C starts now** — no blockers at all; needs no solver and no studio change. |
22 | | -- **B starts now, in parallel** — the longest lead, and it is upstream review |
23 | | - time rather than ours. |
24 | | -- **A1 and A2 before any studio-side FEM UI.** A2's cost rises the longer it |
25 | | - waits. |
26 | | -- **D is independent**, and shrinks the maintenance surface before FEM adds to |
27 | | - it. |
| 1 | +# Tasks |
| 2 | + |
| 3 | +What to do next, ordered by what gates what. The reasoning behind each item |
| 4 | +lives in the plan it came from — this file stays thin enough to work from. |
| 5 | + |
| 6 | +| Question | Document | |
| 7 | +| --------------------------- | ---------------------------------------- | |
| 8 | +| What is this? | [README.md](README.md) | |
| 9 | +| What is built? | [CONTINUE.md](CONTINUE.md) | |
| 10 | +| **What do I do next?** | **this file** | |
| 11 | +| Why is it going that way? | [docs/direction.md](docs/direction.md) | |
| 12 | +| How does instancing work? | [docs/instancing.md](docs/instancing.md) | |
| 13 | +| How does FEM validation go? | [docs/fem.md](docs/fem.md) | |
| 14 | + |
| 15 | +**Track F (foundation) is primary.** It is what studio _is_ under the |
| 16 | +positioning in `docs/direction.md` §1, and everything else is an application of |
| 17 | +it. M runs in parallel because its lead time is upstream review rather than |
| 18 | +ours. V is downstream of F except for V1, which is orthogonal — a different repo |
| 19 | +that touches none of this. |
28 | 20 |
|
29 | 21 | --- |
30 | 22 |
|
31 | | -## Group A — studio work the FEM plan needs |
32 | | - |
33 | | -### A1 — Jobs in the RPC protocol |
| 23 | +## Track F — Foundation |
34 | 24 |
|
35 | | -**What.** Worker subprocess, server-initiated notifications, a job id space, |
36 | | -cancellation. |
| 25 | +### F1 — Kill the round trip |
37 | 26 |
|
38 | | -**Why.** `serve()` is a strictly serial blocking loop: one line in, one line |
39 | | -out, in order; every write echoes a request `id`, so there are no |
40 | | -server-initiated messages; and there is no `threading`, `asyncio` or |
41 | | -`subprocess` anywhere in the engine. A solve through it freezes the scene tree, |
42 | | -the inspector, the sliders and the 3D view for minutes. It also pays for |
43 | | -something already wanted — mesh reorientation blocks the same loop at 16 s for |
44 | | -20k faces. |
45 | | - |
46 | | -**Done when.** A long call runs without blocking any other request, reports |
47 | | -progress, and can be cancelled; the existing test suite still passes. |
| 27 | +**What.** `parse_script` goes, with the matched emitter/parser idiom pairs |
| 28 | +(`_mirror`, `_superquadric`, the `for i in range(1, n)` loop shape, the |
| 29 | +`_name_copy` line emitted and then skipped). `to_script` becomes export and |
| 30 | +recording only. |
48 | 31 |
|
49 | | -**Blocks.** `FEM.md` M7, and all three workflows in §12. |
| 32 | +**Why.** `docs/direction.md` §2 and §5.1. Every project in its §4 table |
| 33 | +generates one-way. This is a deletion with a known shape and it shrinks the |
| 34 | +surface F2 has to work in. |
50 | 35 |
|
51 | | -### A2 — Refusal-first job API |
| 36 | +**The decision inside it.** The script tab stops being applied on save. That is |
| 37 | +a UI change, not only a deletion, and it should be decided rather than |
| 38 | +discovered. `load_script` and `apply_script` keep working by execution, which is |
| 39 | +already their fallback. |
52 | 40 |
|
53 | | -**What.** The job API **errors**, rather than warns, on: a residual without |
54 | | -convergence metadata, a solve past budget, and a comparison mixing `ideal` and |
55 | | -`physical` mode. |
| 41 | +**Done when.** The round trip is gone, import still works by execution, and the |
| 42 | +two-tier cliff is unreachable. |
56 | 43 |
|
57 | | -**Why.** §13.5. A human glances at a "provisional" badge; an agent ignores a |
58 | | -warning field and hill-climbs on mesh noise, confidently, for hours. And the |
59 | | -guardrail cannot live in a skill file — the README's _"there is no second |
60 | | -validation layer"_ settles where it goes. Cheap now, expensive once callers |
61 | | -depend on permissive behaviour. |
| 44 | +### F2 — Parameterised instancing |
62 | 45 |
|
63 | | -**Done when.** Each of the three refusals has a test asserting an error rather |
64 | | -than a warning. |
| 46 | +**What.** A definition document with declared parameters, and an `instance` |
| 47 | +event that references it with arguments. Design in |
| 48 | +[docs/instancing.md](docs/instancing.md). |
65 | 49 |
|
66 | | -### A3 — Source/probe hash partition |
| 50 | +**Why.** The missing reuse feature. All four wanted units of reuse are |
| 51 | +composition units, and a structured format composes if it has instancing plus |
| 52 | +exported parameters. |
67 | 53 |
|
68 | | -**What.** A content hash over field-affecting events only — magnets, currents, |
69 | | -anything with μr ≠ 1, and the transforms carrying them — excluding sensors and |
70 | | -pixel grids. |
| 54 | +**Design first.** Six open questions in `docs/instancing.md` §5 — version |
| 55 | +pinning, nested instances, composition with patterns, editing through an |
| 56 | +instance, whether a document's variables are its signature, and whether |
| 57 | +same-document definitions are worth having. This is the highest-design-risk item |
| 58 | +in the plan and the most tempting to start coding. |
71 | 59 |
|
72 | | -**Why.** Solve once, probe forever. Moving a sensor must not invalidate a solve. |
| 60 | +**Done when.** Design questions closed, then: an instance resolves in `_build`, |
| 61 | +`to_script` emits a call, a definition round-trips by hash, and a pattern of |
| 62 | +instances works. |
73 | 63 |
|
74 | | -**Done when.** Moving a sensor leaves the hash unchanged; changing a magnet |
75 | | -changes it; and undoing back to a previous state reproduces that state's earlier |
76 | | -hash exactly. The last property is what turns history navigation into free FEM |
77 | | -navigation. |
| 64 | +### F3 — GUI as parameter binder |
78 | 65 |
|
79 | | -### A4 — Units |
| 66 | +**What.** Introspect a definition's parameters, render widgets, rebuild, draw. |
80 | 67 |
|
81 | | -**What.** A unit _kind_ on a variable, beside `integer`; one model unit per |
82 | | -document; emitters convert at the boundary; the UI formats. |
| 68 | +**Depends on** F2 — there are no parameters to bind until definitions exist. |
83 | 69 |
|
84 | | -**Why.** AEDT wants `"5mm"`, solvers want consistent SI, and `FEM.md` §6 chose |
85 | | -metadata over unit-carrying values so no document migrates. Cheaper than that |
86 | | -section implies: `_PARAM_UNITS` already sits beside `_PARAM_ATTRS`. |
| 70 | +**Why.** `docs/direction.md` §5.3. The sync surface shrinks to "parameters → |
| 71 | +widgets", which cannot drift. Proven shape: OpenSCAD Customizer, Storybook |
| 72 | +controls, Streamlit. |
87 | 73 |
|
88 | | -**Done when.** Every existing document loads unchanged and the script round-trip |
89 | | -is stable. |
| 74 | +### F4 — Grow `expressions.py` toward Starlark |
90 | 75 |
|
91 | | -**Blocks.** M6. |
| 76 | +**Deliberately not scheduled.** `docs/direction.md` §5.4 — the right answer and |
| 77 | +the expensive one. Starlark took Google eight years. Nothing forces the choice |
| 78 | +yet. |
92 | 79 |
|
93 | 80 | --- |
94 | 81 |
|
95 | | -## Group B — magpylib core (start now; upstream lead time is the constraint) |
| 82 | +## Track M — magpylib core (start now; the constraint is upstream review) |
96 | 83 |
|
97 | | -### B1 — `susceptibility` / μr as a documented property |
| 84 | +### M1 — `susceptibility` / μr as a documented property |
98 | 85 |
|
99 | | -**What.** A real property on magnets, rather than the attribute |
100 | | -`magpylib-material-response` monkey-attaches and searches parents for. |
101 | | - |
102 | | -**Why.** It is the `physical`-mode input. Without a shared convention the |
103 | | -exporter invents its own home for μr and it differs from material-response's — |
104 | | -at which point tier 1's three-way comparison silently compares magnets that are |
105 | | -**not the same magnet**, and the discrepancy looks like physics. |
| 86 | +**Why.** It is the `physical`-mode input (`docs/fem.md` §3.2). Without a shared |
| 87 | +convention the exporter invents its own home for μr and it differs from |
| 88 | +`magpylib-material-response`'s — at which point tier 1's three-way comparison |
| 89 | +silently compares magnets that are **not the same magnet**, and the discrepancy |
| 90 | +looks like physics. |
106 | 91 |
|
107 | 92 | **Done when.** Merged upstream, or a documented studio-side convention exists |
108 | 93 | that material-response also reads. |
109 | 94 |
|
110 | | -### B2 — Public constructor-parameter introspection |
111 | | - |
112 | | -**What.** One accessor upstream replacing studio's hardcoded `_PARAM_ATTRS`. |
| 95 | +### M2 — Public constructor-parameter introspection |
113 | 96 |
|
114 | | -**Why.** The physics layer needs the identical table, so a new magnet class in |
115 | | -core would fall silently through **both** copies. |
| 97 | +**Why.** Studio hardcodes `_PARAM_ATTRS`; the physics layer (V1) needs the |
| 98 | +identical table, so a new magnet class in core would fall silently through |
| 99 | +**both** copies. |
116 | 100 |
|
117 | 101 | **Done when.** `get_params` reads it instead of the literal tuple. |
118 | 102 |
|
119 | 103 | --- |
120 | 104 |
|
121 | | -## Group C — the physics layer (unblocked, start today) |
122 | | - |
123 | | -### C1 — Package skeleton and the home decision |
| 105 | +## Track V — Validation |
124 | 106 |
|
125 | | -**What.** Settle `FEM.md` §4's split — physics on magpylib objects in a |
126 | | -standalone package, parametrics on the document in studio — and create it. |
| 107 | +Full plan and its gates in [docs/fem.md](docs/fem.md). Only V1 is orthogonal to |
| 108 | +Track F; the rest build on the foundation and should follow it. |
127 | 109 |
|
128 | | -**Done when.** It imports, has CI, and depends only on magpylib. |
| 110 | +### V1 — The physics layer (orthogonal — start any time) |
129 | 111 |
|
130 | | -### C2 — Conventions module |
| 112 | +Package skeleton and the §4 home decision · conventions module (§3.1's verified |
| 113 | +table, including the two off-by-two traps) · the required `ideal`/`physical` |
| 114 | +mode switch (§3.2) · solver-free conformance: the `getJ` occupancy test plus the |
| 115 | +volume/centroid check. |
131 | 116 |
|
132 | | -**What.** Pose → euler, J → (Hc, μr, world direction), geometry-parameter |
133 | | -normalisation. Pure functions, no solver, no vendor, no document. |
| 117 | +**Why it can run alongside F.** Different repo, magpylib objects only, no |
| 118 | +solver, no studio change, no open decision. Reaches `docs/fem.md`'s **G1** with |
| 119 | +nothing installed. |
134 | 120 |
|
135 | | -**Why.** `FEM.md` §3.1's table, verified against a live checkout — including the |
136 | | -two off-by-two traps: `Cylinder` and `Sphere` take **diameter**, and `Cuboid` |
137 | | -takes **full** edge lengths while `create_box` takes a corner. |
| 121 | +### V2 — Units |
138 | 122 |
|
139 | | -**Done when.** Every row of that table is pinned by a test. |
| 123 | +Unit _kind_ on a variable beside `integer`; one model unit per document; |
| 124 | +emitters convert at the boundary. Cheaper than `docs/fem.md` §6 implies — |
| 125 | +`_PARAM_UNITS` already sits beside `_PARAM_ATTRS`. **Interacts with F2**: a |
| 126 | +definition's parameters want units for the same reason its variables do. |
140 | 127 |
|
141 | | -### C3 — The ideal / physical switch |
| 128 | +### V3 — Jobs in the RPC protocol |
142 | 129 |
|
143 | | -**What.** A required mode argument with no default. |
| 130 | +Worker subprocess, server-initiated notifications, a job id space, cancellation. |
| 131 | +`serve()` is a strictly serial blocking loop with no threading, asyncio or |
| 132 | +subprocess anywhere in the engine, so a solve through it freezes the whole UI |
| 133 | +for minutes. Also pays for mesh reorientation blocking the same loop at 16 s. |
144 | 134 |
|
145 | | -**Why.** §3.2. A μr = 1 magnet and a μr = 1.05 magnet with the same Br are |
146 | | -different magnets. `ideal` validates our translation; `physical` measures the |
147 | | -modelling error. Conflating them yields a comparison that means nothing while |
148 | | -looking rigorous. |
| 135 | +### V4 — Refusal-first job API |
149 | 136 |
|
150 | | -**Done when.** No call site can omit it. |
| 137 | +Errors, not warnings, on: a residual without convergence metadata, a solve past |
| 138 | +budget, a comparison mixing `ideal` and `physical`. `docs/fem.md` §13.5 — an |
| 139 | +agent ignores a warning field and hill-climbs on mesh noise. **Cost rises the |
| 140 | +longer callers depend on permissive behaviour**, so decide the shape early even |
| 141 | +if the work lands late. |
151 | 142 |
|
152 | | -### C4 — Solver-free conformance tests |
| 143 | +### V5 — Source/probe hash partition |
153 | 144 |
|
154 | | -**What.** The `getJ` occupancy test, plus the volume/centroid check beside it. |
155 | | - |
156 | | -**Why.** Catches centre-vs-corner, diameter-vs-radius, degrees-vs-radians, |
157 | | -local-vs-world polarisation and a wrong Euler convention — with **nothing |
158 | | -installed**. |
159 | | - |
160 | | -**Done when.** Green for `Cuboid`, `Cylinder`, `Sphere` and `CylinderSegment` |
161 | | -against a pure-Python membership evaluator. This is `FEM.md`'s **G1**. |
| 145 | +A content hash over field-affecting events only, excluding sensors and pixel |
| 146 | +grids. Solve once, probe forever. Undo back to a previous state must reproduce |
| 147 | +that state's earlier hash — that property is what turns history navigation into |
| 148 | +free FEM navigation. |
162 | 149 |
|
163 | 150 | --- |
164 | 151 |
|
165 | | -## Group D — drag reduction |
166 | | - |
167 | | -### D1 — Kill `parse_script`; `to_script` becomes export only |
168 | | - |
169 | | -**What.** Remove the read-back path and the matched emitter/parser idiom pairs |
170 | | -(`_mirror`, `_superquadric`, the `for i in range(1, n)` loop shape, the |
171 | | -`_name_copy` line that is emitted and then skipped). |
172 | | - |
173 | | -**Why.** `DIRECTION.md` §2's cliff and §5.1, and every project in its §4 table |
174 | | -generating one-way. Shrink the maintenance surface before FEM adds to it. |
175 | | - |
176 | | -**Careful.** `load_script`, `apply_script` and the script tab depend on it. The |
177 | | -script tab stops being applied on save — that is a UI change, not only a |
178 | | -deletion, and it needs deciding rather than discovering. |
179 | | - |
180 | | -**Done when.** The round trip is gone, import still works by execution, and the |
181 | | -two-tier cliff is no longer reachable. |
182 | | - |
183 | | -### D2 — ~~Rewrite `DIRECTION.md`~~ **done** |
184 | | - |
185 | | -Rewritten around _data is the artifact / one-way generation / parameterised |
186 | | -instancing_, with code-as-truth kept as §7's recorded-and-rejected alternative |
187 | | -and §4 carrying the Bazel, Jsonnet, Onshape, Godot and OpenSCAD evidence. |
188 | | - |
189 | | ---- |
| 152 | +## Not scheduled, and why |
190 | 153 |
|
191 | | -## Not started, and why |
192 | | - |
193 | | -- **Anything downstream of `FEM.md`'s G3 spike** — the solver is deliberately |
194 | | - undecided until it is measured. |
195 | | -- **Parameterised instancing** (`DIRECTION.md` §5.2) — the missing reuse |
196 | | - feature, and the answer to all four units of reuse. Agreed in principle, not |
197 | | - scoped, and not a FEM dependency, so it is deliberately not in the groups |
198 | | - above. |
199 | | -- **Growing `expressions.py` toward Starlark** (`DIRECTION.md` §5.4) — the right |
200 | | - answer and the expensive one. Nothing forces the choice yet. |
201 | | -- **The agent skill (M9)** — a skill may only describe an API that exists. |
| 154 | +- **Anything downstream of `docs/fem.md`'s G3 spike** — the solver is |
| 155 | + deliberately undecided until it is measured. |
| 156 | +- **F4** — see above. |
| 157 | +- **The agent skill** (`docs/fem.md` M9) — a skill may only describe an API that |
| 158 | + exists. |
0 commit comments