Skip to content

Add type-strip mode: run Harper directly from .ts sources - #562

Draft
kriszyp wants to merge 69 commits into
mainfrom
claude/typestrip-mode
Draft

kriszyp wants to merge 69 commits into
mainfrom
claude/typestrip-mode

Conversation

@kriszyp

@kriszyp kriszyp commented May 16, 2026 •

Copy link
Copy Markdown
Member

⊙ Problem

Native TypeStrip execution needs ESM-compatible CLI and worker modules. This branch had fallen behind main’s deployment, worker-pool and lazy-loading changes.

❓ Your call: requirement

Continue the existing TypeStrip implementation as requested. Preserve the owner’s decision to block exec, execFile and spawn before configuration loads. Keep the existing v5.4 milestone and leave this PR draft while its broader native unit-fixture migration remains unfinished.

💡 Solution

Run source commands with node --conditions=typestrip bin/harper.ts; public package imports retain the compiled CommonJS entry. Runtime paths and startup hooks support both modes. The rebase preserves current canary admission, dedicated worker pools, SQL authorization and dependency choices. The worker entry binds only for an actual HTTP worker. Core paths follow the actual module tree; metadata-owned product startup and public relative-worker paths retain main’s behavior. A shared CommonJS JSON import restores emitted schema assets.

The existing session-fixture teardown can mask failed setup; that minor cleanup limitation remains.

⚖️ Alternatives

❓ Your call: embedded ownership

Adopt module-owned core paths and the shared CommonJS schema bridge; preserve metadata-owned product startup and main’s relative-worker .js default. Asset fallbacks can select stale JSON, while moving PACKAGE_ROOT changes product identity. The repair remains inside core and is covered by isolated layout, CLI and worker checks.

Retained choices

  • Loader shim or package-wide ESM: changes the existing distribution contract.
  • Squash/reconstruct: loses patch provenance; retain the requested rebase and audit merge-resolution hunks separately.
  • Wait for admission during shutdown: refused canaries never receive it. Wait for component loading/reporting, then dispose.
Planning and retained decisions

This rebase’s planning review returned Framing-Verdict: chosen-approach-sound for separate load/report and admission boundaries, with cached synchronous runtime loaders preserving main’s lazy dependencies. Its separate task flag was absent, limiting independent derivation. The later packaging recheck adopted compiler-owned schema emission and main’s relative-worker contract; the final chosen approach cleared. The schema bridge uses an explicit named export for native linking and keeps a local mount binding for the existing legacy test seam. Earlier planning alternatives adopted direct codecs and the existing shutdown drain; retained patch provenance instead of reconstruction.

The existing startup FIFO, late-hook microtask contract, mandatory MCP graph, lazy Resource constructors, default logger refresh, worker-only early inspector setup and accepted 64 MB heap floor remain. Inherited audit-retention/password-hash snapshots, optional MCP degradation and legacy filter implementation remain follow-up work. Codemod aliases, repeated TDZ wrappers and stale-comment cleanup remain deferred. Main also lacks the legacy LMDB filterByType export; multi-condition legacy search remains broken. No new public readiness or cancellation API is introduced.

🔧 Changes

Architecture and changed files

Product and architecture tour

Runtime startup

How do both runtimes retain loading, admission and disposal boundaries?

Runtime paths and cold loaders select source .ts or compiled .js files from core’s canonical module directory, including embedded dist/core. Package metadata remains with its original owner. The shared CommonJS schema bridge lets the compiler emit the built-in JSON alongside core. Startup hooks run after configuration is initialized. Cyclic registrations remain synchronous through worker state and operation dispatch state. Newly introduced dependencies stay lazy through the existing CommonJS loader; source imports never rely on a global require.

Canary admission and shutdown

Shutdown waits for worker-owned loading/reporting, independently of main’s admission decision.

flowchart TD
  Config[Initialize configuration] --> Hooks[Run startup hooks]
  Hooks --> Load[Load components]
  Load --> Report[Report component verdict]
  Report --> Admission[Wait for main admission]
  Admission --> Bind[Bind listeners and report started]
  Shutdown[Receive shutdown] --> Terminal[Mark worker terminal]
  Terminal --> Settled[Wait for loading to settle]
  Report -. settles load barrier .-> Settled
  Settled --> Dispose[Drain and dispose scopes and stores]
  Dispose --> Exit[Exit worker]
Loading

The load barrier closes when awaitAdmission reports its verdict publishes the existing verdict. Readiness waits for admission before binding. Terminal workers enter idempotent cleanup after load rejection, admission or bind failure. The graceful path waits for registered scope disposal before exit; termination backstops and later-created scopes remain limits. This separates promises without changing the canary message protocol.

Importing Harper in a job or diagnostic worker does not start HTTP. The configured allowlist gates exec, execFile and spawn. Refused canaries neither bind nor report ready, and shutdown does not await CHILD_ADMITTED.

Changed files

.github. Keep review framing coverage for both names of the renamed backup importer.

review-coverage.yml.

DESIGN.md. Index the renamed worker design references and native/compiled startup invariant.

DESIGN.md.

agent. Agent startup uses the converted thread manager.

agent.ts.

bin. CLI commands initialize configuration before lazy subcommand imports; runtime paths and CommonJS default interop support both execution modes. The entry guard accepts compiled extensionless invocations without executing imported CLI modules.

agentCli.ts, backup.ts, cliOperations.ts, copyDb.ts, harper.ts, client.ts, restart.ts, run.ts, status.ts, upgrade.ts.

components. Component loading and existing deployment, MCP, secret and status operations retain upstream behavior with explicit ESM bindings. Built-in plugin preloads run in the startup phase; restart reset registration remains synchronous. Lazy Fastify and model plugins use module-owned URLs instead of an embedding product’s #src mapping, preserving the caller module family under symlinks.

Application.ts, Component.ts, ComponentV1.ts, EntryHandler.ts, OptionsWatcher.ts, PluginModule.ts, Scope.ts, canaryRollout.ts, componentLoader.ts, deployLifecycle.ts, listChanged.ts, resources.ts, serverRequests.ts, application.ts, operations.ts, operations.ts, operationsValidation.ts, requestRestart.ts, rootConfigPublication.ts, secretOperations.ts, crossThread.ts.

config. Configuration imports and existing test aliases support ESM while retaining upstream persisted environment state and validation.

configUtils.ts, harperConfigEnvVars.ts.

dataLayer. Existing operations use ESM imports, callable default interop and erased type annotations. The unused legacy transaction wrapper is removed as in the original PR. SQL search and export retain cold synchronous module loading; CSV parsing uses the CommonJS default in both modes.

SQLSearch.ts, SearchObject.ts, bulkLoad.ts, UpsertObject.ts, delete.ts, export.ts, getBackup.ts, insert.ts, readAuditLog.ts, rocksdbBackup.ts, schema.ts, schemaDescribe.ts, search.ts, transaction.ts, update.ts.

Storage bridges. Convert legacy LMDB modules to TypeScript/ESM, preserve callable defaults and existing operation bodies, and use explicit paths. Retain the original PR’s schema/table identifier and audit-object construction corrections.

ResourceBridge.ts, insertUpdateValidate.ts, harperBridge.ts, lmdbCreateAttribute.ts, lmdbCreateRecords.ts, lmdbCreateSchema.ts, lmdbCreateTable.ts, lmdbDeleteAuditLogsBefore.ts, lmdbDeleteRecords.ts, lmdbDropAttribute.ts, lmdbDropSchema.ts, lmdbDropTable.ts, lmdbFlush.ts, lmdbGetBackup.ts, lmdbGetDataByHash.ts, lmdbGetDataByValue.ts, lmdbReadAuditLog.ts, lmdbSearchByConditions.ts, lmdbSearchByHash.ts, lmdbSearchByValue.ts, lmdbTransaction.ts, lmdbUpdateRecords.ts, lmdbUpsertRecords.ts, LMDBCreateAttributeObject.ts, LMDBDeleteTransactionObject.ts, LMDBInsertTransactionObject.ts, LMDBUpdateTransactionObject.ts, LMDBUpsertTransactionObject.ts, initializeHashSearch.ts, initializePaths.ts, lmdbCheckForNewAttributes.ts, lmdbCreateTransactionsAuditEnvironment.ts, lmdbProcessRows.ts, lmdbSearch.ts, lmdbWriteTransaction.ts.

index.ts. Guard the CommonJS package export bridge during native evaluation; package exports still default to the compiled distribution.

index.ts.

Integration tests. Real CLI fixtures start two HTTP workers in compiled and native modes, inspect worker identity, PUT/GET a REST record, verify configured operation/refresh token lifetimes, and reject a forbidden builtin import. Extend the existing slow-blob test to both modes, proving the configured transaction monitor observes and spares an in-progress commit. Both-mode tests also exercise the accepted 64 MB worker floor, denial logs and structured CSV job errors, cold SQL/date searches, real export jobs and denied SQL authorization.

blob-commit-over-time.test.ts, operation-denial-log.test.ts, operations-server.test.ts, thread-heap-memory-recovery.test.ts, typestrip.test.ts, config.yaml, resources.ts, schema.graphql.

launchServiceScripts. Explicit ESM bindings and erased types support the native runtime.

launchHarperDB.js, startHarperDB.ts.

resources. Resource imports, native optional bindings and erased types support source execution; cyclic classes and database access use lazy bindings. Configured startup refreshes transaction queue/debug settings and re-arms the transaction monitor at its configured interval. Existing branch stores, indexes, analytics and model behavior remain upstream.

DatabaseTransaction.ts, ErrorResource.ts, LMDBTransaction.ts, RecordEncoder.ts, Resource.ts, Resources.ts, RocksIndexStore.ts, RocksTransactionLogStore.ts, Table.ts, write.ts, auditStore.ts, blob.ts, dataLoader.ts, databases.ts, derivedIndexes.ts, graphql.ts, hnswPlaneBinding.ts, login.ts, calibrationStore.ts, decideHook.ts, embedHook.ts, originClosedFloor.ts, replayLogs.ts, scheduler.ts, search.ts, transactionBroadcast.ts.

security. Authentication and user operations use ESM-compatible imports and runtime JSON reads. Config-dependent authentication initialization and token lifetime refresh use the startup phase; the loader binds native require locally and keeps optional sandbox dependencies lazy. Preserve main’s shared pure-ESM compartment resolver and synchronous SES shim ordering, using locally bound nativeRequire.

auth.ts, fastifyAuth.ts, jsLoader.ts, keys.ts, permissionsTranslator.ts, tokenAuthentication.ts, user.ts.

Certificates. Lazy Resource constructors avoid ESM class cycles while preserving subclass construction and static inheritance. Current upstream certificate cache expiration and verification logic remain intact.

certificateVerificationSource.ts, crlVerification.ts, ocspVerification.ts, pkijs-ed25519-patch.ts, verificationUtils.ts.

server. Native/operations server loading uses explicit ESM bindings and type-only Server imports; runtime path and configuration-dependent initialization changes preserve listener/startup behavior. Job workers initialize configuration and run startup hooks before operations. Legacy Fastify remains lazy.

DESIGN.md, DurableSubscriptionsSession.ts, REST.ts, Server.ts, fastifyRoutes.ts, getCORSOptions.ts, getHeaderTimeoutConfig.js, getHeaderTimeoutConfig.ts, getServerOptions.ts, hdbCore.ts, http.ts, serverHandlers.ts, jobOwnership.ts, jobProcess.ts, jobRunner.ts, jobs.ts, liveSubscriptionAuth.ts, loadRootComponents.ts, mqtt.ts, operationsServer.ts, static.ts, index.ts, storageReclamation.ts.

Server helpers. Operation dispatch reads leaf state at invocation; native addon loading uses bound require. HTTP singleton bindings and content types attach synchronously; other conversions retain existing request and permission behavior. Cached SQL imports remain cold, and the tagged operation logger refreshes after installation during startup.

contentTypes.ts, operationDispatchState.ts, registeredOperations.ts, requestTimePlugin.ts, serverHandlers.ts, serverUtilities.ts, uwsServer.ts.

Workers. Source and distribution workers select their own files. Leaf state preserves early callbacks, process incarnation is shared without loading the server, and HTTP worker bootstrap is limited to its actual entry point. Retain upstream started/loaded boundaries, strict DDL acknowledgments and shutdown draining. Held canary loading/reporting is separate from admission: refusal and terminal bind errors finish scope disposal without waiting for admission. Public relative worker paths retain the package root and .js default; internal job producers pass complete absolute core filenames.

heldStart.ts, isolatedApplications.ts, itc.ts, logRotationTransport.ts, manageThreads.ts, processIncarnation.ts, socketRouter.ts, threadMessageState.ts, threadServer.ts.

sqlEngine. Replace local CommonJS requires with explicit ESM bindings, retaining SQL parser, mutation and routing behavior.

defaultDatabase.ts, differential.ts, errors.ts, runMutation.ts, parse.ts, router.ts.

sqlTranslator. Convert legacy translator modules and imports to ESM with callable default interop and erased types.

SelectValidator.ts, alasqlFunctionImporter.ts, deleteTranslator.ts, index.ts, sql_statement_bucket.ts.

Unit tests. Update existing compiled test seams and source filename expectations; add native cyclic registration, CLI import, service entry, lazy class inheritance, process incarnation, CLI/server imports from evaluated workers and symlink-preserving runtime path and cold-module identity checks. Keep the legacy SQL engine absent from both boot graphs until first use. Add isolated dual-mode lifecycle coverage for ordered awaits, idempotency, reset, late registration and startup failure. The shutdown fixture uses .cjs to stay out of the standard server test glob, waits for the actual ready/query messages and stays alive after parentPort unref. New real worker cases cover admission, refusal, shutdown during loading and exclusive listener retry in both runtimes. A TypeScript AST guard detects unbound production require calls. The embedded fixture checks product CLI invocation once, core credential/restart paths, real admitted workers on both engines, and an external relative worker. Package fixtures prove standalone/nested compiler JSON emission and replacement of stale output. Actual default-app plugin loading and the legacy launcher work in nested core; compiled CLI runs once with either spelling, and source/compiled plugin imports preserve symlink identity.

setupTestApp.mjs, bulkLoad.test.js, delete.test.js, insert.test.js, readAuditLog.test.js, caching.test.js, create.test.js, authCredentialDeferral.test.js, jsLoader.test.js, admission-scope.cjs, component-shutdown.cjs, embedded-layout.cjs, runtime-condition.cjs, startup-ref.cjs, startup-shutdown.cjs, manageThreads-shutdown-fixture.cjs, manageThreads-shutdown.test.js, typestrip-runtime.test.mjs, typestripSource.test.mjs, testUtils.js, lifecycle.test.js, mount_hdb.test.js, packageUtils.test.js, watchPath.test.js.

upgrade. Read the compiler-emitted built-in schema through the shared CommonJS bridge and import converted helpers explicitly, preserving upstream version-specific directives and provisioning.

5-1-0.ts, 5-2-0.ts, 5-3-0.ts.

utility. Use ESM-compatible imports and package-root paths; leaf lifecycle/database registries break cycles. Native source and compiled distribution paths are selected centrally from canonical module locations, including with --preserve-symlinks. The cold module helper retains its own symlink path family; SQL AST authorization loads its parser only on first use. The CommonJS systemSchema.js bridge restores compiler-owned JSON emission and main’s shared parsed schema without loading it into the path helper. Lazy plugin URLs retain the caller’s path family, matching the cold module loader.

DESIGN.md, common_utils.ts, databasesRef.ts, environmentManager.ts, systemInformation.ts, geo.ts, alaSQLExtension.ts, globalSchema.ts, checkJWTTokensExist.ts, installer.ts, lifecycle.ts, mount_hdb.ts, npmUtilities.ts, operation_authorization.ts, packageUtils.js, signalling.ts, systemSchema.js.

LMDB utilities. Use ESM-compatible CommonJS defaults and cycle-tolerant environment initialization, retaining existing LMDB operations.

OpenDBIObject.ts, OpenEnvironmentObject.ts, environmentUtility.ts, writeUtility.ts.

Logging. Use ESM-compatible defaults and lazy imports for optional crash handling, rotation and root configuration. Retain compiled exports and expose native logger startup hooks.

harper_logger.ts, logRotator.ts, logger.ts, readLog.ts, transactionLog.ts.

Service processes. Compiled daemon startup retains the metadata owner’s product CLI; core’s restart utility uses its physical runtime directory. Source mode retains the core CLI. Process management and environment inheritance remain intact.

processManagement.ts, servicesConfig.ts, restartHdb.ts.

validation. Use ESM bindings and CommonJS callable/default interop while preserving upstream validation behavior.

configValidator.ts, fileLoadValidator.ts, installValidator.ts, readLogValidator.ts, role_validation.ts, schemaMetadataValidator.ts, searchValidator.ts, validationWrapper.ts.

✅ Verification

  • Build, types, strict lint, formatting and design-doc checks pass on the final repair (Linux, Node 26.2). Focused runtime/lifecycle/loader/package checks: 85 passing.
  • Full core at f6eb005: 7,008 passing / 207 pending. Resources: RocksDB 4,283 / 54; LMDB 3,255 / 722. These runs precede the final plugin/CLI repair.
  • Full integration at f6eb005: 2,389 passing, 18 skipped, one TODO, zero failures, using the installed llama3.2:3b model and no inherited ROOTPATH. Final repair: 18 source/compiled startup integration tests and 2,073 component tests / seven pending pass.
  • Embedded workers, default plugins, schema emission, CLI invocation and relative-worker contracts pass. Source/compiled symlink plugin imports retain module identity. Clean main fails the mid-load shutdown and bind-retry assertions; all four canary cases pass in both branch runtimes.

No documentation companion is added during this rebase: this remains a draft implementation PR, with the source invocation described above.

❓ Your call: native unit migration

Keep the full native unit-fixture migration as follow-up work. Old #js aliases still target source .js files that this PR renames. Routing them to dist would mix compiled state into source tests. CLI, worker and REST coverage is separate; these legacy aliases still prevent a green full native unit lane.

❓ Your call: disposal boundary

Retain the tested load/report boundary for this rebase. Two new minor risks remain: deferred-load polling can delay cleanup beyond the backstop, and the shutdown load wait follows the port unref. A both-mode unreferenced-timer probe passed, but does not prove every RocksDB wake. Later-created scopes and Bun/uWS bind races remain follow-up work.

Validation and review details

Full core/resources/integration checks cover f6eb005, updated through main 3fd9ae9. The first full core run had 7,006 passes and two failures: deployment rename retry timing and watcher content observed before its write. The two unchanged suites then passed 104 tests / one pending on this commit and on clean main. The subsequent full core repeat passed all 7,008 tests. Matching failing main reproductions are not claimed. No timing workaround or test weakening was added.

The earlier default-model integration run had four Ollama HTTP 404 failures: this host has llama3.2:3b but lacks the latest tag requested by the default name. The supported model override executes all six real Ollama cases and the full integration route; no models were downloaded or service settings changed. Clean main's original native Ollama fixture fails earlier on its source JSON import, so a matching four-failure main run is not claimed. The initial runner's unit ROOTPATH leak was corrected before the valid integration runs. CI policy's 143 tests passed before the packaging-only repair; its policy files are unchanged by that repair.

Clean main's compiled worker controls pass admission/refusal but fail shutdown during loading (6-second graceful-exit assertion) and shutdown during bind retry (exit 1 instead of 0). All four scenarios pass in both branch runtimes. Those cases cover registered scopes, not later-created scopes. A further real-worker probe with an unreferenced 500 ms load timer passed in both modes; it does not establish liveness for every RocksDB wake. The native loader's 25 cases exercise VM/compartment resolution, import-only/dual packages, symlinks, SES shim order and native addons.

Before the packaging repair, an actual copied core distribution selected a missing worker and separately failed reading the schema from its outer metadata root. A supported direct core version command printed nothing because its entry guard compared against the outer CLI. The formal after-tests boot embedded core workers, prove one direct and one product CLI version output, preserve metadata and relative-worker ownership, and link all eight schema readers natively and compiled. Standalone/nested compiler fixtures emit current schema JSON and overwrite deliberately stale output. The schema cache remains mutable as on main. The fixture uses the original outer-dist #src/#js imports map; The final repair also exercises Fastify and model-gateway imports through module-owned URLs, default-app loading, the legacy launcher, and an extensionless direct core CLI. Both runtimes retain one plugin module family with --preserve-symlinks. Actual wrapper deployment/source startup, Bun/uWS and Windows execution remain unverified.

The range audit retained 64 non-merge patches, skipped the superseded forge interop patch, and restored six resolution hunks from the original four merges. The current range differs from that replay only by four author repair/style commits. The 249-file comparison preserves current main loader/agent behavior, manifest and lockfile. The native legacy #js fixture migration remains follow-up work; aliases were not redirected to dist.

Final artifact review: fresh full scope at 7c896a4, exit 0, independent coverage from Claude and Gemini. Both confirm the plugin and extensionless CLI fixes; no new actionable defect was found. Claude reports nine repeated findings plus one harness coverage gap; Gemini reports three repeated findings. No further code fixes were made for that round. MCP optional-import behavior is retained by the earlier design decision; the missing legacy LMDB filter export is also absent on main; duplicate cold dispatcher loading is cosmetic.

independent-review: DEGRADED. The selected domain adjudicator failed with “Selected model is at capacity.” It produced no adjudication; author scope rulings above are not independent domain coverage. Cursor was pruned by the standard final-artifact policy. The input diff was truncated; the trace grader reports 31 rows, two NO entries, three listed sites untraced and 21 groups past its shown cap. Three prior trace gaps carry. The full-pass counter remains four, not seven. The receipt reports closing-full=armed and not-converged due to absent adjudication; armed owes no additional closing round. Machine open-finding retirement is not claimed.

The formatter self-check named two deleted paths (dataLayer/transaction.ts and server/fastifyRoutes/helpers/getHeaderTimeoutConfig.js); the actual whole-repository formatting gate passes. The teardown guard repeats the documented session fixture limitation. Release inference was inconclusive; the existing v5.4 milestone is retained explicitly.

Remaining scoped concerns include the inherited first-install audit-retention and hash snapshots, MQTT’s truthy DEV_MODE string, optional asynchronous Bun/uWS bind races, and MCP’s mandatory import graph. Existing test limitations cover successful post-shutdown binds, the external fresh-install helper’s initial config state, duplicate underlying auth initialization and unspecified worker memory headroom. Cosmetic conversion cleanup and dormant legacy audit hydration costs remain deferred; no performance claim is made for that path.

The related-PR scan is partial: only the first 50 merged PRs were scanned, with 246 additional PRs outside that window; the automatic issue-number search was capped at 20 of 33. This conversation is PR-anchored, so that search does not establish an issue-closing relationship.

The last review reproduced default Fastify imports resolving against the outer product’s imports map. Module-owned file URLs fix that error without eagerly importing either plugin. An initial canonical URL probe exposed a duplicate core graph under --preserve-symlinks; retaining the helper’s path spelling matches the existing cold loader and passes the formal source/compiled test. The entry guard restores main’s extensionless compiled CLI behavior. 7c896a4 is the tested final repair; broad storage/full integration results above precede this narrow delta.

🤖 Generated by OpenAI Codex; posted via @kriszyp.

Release target: v5.4 — retain this draft feature’s existing release milestone.

Related PRs: #3019 overlaps (UDS mirror hardening), #3020 overlaps (RocksDB validation), #2065 overlaps (cache-fill convergence), #3018 independent (CODEOWNERS comment follow-up), #3015 overlaps (main packaging cleanup retained), #2718 independent (main reviewer workflow retained), #3014 independent (design-note overlap only), #3016 overlaps (write queue/export hygiene), #3017 overlaps (analytics aggregation), #3010 overlaps (TLS renewal follow-up), #3011 overlaps (agent fetch policy), #3003 overlaps (main dependency updates retained), #372 overlaps, #1371 overlaps, #1770 overlaps, #1835 overlaps, #1921 overlaps, #2122 overlaps, #2138 overlaps, #2155 overlaps, #2170 overlaps, #2446 overlaps, #2463 overlaps, #2532 overlaps, #2564 overlaps, #2575 independent (release backport), #2648 overlaps, #2649 overlaps, #2693 overlaps, #2752 independent (design-note overlap only), #2763 overlaps, #2775 independent (design-note overlap only), #2883 overlaps, #2901 independent (design-note overlap only), #2906 overlaps, #2918 overlaps, #2930 independent (design-note overlap only), #2939 overlaps, #2946 overlaps, #2956 independent (release backport), #2958 overlaps, #2962 overlaps, #2963 overlaps, #2981 overlaps, #2986 overlaps, #2990 overlaps, #2994 independent (release backport), #3000 overlaps, #2998 overlaps, #2979 overlaps, #2982 independent (release backport), #2989 overlaps, #2987 independent (release backport), #2988 overlaps, #2926 overlaps, #2985 overlaps, #2938 overlaps, #2954 overlaps, #2960 independent (design-note overlap only), #2957 overlaps, #2902 overlaps, #2966 independent (release backport), #2964 independent (design-note overlap only), #2929 overlaps, #2948 overlaps, #2903 overlaps, #2936 overlaps, #2914 overlaps, #2921 overlaps, #2904 overlaps, #2913 overlaps, #2916 overlaps, #2911 overlaps, #2900 overlaps, #2897 overlaps, #2899 overlaps, #2893 overlaps, #2896 independent (design-note overlap only), #2890 overlaps, #1844 overlaps, #1738 independent (optional type checker), #1574 overlaps, #3070 independent (release tooling), #3078 overlaps (product identity and CLI ownership), #3117 independent (agent tool-result budget), #3126 overlaps (REST login conversion), #3140 overlaps (optional native server loading), #3177 independent (agent session budget), #3064 independent (merged agent limits retained), #3093 overlaps (merged compartment resolver retained), #3072 overlaps (merged core memory/import changes retained), #3141 overlaps (merged live subscription authorization retained), #3021 overlaps (merged Table allocation fix retained), #3083 overlaps (merged component config behavior retained), #3107 independent (backup ownership documentation), #3069 overlaps (merged content-type upload drain retained), #3085 independent (origin-closed floor), #3065 independent (backup integrity fixture), #3036 overlaps (merged logger file identity fix retained)

Complexity: complicated

Review-Coverage: authored=codex; ran=gemini,claude; blocked=domain(exit-1); declined=cursor-grok,cursor-composer,cursor-kimi,cursor-muse; rounds=10; full=4 @ 7c896a4

Review-Attention: deep ~275m (critical: copyDb.ts, ResourceBridge.ts +63; sensitive: review-coverage.yml, login.ts +14; hot: Resource.ts, DurableSubscriptionsSession.ts +12; raised: degraded review) @ 7c896a4

@kriszyp
kriszyp requested review from a team as code owners May 16, 2026 23:21
Comment thread bin/run.ts Outdated
Comment thread server/threads/threadServer.ts
@claude

claude Bot commented May 16, 2026 •

Copy link
Copy Markdown
Contributor

Reviewed; no blockers found.

@kriszyp
kriszyp force-pushed the claude/typestrip-mode branch from 23a2e4d to ded6937 Compare May 17, 2026 00:18
Comment thread server/threads/socketRouter.ts Outdated
Comment thread bin/upgrade.ts Outdated
Comment thread dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.ts Outdated
@kriszyp
kriszyp force-pushed the claude/typestrip-mode branch from 2b250f2 to 31b0ef6 Compare May 17, 2026 02:22
Comment thread dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbCreateAttribute.ts Outdated
Comment thread launchServiceScripts/launchHarperDB.ts Outdated
Comment thread dataLayer/harperBridge/lmdbBridge/lmdbUtility/LMDBCreateAttributeObject.ts Outdated
Comment thread dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByValue.ts Outdated
Comment thread dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.ts Outdated
Comment thread launchServiceScripts/launchHarperDB.ts Outdated
Comment thread dataLayer/harperBridge/lmdbBridge/lmdbMethods/lmdbSearchByConditions.ts Outdated
Comment thread security/certificateVerification/certificateVerificationSource.ts Outdated
Comment thread security/certificateVerification/certificateVerificationSource.ts Outdated
Comment thread security/certificateVerification/crlVerification.ts Outdated
Comment thread security/certificateVerification/certificateVerificationSource.ts Outdated
@kriszyp

kriszyp commented May 17, 2026

Copy link
Copy Markdown
Member Author

Session wrap-up — major progress, one remaining failure

This session pushed 31 commits and dramatically reduced failures. Posting a roll-up so the next iteration has a clear starting point.

Where we are

  • ✅ Daemon mode under typestrip: node bin/harper.ts start works end-to-end
  • ✅ Daemon mode under CJS dist: node dist/bin/harper.js start works
  • ✅ test:unit:main: 1848 passing, 0 failing (was 96 failing at PR start)
  • ✅ test:unit:apitests: 168 passing, 0 failing (was unreachable due to upstream failures)
  • ✅ All builds green across Node 20/22/24 + Windows
  • ✅ Format Check green
  • ✅ claude/review marks PR with "no new blockers" on every iteration
  • ❌ test:unit:resources exits 139 (segfault) in CRUD operations with the Resource API describe block — first time this phase has been reached on this branch
  • ❌ runLinter pre-existing on main (npm ci lockfile drift for optional native deps bufferutil/utf-8-validate)

Root causes uncovered & fixed this session

  • lmdbSearchByConditions.ts:2-3 JSDoc-only require() (typestrip crash)
  • signalling.ts CJS double-default unwrap (mod.default?.default ?? mod.default ?? mod)
  • alaSQLExtension collapsed to default-only after .js→.ts conversion (test + consumer expected named exports)
  • readLog.test.js rewire __set__('configUtils_js_1', …) updated to _ts_1 after configUtils conversion
  • security/keys.ts:658, config/harperConfigEnvVars.ts:29, resources/Resources.ts:47 — stale require()s in ESM-evaluated files
  • jsLoader.ts basePath/ALLOWED_COMMANDS captured at module load — moved into the spawn closure with ['npm','node'] fallback
  • resources/databases.ts lost the top-level initSync() during conversion — restored. This was the root cause of the componentsRoot is not configured cascade in apitests
  • bin/harper.ts STOP subcommand wasn't calling initEnv() — added
  • componentLoader.ts config ??= DEFAULT_CONFIG defensive guard for when getConfigObj() returns undefined
  • threadServer.ts componentsLoadedResolve(loaded) was resolving with the module namespace (post-import * as) instead of the actual chain — now captures loadedPromise and returns it from startServers
  • setupTestApp.mjs was setting server.getUser = stub before runStartup(), so user.ts's onStartup hook clobbered the stub back to getUserImpl — moved the drain to fire first
  • threadServer.ts onSocket became async after require() → await import(), so server.socket(...) returned a Promise and broke the mTLS test's [0].listen() — hoisted getComponentName to a static import, restored sync

What's left

  1. test:unit:resources segfault. Right before the crash, an unhandled rejection lands at unitTests/resources/caching.test.js:362 — CachingTable.primaryStore.cache.clear() where primaryStore.cache is undefined. Likely a teardown/state issue in a prior test that pollutes shared store state and then native code dereferences something bad in the next describe block's before(). Worth a focused dive locally; remote logs aren't enough.
  2. claude/review's open hypothetical about CertificateVerificationSource not being constructible due to started===true/microtask timing — but the corresponding test (should export CertificateVerificationSource class) passes on CI. The Proxy refactor it suggests is cheap and matches the ErrorResource pattern if we want to belt-and-suspenders it.

Generated by Claude.

Comment thread security/certificateVerification/certificateVerificationSource.ts Outdated
Comment thread security/certificateVerification/certificateVerificationSource.ts Outdated
@kriszyp
kriszyp marked this pull request as draft May 17, 2026 20:11
Comment thread server/threads/itc.ts Outdated
kriszyp added a commit that referenced this pull request May 18, 2026
CRL/OCSP integration tests' fixture/config.yaml contains only a YAML
comment, so parseDocument(...).toJSON() returns undefined. The earlier
`config ??= DEFAULT_CONFIG;` fallback (intended for root configs when
getConfigObj() returns undefined) then synthesized DEFAULT_CONFIG
(rest, graphqlSchema, etc.) for the fixture. The component loader
created a Scope for each synthesized plugin, whose OptionsWatcher
watched the fixture's empty config.yaml; with no matching plugin key
in the file, OptionsWatcher never emits 'ready', scope.ready hangs
forever, sequentiallyHandleApplication never starts, and the http
worker never sends CHILD_STARTED — so Harper times out at startup.

Constrain the fallback to isRoot (which is the case the comment
described) and treat an empty/null parse result on a non-root
component as "nothing to load" rather than silently filling in
default plugins.

Fixes the CRL Certificate Verification, OCSP Certificate Verification,
and related mTLS-bearing integration test hangs on PR #562.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kriszyp
kriszyp marked this pull request as ready for review May 27, 2026 02:01
@kriszyp
kriszyp removed request for a team May 27, 2026 02:01
kriszyp and others added 18 commits October 12, 2026 18:17
common_utils.ts → databases.ts → itc.ts → common_utils.ts created
a circular dependency that caused the 'restart' ITC listener to not
register on the main thread, breaking restart_service jobs (workers
couldn't restart HTTP workers after component hot-reload).

Fix: inline isEmpty() directly in itc.ts (it was the only function
itc.ts used from common_utils) so itc.ts no longer imports common_utils.
This breaks the cycle and allows common_utils.ts to safely add a
top-level import of getDatabases from databases.ts.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…level import

Previous approach (direct top-level import) created circular deps with
multiple modules: databases.ts → Table.ts / auditStore.ts / DatabaseTransaction.ts
→ common_utils.ts, all of which import back into common_utils.ts.

New approach:
  - utility/databasesRef.ts: tiny dep-free registry with setDatabasesGetter()
    and getDatabases()
  - resources/databases.ts: calls setDatabasesGetter(() => getDatabases()) at
    module top-level, after its own getDatabases export is defined
  - utility/common_utils.ts: imports getDatabases from databasesRef.ts (no cycle)
  - server/threads/itc.ts: inlines isEmpty to remove its import of common_utils
    (that import would have created a cycle via databases→itc→common_utils)

This eliminates all `require()` calls from common_utils.ts while keeping the
lazy-loading semantics needed to avoid circular dependency issues.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
In ESM (node bin/harper.ts), `import _validate from 'validate.js'`
returns the CJS module wrapped as `{ default: validateFn }`. The old
`import * as validate from 'validate.js'` therefore left `validate`
pointing at the namespace object, making `validate.cleanAttributes`
undefined.

Use `_validate.default ?? _validate` to handle both ESM (where .default
is the library) and CJS dist (where _validate already IS the library).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- resources/RecordEncoder.ts: stale environmentManager.js import -> .ts (main
  added this import after the conversion; ESM needs the real extension). This was
  the only stale .js->.ts import; verified via full-tree scan.
- unitTests/dataLayer/bulkLoad.test.js: rewire binding _js_1 -> _ts_1 (tsc CJS
  emit names the import after the .ts source file) [open blocker 1]
- unitTests/resources/caching.test.js: cache.clear() -> cache?.clear() to match
  Table.ts's optional-chained cache access on the RocksDB path [open blocker 2]

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- bin/cliOperations.ts: replace require('dotenv') with static import
- bin/harper.ts: replace require('./mcp') with await import('./mcp/index.ts')
- bin/restart.ts: replace both require('./run') with await import('./run.ts')
- components/componentLoader.ts: remove duplicate null-config guard block (merge artifact)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- export default was missing start/startOnMainThread (updateLogSettings),
  so YAML logging config was silently ignored in TypeStrip mode
- replace require('segfault-handler') with dynamic import() so it works
  in ESM without require being defined as a global
- remove .claude/scheduled_tasks.lock from git tracking (tooling artifact)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…segfault handler

In TypeStrip (ESM) mode, componentLoader calls extensionModule.startOnMainThread?.()
on the harperLogger plugin to trigger log settings from YAML. The export default
object was missing start and startOnMainThread, so log configuration was silently
ignored in TypeStrip mode. Add both pointing to updateLogSettings.

Also replace require('segfault-handler') with dynamic import() so it works in ESM
where require is not available as a global (the try/catch suppressed the crash but
left the segfault handler unregistered).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The CJS→ESM conversion turned module.exports.restartNumber = ... into a
globalThis assignment instead of reassigning the exported module binding,
so restart-interrupt checks in databases.ts and threadServer.ts (which
read the real live binding) never observed a pending restart. A
long-running index backfill would run to the 10s force-kill instead of
checkpointing gracefully.

Also confirms the threadServer.ts realExit(1) fix (flagged in the same
PR review round) is already in place on this branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Retain upstream startup, strict ITC acknowledgments, storage behavior and subprocess policy while completing the source ESM migration. Preserve compiled dispatch interfaces and add native/compiled runtime and REST worker regression coverage.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Cover startup ordering, idempotency, reset, late registration and failure in both execution modes.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Re-arm transaction monitoring and token lifetimes after the ESM graph links. Run configured startup in job workers and exercise worker restrictions and transaction monitoring in both runtime modes.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Check the entry exists before resolving its canonical path, and import both CLI and server modules in the compiled and TypeStrip worker regression.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Keep the accepted worker heap minimum, synchronous SQL authorization and lazy legacy Fastify loading. Restore cold SQL module boundaries with symlink-safe runtime resolution, refresh the operation logger after installation, and correct native CSV parser interop. Exercise heap startup, logging, SQL exports and authorization through real compiled and native processes.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Keep nested initialization inside the startup barrier, expose the declared
source facade values, and carry source conditions into managed workers.
Restore component errors, configured analytics and logger sink behavior;
verify cold SQL table and attribute authorization in both runtimes.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Restore main's empty-component skip and hold HTTP workers alive across
startup hooks. Preserve both legacy JavaScript launcher paths through the
TypeScript implementation. Use PapaParse's actual default in the shared
CSV stream helper.

Verify both modes with real workers, launcher authentication and CSV rows.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
@kriszyp
kriszyp marked this pull request as draft October 13, 2026 00:23
kriszyp and others added 10 commits October 12, 2026 18:32
Select direct JSON codecs before serving requests, restore serial log rotation reconfiguration, and drain interrupted HTTP startup before exit. Verify real cache reads and dual-mode REST/subscription behavior.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Refresh newly eager authentication, application-loader, MQTT, forwarding,
bulk-load and debugger state after in-process installation. Keep the
existing configuration expressions and initialize the inspector once.

Exercise the real fresh-install main thread and actual cache timer in
compiled and TypeStrip modes. Resolve the security fixture after startup.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Retain main's lazy dependencies, canary admission and dedicated worker pools. Keep loading/reporting separate from readiness so refused or stopped workers finish disposal, and cover both runtime paths with real worker fixtures and a source-import guard.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Retain main's pure-ESM compartment resolver, SES shim sequence and agent token-limit handling. Bind the shim loads locally for native execution and retain the source-based ordering check.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Preserve product startup and public relative-worker paths while locating core workers and shared schema assets from their own module tree.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
Preserve the caller module family under symlinks and restore extensionless compiled CLI entry detection. Exercise default embedded plugins, the legacy launcher and both CLI spellings.

Co-Authored-By: GPT-6.1 Codex <noreply@openai.com>
@kriszyp
kriszyp force-pushed the claude/typestrip-mode branch from a6b977f to 7c896a4 Compare October 13, 2026 07:29

This branch has not been deployed

No deployments
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.

3 participants