beamsplitter deletes hand-written declarations that AGENTS.md tells agents to regenerate
- Dominant language
- C++
- Stars
- 20.5k
- Forks
- 2.3k
- Avg merge
- 2d 16h
- Merged PRs (30d)
- 74
Description
`AGENTS.md` points agents at `skills/bindings_synchronization/SKILL.md`, which says:
> If you modify options structs defined in `filament/include/filament/Options.h`, you must run the beamsplitter tool: `cd tools/beamsplitter && go run .`
Following that instruction on a clean checkout deletes 328 lines of public TypeScript:
```
$ git clone --depth 1 https://github.com/google/filament
$ cd tools/beamsplitter && go run .
$ git diff --stat
web/filament-js/filament.d.ts | 328 ---------------------
android/.../filament/View.java | 2 -
```
### The TypeScript half
`filament.d.ts:1498` says `// The remainder of this file is generated by beamsplitter`. That is true up to line 2249. Lines 2250-2577 are hand-written and hold 30 exports: `Camutils$Mode`, `Camutils$Manipulator`, `viewer$ToneMapping`, `ViewSettings`, `AutomationEngine`, `ViewerGui` and the rest.
`EditTypeScript` in `tools/beamsplitter/emitters/javascript.go:105-118` reads up to the marker, breaks, then calls `os.Create`, which truncates. Whatever followed the generated section is gone.
The hand-written tail arrived after the marker convention did: #9997 (2026-05-22) added the Camutils bindings and #10065 (2026-05-28) the viewer ones. `AGENTS.md` and the skill came later, in #10093 (2026-06-10) -- by then the file could no longer be regenerated safely.
This is not cosmetic: `Camutils$Manipulator` is registered in embind at `jsbindings.cpp:2892`, and `web/filament-js/package.json` declares `"types": "filament.d.ts"`. Losing those lines breaks typing for anyone consuming the npm package.
### The Java half
`View.java` loses two hand-added `@Deprecated` annotations, on `filterWidth` and `minVarianceScale`. Both fields carry `/** @deprecated has no effect. */` in `Options.h`, so the docblock says deprecated and the compiler does not.
### Nothing catches this
`grep -rn beamsplitter .github/` is empty -- no CI job runs the generator, so a regenerated tree is never compared against the committed one.
### Fix
I have a patch ready and will send it if you want it this way:
- `javascript.go`: a paired end marker. Everything after `// End of beamsplitter-generated code` is preserved across runs. A file without the marker behaves exactly as before, so nothing else in the tree changes.
- `java.go`: `getFieldAnnotation` emits `@Deprecated` when the field's C++ comment contains `@deprecated`, instead of the annotation being re-added by hand after every run.
With both, `go run .` on a clean tree touches nothing except the one marker line, and running it twice is a no-op.
Two things I did not touch, in case they matter to you:
- `Settings_generated.cpp` and `jsbindings_generated.cpp` also come back changed, but only by `#include` ordering -- those generated files appear to be formatted after generation. Different problem.
- the skill also states that every method bound in `jsbindings.cpp` should be declared in `filament.d.ts`. Comparing the two turns up 14 that are not, among them `Skybox::getIntensity`, `View::getAntiAliasing` and `EntityManager::destroy`. Can open that separately if it is useful.
Contributor guide
Research direction
Start with tools/beamsplitter/emitters/javascript.go:105-118 and java.go, then run `cd tools/beamsplitter && go run .` on a clean checkout to reproduce the deletions. Preserve content after the TypeScript end marker and emit `@Deprecated` for fields whose C++ comments contain `@deprecated`; rerunning the generator should leave the tree unchanged apart from the intended marker behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, go, java, typescript
- Domain
- build-system, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 62/100