Skip to content

H-6456: Update hCore (2026-05)#134

Draft
judeallred wants to merge 155 commits intomainfrom
modernization
Draft

H-6456: Update hCore (2026-05)#134
judeallred wants to merge 155 commits intomainfrom
modernization

Conversation

@judeallred
Copy link
Copy Markdown
Collaborator

Creating a draft PR based on my fork from https://github.com/judeallred/hashintel-labs.

I expect to have to do a fair bit of iteration to resolve the merge conflicts.

Comment thread .github/workflows/e2e.yml Fixed
Comment on lines +26 to +53
name: Lint, Test & Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24"
cache: yarn
cache-dependency-path: apps/sim-core/yarn.lock

- name: Install dependencies
working-directory: apps/sim-core
run: yarn install --frozen-lockfile --ignore-scripts

- name: ESLint
run: npx eslint --quiet "src/**/*.{ts,tsx}"

- name: TypeScript
run: npx tsc --noEmit

- name: Unit tests
run: npx jest --forceExit --testPathIgnorePatterns "/node_modules/|/tests/e2e/"

- name: Production build
run: yarn build
// >>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:README.md
// Try it on https://regex101.com/r/aw03un/1
const GIT_CONFLICT_MARKERS_REGEX =
/(^<<<<<<< \w+:\w+.+\s)((?:.|\s)*?)\s(=======\s)(^(?:.|\s)*?)(^>>>>>>> \w+:\w+.+\s)/gm;
// >>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:README.md
// Try it on https://regex101.com/r/aw03un/1
const GIT_CONFLICT_MARKERS_REGEX =
/(^<<<<<<< \w+:\w+.+\s)((?:.|\s)*?)\s(=======\s)(^(?:.|\s)*?)(^>>>>>>> \w+:\w+.+\s)/gm;

export const yieldToBrowser = () =>
new Promise<void>((resolve) => {
const uid = Math.random();
Comment on lines +188 to +201
<div className="ProcessChart">
<div className="ProcessChart__Header">
<h3>Process Model Chart</h3>

<div className="ProcessChart__ChartSelect">
{isDraft && <span className="ProcessChart__DraftLabel">DRAFT</span>}

<select
onChange={(event) => setProcessChart(event.target.value)}
value={processChartOption}
>
<option value={newProcessChartValue}>New process</option>
{chartFiles.map((file) => (
<option key={file.path.name} value={file.path.name}>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
petrinaut-hazel Error Error May 1, 2026 5:55pm

judeallred and others added 25 commits May 1, 2026 13:23
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
Co-authored-by: David @ HASH <6226576+nonparibus@users.noreply.github.com>
- This is so that environments with an empty 'localstorage' don't get a blank page.
- Also hide the 'my projects' link to the /user page
- limits top-level folders to our approved list of src, data, views, dependencies
- omits hidden "." files from the import
- omits files of unsupported types (as enforced by the preexisting file parsing code)
- strips empty top-level folders from the import
- The resource browser in the left panel
- The 'cloud' options in the experiment dialog
judeallred and others added 23 commits May 1, 2026 13:25
Three root causes prevented these tests from passing:

1. Helper timeouts too short: stepSimulation/playSimulation/resetSimulation waited only 10s for WASM init; increased to 30s to match actual load times.

2. Missing Symbol.observable on stores: The analysis middleware uses RxJS fromStore() which requires Symbol.observable. Added the protocol to both appBridge and reduxCompat createStore, fixing the crash when clicking the Analysis tab.

3. No file persistence to localStorage: Edits in Monaco were never written back to localStorage, so changes were lost on refresh. Added debounced auto-persist in StoreSync that writes the current project + files to localStorage when filesState changes.

Also implemented two stub persistence tests with real assertions: project-changes-persist-after-refresh now edits init.js and verifies the marker survives reload, and custom-project-loadable verifies the project has files loaded from localStorage.

Made-with: Cursor
Major upgrade spanning 27 minor versions. Replace vite-plugin-monaco-editor-esm
with Vite-native worker config. Fix breaking API changes (getModeId,
cursorSmoothCaretAnimation, forceTokenization, addDynamicKeybinding).
Enable bracket pair colorization, sticky scroll, inlay hints.
All 78 E2E tests pass with zero console errors.

Made-with: Cursor
Move example .zip files from apps/sim-core/example_projects/ into
packages/core/public/example_projects/ so Vite serves them as static
assets. Add a manifest.json describing all 13 examples.

Architecture changes:
- Delete builtinSimulations.ts (177-line inline data blob)
- bootstrapQuery now fetches manifest.json to populate examples list
- DefaultProject auto-imports the default example zip on first visit
  (instead of reading pre-seeded localStorage data)
- Example projects menu items fetch+import zips on click instead of
  navigating to hardcoded routes
- Extract parseZipToProject() and fetchAndParseProject() as reusable
  functions from the import hook
- Add useImportProjectFromUrl hook for programmatic zip imports

Also removes the redundant generated wildfires-regrowth.zip and updates
E2E test helpers, ARCHITECTURE.md, and README.md.

Made-with: Cursor
…intercept

- Add --use-gl=angle --use-angle=swiftshader to Playwright Chromium config
  to fix WebGL context creation failures in headless mode
- Add WebGL error strings to smoke test console error filter (pre-existing)
- Rewrite example-projects.spec.ts to use Playwright route interception:
  intercepts manifest.json to set each example as default, so the normal
  auto-import flow tests each zip in isolation (avoids "Data missing for
  run" error from same-session project switching)
- All 13 example projects pass: load, render viewer, and step simulation
- Update TODO.md: add Phase 5b (example projects architecture), update
  test table, bump last-updated date to March 2026

E2E results: 75 passed, 3 flaky (pass on retry), 10 pre-existing failures

Made-with: Cursor
- Restore wildfires-regrowth.zip from git history (was incorrectly
  deleted during the zip-based architecture migration)
- Add wildfires-regrowth to manifest.json as the default example
  (matches original behavior where wildfires was the default simulation)
- Move default flag from ant-foraging to wildfires-regrowth
- Add E2E test verifying the File > Example projects menu lists all 14
  examples from the manifest
- All 15 example project tests pass (14 load+step + 1 menu verification)

Made-with: Cursor
When switching projects, the simulator store resets simulationData to {}
before React unmounts ActivityHistorySingleRun/ExperimentGroup components.
useSyncExternalStore fires getSnapshot synchronously on the still-mounted
components, whose selectors threw on missing run data, triggering the
error boundary.

Fix: return null from stale-data selectors instead of throwing, and
render nothing while data is missing. All hooks remain unconditional
to satisfy React's rules of hooks.

Includes E2E test that reproduces the exact user flow (load example A,
switch to example B via File menu) and verifies no crash.

Made-with: Cursor
The root cause of 8/14 example project failures was in the WASM engine's
initial state deserialization. `serde_wasm_bindgen::from_value` with
`deserialize_struct` only iterated the 15 built-in field names, silently
dropping custom properties like scatter_templates, strain, height_scaling.
Switched to JSON-based `from_js_json` which correctly processes all keys.

Additional fixes:
- Add toError/extractErrorMessage utilities for robust WASM-JS error
  handling (eliminates "[object Object]" error messages)
- Fix remove_agent crash when msg.data is undefined (remove_self behavior)
- Improve middleware error extraction for non-Error runner errors
- Harden JsCustomBehavior error paths against cascading WASM failures
- E2E tests now run 5 simulation steps with real assertions instead of
  silently swallowing step failures

Made-with: Cursor
Root cause: During the Redux-to-Context migration, Monaco model sync
moved from store.subscribe() (synchronous during dispatch) to
useEffect (runs after render). This meant models didn't exist when
HashCoreEditorFile rendered, leaving the editor showing stale content
from the previous project.

Fix: Call syncModels synchronously during MonacoModelSync's render
phase (guarded by a ref to skip redundant calls), restoring the
timing guarantee that models exist before the editor tree renders.

Also removes the _modelsVersion / MODELS_SYNCED band-aid that forced
a second render cycle — the synchronous approach is both simpler and
matches the original Redux behavior.

Adds E2E test that loads two different examples and verifies the
editor content updates.

Made-with: Cursor
…tions

promise-worker-transferable fires each message callback without awaiting
the previous one, allowing concurrent WasmRequestHandler instances that
share mutable RunnerState.  When switching from a running simulation,
the `initialize` handler would set `runner.simulationRunId` to the new ID
before its first `await`, while a stale in-flight `getReadySteps` handler
was still building its response.  The stale response would carry the new
ID with old step data, corrupting the new simulation's store entry and
leaving the viewer with a mismatched step count (blank display).

Two fixes applied:
- Serialize worker message handling via a promise queue so handlers
  execute one at a time
- Defer setting runner.simulationRunId until after async initialization
  completes, and clear accumulatedSteps early, so any concurrent handler
  capturing runner state sees the old ID (harmlessly discarded by the
  main thread)

Made-with: Cursor
Audited fork/main (11273e1..91e2f46) vs modernization; cherry-picks conflict wholesale, so applied equivalents manually.

Ported (by original fork/main commit intent):
- 91e2f46, 7fb8761: ignore tsconfig.tsbuildinfo and .vercel under apps/sim-core
- f9b4b7b: Help menu link to GitHub issue chooser + rel on docs link
- 6eb3fdb: preview:core script (yarn ws:core start / vite preview)
- 2e69841: engine-web and utils fmt use && and explicit --write/--check (cross-shell)
- 110c4a3: Mapbox spelling in GeospatialMap placeholder copy

Dismissed as superseded or incompatible with modernization:
- b149727 OSS hCore import, 9bbae6c project creation, b3f9e0f/5e78ed0 auto-types/GraphQL paths (removed on modernization)
- f2be7a2 Python libs under libs/ (out of sim-core scope; tree differs)
- e7469eb Renovate (.github/ out of sim-core policy)
- 09d1f25/f62782f Husky (no matching .config/husky prepare on current root)
- 517f444 through 154ee9b Vite/webpack/eslint/tsconfig bulk (reimplemented on modernization)
- 526ef58 Promise.resolve webworker shim (no matching pattern in tree)
- 8da4a2e vercel.json (file absent on modernization branch)
- 8688927 vite-env.d.ts (present elsewhere if needed)

Co-authored-by: Cursor <cursoragent@cursor.com>
…ntain permissions'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants