Closed bug report

create-chip output cannot be thumbnailed: metadata carrier at z=-999 inflates the bbox to 1 metre

Ray · 1mo ago ·closed by Ray

The STEP engine cannot thumbnail its own /create-chip output. The PNG comes back as an essentially empty frame with the chip a single dark speck near the top edge — and it comes back as a successful job, 2 KB, no error, no warning.

Cause

/create-chip carries its annotation JSON through STEP export by parking a 1 µm cube at z = -999 mm and naming the product chipsmith_metadata {…}:

api/create_chip.py:724

tiny = BRepPrimAPI_MakeBox(gp_Pnt(0, 0, -999), 0.001, 0.001, 0.001).Shape()
label = shape_tool.AddShape(tiny)
TDataStd_Name.Set_s(label, TCES(f"chipsmith_metadata {blob}"))

The mechanism itself is sound and deliberate — XCAF attributes do not survive STEP export, the product name does, and step_meta.py reads it back. api/create_footprint.py:379 does the same.

The problem is that nothing downstream knows to ignore it. Grepping chipsmith_metadata finds only the two writers and step_meta.py. None of the three consumer paths filter it:

path filters the marker?
api/step_to_thumbnail.py no
api/step_to_gltf.py no
api/occt/occt_outline.py no

So every consumer sees a part whose bounding box is 1 metre tall.

Evidence

Emitting the shipped fixture test-chip3d.json and reading the result back, per solid:

solid  0   z [   0.1800 ..  1.9300]   body
solid  1..8 z [  -0.0000 ..  0.3300]  leads
solid  9   z [   1.8800 ..  1.9300]   pin-1 dot
solid 10   z [-999.0000 ..-998.9990]  <-- metadata carrier

Whole-shape bbox z = [-999.0000001 .. 1.9300001] for a part 1.93 mm tall.

Thumbnailing that STEP through POST /thumbnail fits the camera to the full bbox, so the 5 mm chip occupies well under a pixel. Attached.

Converting it through POST /convert keeps the carrier as an 11th mesh, and the quantized position accessors span the full int16 range across that 1 m extent, so the whole chip is squeezed onto a grid sized for a metre rather than for a few millimetres.

Suggested direction

Skip products whose name starts with chipsmith_metadata when building renderable geometry — one shared helper used by the thumbnail, glTF and outline paths, rather than three copies. Worth deciding at the same time whether the carrier should move to somewhere less hostile than z = -999 (a point at the part origin would still round-trip the name and would not distort any bbox), though that changes emitted STEPs and needs its own thought about consumers that already read it.

Found while running the standby-container endpoint parity diff. Both containers behave identically, so this is not a standby regression — it is pre-existing on both.

chip-thumb

1 Reply

Ray · 1mo ago

Fixed and deployed. 1.3.7 (748b475e), live.

The carrier mechanism itself was never the problem — a product name is the one thing that survives a STEP export, so smuggling the annotation JSON out that way is sound. Parking it at z = -999 mm was the problem, and the fact that nothing downstream knew it existed: grepping chipsmith_metadata finds only the two writers and the one reader.

Two defences, because they cover different files.

New emissions anchor the carrier at the minimum corner of the geometry it ships with, so it provably cannot enlarge the box. That fixes every consumer at once — including /outline, which reads STEP without XCAF and so cannot see product names at all.

z-extent of the emitted chip
before [-999.0000001, 1.9300001]
after [-2e-07, 1.9300001]

Volume, area, centroid and the solid/face/edge/vertex counts are unchanged.

Consumers that do have the names now leave the carrier out of the box they fit to, which is what rescues the STEPs already written.

Verified on production:

case result
chip emitted by production, then thumbnailed renders the chip, 7464 bytes
the old z = -999 chip, thumbnailed renders the chip, 7408 bytes (was 2003, an empty tile)
a part with no carrier byte-identical, sha 5fe409ff

Two traps worth recording, both found by testing rather than by reading the code. The carrier is a component of the assembly, not a free shape, so my first filter — over free shapes — changed precisely nothing. And inside an assembly the component is named for its label path (=>[0:1:1:12]) while the real product name sits on the label it refers to, so testing the component's own name never matches either. Then, even with the box correct, the render was still empty: the camera used a plain FitAll, which fits whatever is displayed, not the box you computed. The carrier is still drawn — excluding it would mean rebuilding the assembly's colour presentation per component — but the view now fits the carrier-free box explicitly. At 1 µm it costs nothing to draw.

Incidentally the stale box also made the meshing deflection, which is derived from the box diagonal, about a thousand times too coarse on these parts.

One thing this does not cover. /outline and /convert on STEPs emitted before 1.3.7 still see the old box, because neither can read product names — outline doesn't load XCAF, and the glTF writer walks the whole document. Re-emitting those parts fixes them, and anything emitted from 1.3.7 on is correct by construction.

PR: https://github.com/adom-inc/service-occt/pull/11 — api/test_metadata_carrier.py pins the anchor, that anchoring there cannot grow the box, that the carrier is found through its reference rather than its own name, and that a part without one is untouched.

Log in to reply.