Status: in progress
Audit basis: packages/legacy-documented/**/*.pseudo.md and *.proposed_improvements.md
Target under audit: current v5 work in progress across packages/*
This document is a staged audit of the current v5 implementation against the behavioral contracts extracted from the legacy system and documented in packages/legacy-documented.
This is not a one-shot verdict document. It is being written incrementally so each pass can stay evidence-based and avoid false certainty.
The goal is to answer, with maximum care:
- what v5 already does well
- what v5 intentionally changed in a good way
- what legacy behavioral guarantees are currently missing
- what regressions appear to have been introduced
- what still needs to be audited in subsequent passes
This pass is intentionally limited to high-confidence observations based on directly inspected source files.
The benchmark source for expected behavior is the documented legacy package in:
packages/legacy-documented/src/controllers/*.pseudo.mdpackages/legacy-documented/src/api/*.pseudo.mdpackages/legacy-documented/src/api/model/*.pseudo.mdpackages/legacy-documented/src/cli/*.pseudo.mdpackages/legacy-documented/src/events/*.pseudo.mdpackages/legacy-documented/src/logging/*.pseudo.mdpackages/legacy-documented/src/utils/*.pseudo.mdpackages/legacy-documented/src/structures/*.pseudo.mdpackages/legacy-documented/src/controllers/initializer.proposed_improvements.md
The following v5 files were directly inspected during this pass:
packages/wa-automate/src/index.tspackages/wa-automate/src/cli-runtime.tspackages/wa-automate/src/server/hono-server.tspackages/client/src/index.tspackages/client/src/Client.tspackages/core/src/index.tspackages/core/src/createClient.tspackages/core/src/events/eventMap.tspackages/core/src/plugins/PluginHost.tspackages/core/src/transport/Transport.tspackages/schema/src/index.tspackages/schema/src/registry.tspackages/schema/src/implementor.tspackages/config/src/index.tspackages/wa-automate/src/session/SessionManager.ts
- Items marked as findings below are grounded in code read during this pass.
- If something is only partially verified, it is labeled as an open question or follow-up target.
- Absence of evidence in this pass does not automatically mean the feature is absent everywhere in the repo.
The current repo is already structurally very different from legacy. It is not a monolithic rewrite of Client.ts; it is a package-split architecture.
Relevant package set visible from packages/:
apicliclientconfigcoredomaindriver-interfacedriver-playwrightdriver-puppeteerhyperemitterloggerorchestratorschemasession-syncsocket-clientwa-automate
This is already a meaningful architectural departure from legacy:
schemais now a first-class packageconfigis a first-class packageclientis a thinner facade packagecoreowns lifecycle/events/plugins/transportwa-automateappears to act as an app-facing composition packagesession-syncandorchestratorhave been split out into dedicated concerns
This package decomposition is itself a potential improvement, not a regression.
The following architecture intent is now explicit from the user and should be treated as authoritative when judging v5:
@open-wa/wa-automateremains the main npm package entrypoint for the library.- That main package should expose/re-export the important user-facing layers such as:
- CLI entry/runtime
- SDK/client-facing runtime surface
- other core exports as appropriate
- The CLI is the v5 continuation of the old Easy API concept:
- an opinionated host/runtime
- implemented on top of the SDK
- not the lowest-level session contract itself
- The SDK/client layer owns the fundamental headless/CLI-less session behavior.
- The SDK/client layer consumes browser drivers and generated client/schema surfaces.
- Shared infrastructure like
hyperemitteris intentionally usable from both SDK level and CLI level. - Plugin ecosystem goals exist at both levels:
- SDK-level integrations/plugins
- CLI-level integrations/plugins
- The dashboard (
dashboard-neo) is served alongside the CLI host. - The orchestrator CLI manages multiple CLI sessions and serves its own dashboard.
This clarification changes how several architecture decisions should be judged:
- not everything needs to live in the SDK/core layer
- not everything in the CLI layer is “leakage” or bad layering
- the important boundary is whether lower-level session fundamentals stop at SDK/core, and opinionated integrations remain above that line
Evidence:
packages/wa-automate/package.json
Observed behavior:
- package name is
@open-wa/wa-automate - it owns the
wa-automatebinary - it depends on
@open-wa/api,@open-wa/client,@open-wa/config,@open-wa/core,@open-wa/driver-puppeteer,@open-wa/schema,@open-wa/session-sync
Interpretation:
- this matches the desired role of
wa-automateas the top-level composition package rather than a low-level SDK package.
Important follow-up nuance:
- although
wa-automateis clearly acting as the top-level composition package, the currently inspectedpackages/wa-automate/src/index.tsdoes not yet visibly re-export the SDK/client surface in the way the clarified target architecture implies it eventually should. - So the package role looks right, but the final public export composition may still be incomplete.
Evidence:
packages/cli/package.jsonpackages/cli/src/index.ts
Observed behavior:
@open-wa/clidepends on@open-wa/wa-automatepackages/cli/src/index.tssimply re-exportsrunCli,startCli, andparseCliArgsfrom@open-wa/wa-automate
Interpretation:
- this strongly supports the idea that the CLI package is just a convenience entry/wrapper around the main package’s Easy API host behavior.
- That is architecturally consistent with the user’s clarified vision.
Evidence:
apps/cli/package.jsonapps/cli/src/index.tsapps/orchestrator-cli/package.jsonapps/orchestrator-cli/src/index.tsapps/dashboard-neo/package.jsonapps/orchestrator-dashboard/package.json
Observed behavior:
apps/cliis a private executable wrapper around@open-wa/cliapps/orchestrator-cliis a private executable wrapper around@open-wa/orchestratorapps/dashboard-neoandapps/orchestrator-dashboardare distinct UI applications rather than reusable library packages
Interpretation:
- this is an important sign of architectural discipline:
- reusable logic primarily lives in
packages/* - runnable binaries and dashboards live in
apps/*
- reusable logic primarily lives in
- this helps explain why not every runtime concern needs to be exportable from every library package.
Evidence:
packages/orchestrator/src/utils/resolve-easy-api-entry.tspackages/orchestrator/src/server.ts
Observed behavior:
- orchestrator resolves and launches the
@open-wa/wa-automateCLI entry (dist/cli.cjs) - orchestrator exposes create/start/stop/restart/proxy/list/status style management endpoints
Interpretation:
- this aligns directly with the intended model that orchestrator manages multiple CLI/Easy API sessions rather than multiple raw SDK sessions.
Evidence:
packages/api/src/dashboard/launcher.tspackages/api/src/createApiServer.ts
Observed behavior:
- dashboard sidecar launch is built into the shared API server package
- dashboard is described as
dashboard-neo - it is started by default from API server config unless disabled
- it talks to Easy API via
@open-wa/socket-client
Interpretation:
- this is strongly aligned with the architecture the user described.
Evidence:
apps/orchestrator-dashboard/package.jsonpackages/orchestrator/src/server.ts
Observed behavior:
- there is a dedicated orchestrator dashboard app
- the orchestrator package remains focused on multi-session management/runtime endpoints
Interpretation:
- this matches the intended model where the orchestrator layer has its own management surface rather than reusing the session dashboard unchanged.
From packages/wa-automate/src/index.ts:
- exports
WAServer - exports
APILifecycleManager - exports
SessionManager - exports CLI runtime helpers (
runCli,startCli,parseCliArgs) - re-exports
ConfigandConfigSchemafrom@open-wa/schema - re-exports API server helpers
Legacy centered everything around a single authoritative bootstrap entrypoint: create().
Current v5, at least from @open-wa/wa-automate, does not export a top-level create() equivalent from its package root in the inspected file.
That does not automatically mean v5 is wrong. It does mean the audit must explicitly test whether:
- v5 intentionally replaced “single create entrypoint” with a composed runtime host
- or whether the legacy entrypoint contract was accidentally lost
This is one of the most important audit threads going forward.
Given the user’s clarification, the absence of a top-level exported create() from @open-wa/wa-automate is less important than it first appeared.
The more correct question is now:
- does the SDK/client/core layer expose the fundamental session bootstrap contract clearly enough?
- and does
@open-wa/wa-automatecorrectly act as the main composed package that re-exports the right surfaces?
So this concern should no longer be read as:
“wa-automate must itself look like legacy create().”
It should instead be read as:
“the lower-level SDK/bootstrap contract must exist clearly somewhere below
wa-automate, andwa-automateshould re-export/compose it appropriately.”
From packages/wa-automate/src/cli-runtime.ts, the current CLI boot path is:
- parse CLI flags into
ParsedCliArgs - call
resolveConfig(...)from@open-wa/config - force/merge defaults including:
disableSpins: trueapiLifecycle: 'hybrid'socketMode: truehost: '0.0.0.0'port: 8002
- start
WAServer - create
PuppeteerDriver - call
createClient(...)from@open-wa/core - create
Transport - create
ClientFacadefrom@open-wa/client - attach QR updates from
openwaClient.eventsto the server - call
client.start()
This is a crucial finding:
The current v5 CLI starts the HTTP/API server before the WhatsApp client reaches ready state.
At first glance this looked like a likely readiness regression. After inspecting the shared API middleware, that conclusion needs refinement: v5 appears to intentionally allow the host/server shell to start early while blocking method invocation until the session is connected.
So the real audit question is no longer “does the server start too early?” but rather:
- which routes are safely available before client readiness
- whether those pre-ready surfaces are clearly communicated as such
- whether any user-facing/runtime-facing contract now incorrectly implies full readiness too early
This section only covers items that are already visible with high confidence from inspected files.
Evidence:
packages/schema/src/registry.tspackages/schema/src/implementor.ts
Observed behavior:
- methods are registered with metadata and schemas
- positional and object-parameter calling are both supported in
defineMethodV2 - registry metadata includes namespace, action, licensing, HTTP mapping, parameter order, and documentation-friendly metadata
implementMethod(...)turns registered schemas into runtime implementations with validation and argument normalization
Why this is materially better than legacy:
- legacy
Client.tswas behavior-rich but documentation/contract extraction was much harder - current v5 schema layer is explicitly designed to support docs, validation, metadata, and generators
- this aligns with the user’s note that replacing legacy
Client.tswith a schema system is not itself a regression
Audit status:
- classified as a good architectural change
- still needs deeper sanity checking against legacy behavioral contracts later
Evidence:
packages/config/src/index.ts- grep/test evidence in
packages/config/src/env.tsand config tests
Observed behavior:
- config schema is first-class
- env loading is explicit and schema-driven
- merge/precedence logic is formalized in a package rather than buried in ad hoc CLI code
Why this matters relative to legacy docs:
- the legacy pseudo docs and improvement notes explicitly pushed toward centralized, unconditional env absorption and clearer config contracts
- v5 appears directionally aligned with that goal
Audit status:
- provisionally classified as a good change
- follow-up needed to ensure actual runtime consumers honor the config package consistently
Evidence:
packages/core/src/events/eventMap.tspackages/core/src/plugins/PluginHost.ts
Observed behavior:
- there is a typed event map with many launch/session/webhook/persistence events
- event metadata includes
internalandsensitive - plugin hook mapping already exists for common integration surfaces
Why this is strong:
- legacy relied on wildcard event patterns and session-scoped namespaces
- v5 now appears to be moving toward typed, semantically named event contracts
- this is especially important given the goal that socket/plugin mode becomes central in v5
Audit status:
- classified as a likely improvement
- follow-up needed to test whether actual emitted lifecycle coverage matches the legacy behavioral benchmark, rather than merely naming the events
Evidence:
packages/core/src/plugins/PluginHost.ts
Observed behavior:
- plugins are registered against a typed event surface
- plugins support specific mapped hooks and catch-all event hooks
- plugin errors are isolated and logged rather than crashing registration outright
Relative to legacy:
- this aligns with the new v5 direction where integration/plugin behavior should be first-class rather than bolted on after launch
Audit status:
- classified as a strong intentional improvement
These are not speculative. They arise directly from code currently inspected.
Legacy benchmark source:
packages/legacy-documented/src/controllers/initializer.pseudo.mdpackages/legacy-documented/src/index.pseudo.md
Legacy contract summary:
- one authoritative bootstrap entrypoint
- launch config normalization
- auth handling
- readiness gating
- event/logging/session persistence/injection finalization before public readiness
Current v5 observation:
packages/wa-automate/src/index.tsexports composition pieces but not a visiblecreate()equivalent
Why this matters:
- if v5 is intentionally moving away from
create()then that needs to be documented as an intentional contract change - if it is accidental, this is a major regression in ergonomics and migration clarity
Current classification:
- open concern / likely regression unless justified as an intentional replacement contract
Evidence:
packages/wa-automate/src/cli-runtime.ts
Observed sequence:
- server is created and started
- startup summary is printed
- only afterwards is the driver/client/transport created and
client.start()called
Why this matters against legacy docs:
- legacy
initializerbenchmark strongly emphasizes that partial readiness must not be exposed as full readiness - the new pseudo docs explicitly say the system should not expose a partially initialized client as ready
What is not yet proven:
- whether
WAServer.start()exposes routes that require client readiness beforeserver.setClient(...)
Current classification:
- design difference with partial mitigation present; still requires deeper contract review
Evidence:
packages/wa-automate/src/cli-runtime.ts
The code explicitly prints compatibility warnings for missing parity in areas such as:
- ready webhook delivery not yet wired
- swagger-stats parity not restored
- tunnel parity not restored
- Chatwoot / Twilio / BotPress integration flags not wired into v5 CLI boot path
- webhook registration parity not restored
This is valuable because it gives us direct self-reported gap markers from the current implementation.
Current classification:
- confirmed missing parity, not inferred
Evidence:
packages/api/src/createApiServer.tspackages/api/src/createApiMiddleware.tspackages/api/src/routes/meta.tspackages/api/src/docs/openapi.tspackages/api/src/socket/SocketManager.tspackages/api/src/compat/session-path.ts
Observed behavior:
- v5 has a shared API package rather than embedding server behavior inside
Client.ts - the API package provides:
- Hono-based API server construction
- shared middleware generation
- API-key and rate-limit middleware
- socket capability dispatch via schema-defined methods
- docs/meta routes for OpenAPI/Postman/basic commands/listeners
- compatibility support for session-id-in-path requests
createApiMiddleware(...)blocks invocation with503while the session is not connected unless lifecycle is explicitly set toimmediate
Why this matters:
- this means the legacy
Client.middleware()idea was not simply deleted; it was extracted into a dedicated API package - that extraction is likely a good architectural move
- it also means earlier concerns about “server before client ready” must be interpreted through lifecycle gating rather than through startup order alone
Current classification:
- good architectural extraction, but still behaviorally incomplete relative to full legacy parity
Evidence:
packages/core/src/createClient.tspackages/core/src/transport/Transport.ts
Observed current flow in createClient().start():
- emit
core.starting - set session state to
STARTING transport.initialize()transport.navigate()- set state to
AUTHENTICATING transport.waitForQr()transport.injectWapi()- set state to
READY - emit
core.startedandclient.ready
Against legacy benchmark, what is visibly absent from this inspected path:
- update check/freshness behavior
- explicit session validity check before final readiness
- expired-session/nuke handling
- license preload/check/injection in the startup flow
- patch preload/apply flow in the startup path
- integrity check / repair-before-fail path
- explicit finalization step comparable to legacy
client.loaded()semantics - clear differentiation between authenticated vs QR merely generated
Important caution:
- some of these may exist elsewhere in the repo and not yet be wired into
createClient().start()
Current classification:
- high-confidence missing parity in the currently inspected launch path
Evidence:
packages/core/src/session/index.ts
Observed behavior:
- current
SessionManagerin core primarily stores and emits state transitions - visible states are only:
STARTINGAUTHENTICATINGREADYDISCONNECTEDSTOPPED
- there is no visible richer auth/session-validity classification in the inspected file
- there is no visible persisted-session lifecycle logic in the inspected file
Relative to legacy pseudo docs:
- legacy launch/session flow distinguished materially different states and branches such as:
- valid session reuse
- QR-required flow
- session invalid / nuke
- phone unreachable
- repair/retry/finalization states
Current classification:
- likely substantial reduction in session-state richness in the currently inspected core layer
Evidence:
packages/core/src/transport/Transport.ts
Observed behavior:
- emits before/after events
- sets
const success = true - returns success
- no visible actual WAPI injection logic in the inspected implementation
Current classification:
- clear implementation gap unless actual injection is delegated somewhere not yet inspected
Evidence:
packages/core/src/transport/Transport.ts
Observed behavior:
- polls the QR canvas parent
data-ref - emits
launch.auth.qr.generated - resolves with QR data
- on timeout emits
launch.auth.timeout
What it does not show in the inspected file:
- authenticated-state detection
- phone-out-of-reach distinction
- session-invalid detection
- QR scanned confirmation path tied to actual authenticated session
Current classification:
- substantial auth parity gap in currently inspected transport/auth implementation
This section is important because not every difference is a regression.
Evidence:
packages/wa-automate/src/cli-runtime.tssocketMode: trueforced in resolved CLI overrides
This matches the new v5 direction stated by the user.
Classification:
- good intentional change
Evidence:
packages/client/package.jsonpackages/core/src/createClient.tspackages/client/src/Client.tspackages/api/src/dashboard/launcher.ts
Observed behavior:
@open-wa/clientdepends on@open-wa/hyperemitter- core runtime uses
HyperEmitter - the dashboard sidecar explicitly communicates with Easy API through
@open-wa/socket-client
Interpretation:
- the repo is already moving toward shared infrastructure across layers rather than duplicating layer-specific integration primitives.
- this is aligned with the plugin-at-both-levels vision.
Classification:
- good architectural alignment
Evidence:
packages/core/src/events/eventMap.ts
This is better than legacy in one critical way: it creates an explicit place to reason about which events are sensitive.
That aligns well with the pseudo-doc benchmark requirements around observability and non-leakage.
Classification:
- good intentional change
Evidence:
packages/client/src/Client.ts
Observed behavior:
- facade composes core client + transport + method modules
- method groups are broken out by domain
- listener manager is separate
- collector functionality is imported from domain package
Why this is likely good:
- legacy
Client.tswas huge and behavior-dense - the new structure is more auditable and decomposed
Critical caution:
- this is only an improvement if the behavioral contracts still survive the decomposition
Classification:
- architecturally positive, behaviorally still under audit
Evidence:
packages/client/src/Client.tspackages/core/src/createClient.tspackages/wa-automate/src/cli-runtime.tspackages/api/src/createApiServer.ts
Observed layering:
coreowns runtime lifecycle/events/transport/pluginsclientis a user-facing facade over that runtimeapiis a shared server layerwa-automatecomposes the CLI/Easy API host
Interpretation:
- this is broadly the right layering for the clarified architecture
- the main remaining question is no longer “is the layering wrong?” but “is the lower-level session contract behaviorally complete enough?”
Classification:
- layering mostly aligned; behavioral completeness still the larger issue
Evidence:
apps/cli/*apps/orchestrator-cli/*apps/dashboard-neo/*apps/orchestrator-dashboard/*
Observed behavior:
- runnable binaries and dashboards are split into app packages
- reusable logic remains primarily in
packages/*
Why this is good:
- this reduces pressure to force every runtime concern into a reusable library package
- it gives the architecture room to keep SDK/core reusable while letting CLI/orchestrator/dashboard shells remain opinionated
Classification:
- good structural alignment
Evidence:
packages/api/src/routes/meta.tspackages/api/src/docs/openapi.ts- schema registry/docs generation files already inspected earlier
Observed behavior:
- API explorer/docs are now served from a shared API layer
- command/listener inventories are generated from schema/event registry sources
- deprecated legacy routes like
/swagger-stats,/meta/codegen/:language, and process-control routes are explicitly surfaced as deprecated/410 rather than silently missing
Why this is good:
- this is cleaner than the old mixed CLI/server/docs generation flow
- it aligns with the schema-first approach and makes the docs surface easier to reason about
Current classification:
- good intentional change
Evidence:
packages/api/src/compat/session-path.ts
Observed behavior:
- there is explicit compatibility logic for validating session-id-in-path requests when that mode is enabled
Why this matters:
- this suggests the v5 API layer is attempting to preserve old access patterns where practical instead of discarding them wholesale
Current classification:
- small but positive compatibility signal
Evidence:
packages/client/src/events/EventManager.tspackages/domain/src/structures/Collector.tspackages/domain/src/structures/MessageCollector.tspackages/domain/src/index.ts
Observed behavior:
- collector primitives have been moved into a dedicated
domainpackage MessageCollectorstill exists as a first-class abstraction- the client package now uses a
ListenerManagerthat bridges typed runtime events into the old convenience listener surface (onMessage,onAck,onStateChanged,onLogout, etc.) - listener registration includes payload validation against event schemas and optional queueing behavior
Why this matters relative to the pseudo docs:
- the legacy pseudo docs treated collectors and listener surfaces as important ergonomic/runtime primitives
- v5 appears to have preserved those ideas while making them more modular and more typed
Important caution:
- this does not yet prove full event parity; it only shows that the abstraction category itself was not lost
Current classification:
- good architectural change with likely preserved intent
| Area | Current v5 status in this pass | Initial judgment |
|---|---|---|
| schema-driven method system | directly observed | strong improvement |
| config schema + env/merge package | directly observed | strong improvement |
| typed event map | directly observed | likely improvement |
| plugin host | directly observed | strong improvement |
| shared API extraction from Client.middleware-style behavior | directly observed | strong improvement |
| docs/meta generation via shared API + schema | directly observed | strong improvement |
| collector/listener abstraction split into client+domain packages | directly observed | likely improvement |
| main package as composed entrypoint | directly observed in package metadata | aligned with intended architecture |
| wa-automate re-export breadth (CLI + SDK/client + core conveniences) | top-level package role is correct, but inspected root exports still look incomplete | likely composition gap |
| app wrappers separated from reusable library packages | directly observed | good structural alignment |
| top-level create parity at wa-automate root | less relevant after clarified architecture; SDK bootstrap clarity matters more | reframed concern |
| CLI readiness gating | host starts early but API middleware blocks invocation when disconnected | design difference / needs deeper review |
| webhook/integration parity | explicitly warned as missing | confirmed missing parity |
| update-check parity | not seen in inspected startup path | likely missing |
| patch/license/integrity startup parity | not seen in inspected startup path | likely missing |
| auth-state differentiation | not seen in inspected startup path | likely missing |
| session-state richness in core | directly inspected and currently minimal | likely regression |
| WAPI injection implementation | currently stub-like in inspected transport | probable major gap |
The next pass should inspect, in order:
- whether there is another v5 launch/auth controller outside
core/createClient.ts - whether WAPI injection is implemented elsewhere and merely not wired in the inspected transport file
- whether session validity, stale session, logout, and reinjection logic exists elsewhere in
core,driver-*, orwa-automate - which API/server routes are intentionally allowed pre-ready and whether that contract is explicit enough
- how much of the legacy
initializerbehavioral contract is meant to live in:core/createClient.tsTransportSessionManager- server lifecycle
- plugins
- how schema-generated method surfaces map back onto the legacy client capability inventory
The current v5 work is not merely a bad rewrite of legacy. There are real, meaningful architectural improvements already present:
- schema registry and method metadata
- dedicated config package with formal precedence handling
- typed event map with sensitive/internal metadata
- plugin host model
- package decomposition of major concerns
However, the current inspected startup/runtime path still appears to be far below legacy behavioral completeness in the areas that mattered most in the pseudo docs:
- launch-state richness
- auth-state richness
- readiness gating
- session validity handling
- license/patch/integrity lifecycle
- integration/webhook parity
So the current picture is:
v5 is already architecturally more modern, but in the inspected runtime path it still looks behaviorally underbuilt relative to the legacy benchmark.
That is not the final audit conclusion. It is the correct high-confidence conclusion for this pass.
This section extends the first pass with additional directly inspected files in the API layer and core-adjacent runtime.
packages/api/src/createApiServer.tspackages/api/src/createApiMiddleware.tspackages/api/src/socket/SocketManager.tspackages/api/src/routes/meta.tspackages/api/src/docs/openapi.tspackages/api/src/compat/session-path.tspackages/api/src/invoke-client-method.tspackages/api/src/types.tspackages/schema/src/http-manifest.tspackages/core/src/session/index.tspackages/core/src/controllers/browser.ignore.tspackages/core/test/e2e/createClient.e2e.test.tspackages/schema/migration_plan_doc.md
The background exploration and direct reads support the same conclusion:
schemais the single source of truth for method definitions, metadata, and docs surfacesapiuses that schema layer to build runtime method maps, docs, and socket dispatchclientis a facade over core runtime + transport + domain methodscorehandles lifecycle, events, transport, plugins, and session state
This means the legacy Client.ts was not simply “shrunk”; it was decomposed into:
- schema contract layer
- runtime core layer
- typed facade layer
- shared API host layer
That decomposition is real and intentional.
From direct inspection:
packages/api/src/createApiMiddleware.tsvalidates request payloads against schema input definitions- method invocation is driven by schema metadata and
parameterOrder invokeClientMethod(...)reconstructs positional args from named payloadsroutes/meta.tsbuilds docs and command/listener inventories from registry sourcesSocketManagerdynamically wires schema-defined methods over socket.io
This is important because it means v5 already has one of the key things legacy lacked:
a single contract pipeline from schema definition -> runtime invocation -> HTTP/socket surface -> docs output
That is a major strategic improvement.
This contrast is becoming clearer:
- schema/API/docs surfaces are relatively systematic
- launch/auth/session runtime appears comparatively underimplemented in the active path
This asymmetry likely explains why v5 can look strong architecturally while still feeling operationally substandard compared to the legacy runtime.
Evidence:
packages/api/src/createApiMiddleware.ts
Observed behavior:
- middleware checks
isSessionConnected() - unless
apiLifecycle === 'immediate', it returns503while the session is not connected
Why this matters:
- it mitigates the earlier concern that the server shell being up necessarily means the session is falsely “ready”
- v5 clearly distinguishes:
- server host availability
- actual session readiness for method invocation
Audit impact:
- this reduces the severity of the earlier readiness concern
- but it does not fully remove it, because the UX/contract still needs evaluation: what is visible to users and integrations before session readiness, and is that explicit enough?
Classification:
- good design element that partially mitigates readiness regression risk
Evidence:
packages/schema/migration_plan_doc.md
Observed goals:
- dual-mode inputs
- rich metadata
- runtime normalization
- automatic WAPI bridge through
this.pup
Why this matters:
- it confirms that the schema direction was not an accidental detour
- it was explicitly designed to solve exactly the contract/discoverability/generation problems that legacy made hard
Classification:
- good intentional redesign, confirmed by design documentation
Evidence:
packages/core/src/session/index.ts
Observed behavior:
SessionManagercurrently stores a single state value and emits state-change events- there is no visible richer session-state model in the inspected file beyond:
DISCONNECTEDSTARTINGAUTHENTICATINGREADYSTOPPED
Compared with legacy benchmark expectations:
- this is far thinner than the state richness implied by the legacy pseudo docs
- the event map actually declares many finer-grained launch/session states and situations, but the inspected active core path does not appear to drive most of them yet
Classification:
- likely real regression in operational/session-state richness, unless another uninspected layer owns it
Evidence:
packages/core/src/events/eventMap.tspackages/core/src/createClient.tspackages/core/src/transport/Transport.ts
Observed contrast:
- event map defines a very rich launch/session/persistence/license/patch/reinject vocabulary
- active inspected runtime emits only a relatively small subset of that vocabulary in practice
Interpretation:
- this is not “no design”; it is “design declared faster than implementation completed”
This is an important audit distinction:
v5 already knows many of the right contracts, but the active runtime path does not yet seem to honor them comprehensively.
Classification:
- contract maturity ahead of runtime maturity
Evidence:
packages/core/src/controllers/browser.ignore.ts
Observed behavior:
- this file contains much richer, legacy-style browser/session bootstrap logic including:
- session data restoration
- MD-specific behavior
- quick auth interception
- reinjection-oriented request handling
- session data file lookup/delete logic
- multi-step browser init and page prep
- repeated WAPI script injection
- it also contains clearly draft/dev-oriented behavior such as devtools setup and Puppeteer-era implementation details
Additional context:
notes/issues/11-core-monorepo-refactor.mdexplicitly maps bothcontrollers/browser.tsandcontrollers/browser.ignore.tstowarddriver-puppeteer/- the active core transport currently exports only
Transport.ts, and the inspected runtime path does not importbrowser.ignore.ts
Why this matters:
- it suggests some legacy browser/session behavior was preserved as migration material, but not that the active runtime currently benefits from it
- it also suggests the intended destination for much of that logic was driver-specific code, not necessarily the active core transport in its current form
This matters for audit tone:
- some gaps are “missing from active implementation”
- some ideas are “preserved in draft/parked migration code”
- these should not be counted as completed parity just because the code exists in-repo
Classification:
- important evidence of incomplete migration, but not evidence of active runtime parity
Evidence:
packages/core/test/e2e/createClient.e2e.test.ts
Observed behavior:
- current inspected E2E test verifies that
launch.auth.qr.generatedis emitted when QR appears - that is useful, but narrow relative to legacy launch complexity
Implication:
- current runtime verification appears to focus on a small slice of launch behavior
- it does not yet reflect the breadth of the pseudo-doc benchmark surface
Classification:
- test coverage currently appears much narrower than required behavioral parity
The strongest current interpretation is now:
-
Architecture direction is mostly right
- schema-first contracts
- separate config system
- dedicated API layer
- typed event system
- plugin host
- modular client/domain split
-
Active runtime depth is not yet matching that architecture
- launch/auth/session behavior is still far thinner than legacy expectations
- many of the right events/contracts exist on paper but not yet fully in the active path
-
Some legacy-equivalent runtime logic may be parked, not lost
browser.ignore.tsis strong evidence of that
This makes the problem statement more precise:
v5 does not primarily suffer from bad architectural direction. It suffers from an incomplete translation of legacy runtime depth into the new architecture.
That is a much more actionable diagnosis than “v5 is just worse.”
- schema registry / implementor / manifest pipeline
- config package and precedence handling
- shared API server/middleware/docs extraction
- typed event map with sensitivity metadata
- plugin host model
- modular collector/listener split
- socket mode being treated as a central runtime concern
- replacement of monolithic
Client.tswith schema + core + facade + API split - early server startup with middleware lifecycle gating
- launch state richness
- authentication state richness
- session validity classification
- recovery/retry/reinject behavior in the active runtime path
- patch/license/integrity lifecycle in the active runtime path
- completeness of integration/webhook parity in CLI boot
- breadth of end-to-end runtime tests
- browser/session bootstrap depth in
browser.ignore.ts - richer reinjection/session restore ideas implied by the event map but not wired into the active startup path
17.1 Session compression/backup concerns appear to have been extracted out of browser code into session-sync
Evidence:
packages/session-sync/src/index.tspackages/session-sync/src/local-compression.tspackages/session-sync/src/s3-sync.ts
Observed behavior:
- v5 has a dedicated
session-syncpackage LocalSessionCompressionwatches a session directory and produces.zstarchives on change with throttlingS3SyncManagerhandles backup/restore/delete/existence checks for compressed session artifacts in object storage
Interpretation:
- this supports the user’s clarification that some ideas seen in
browser.ignore.tswere draft-y or exploratory in that file - it also shows that session compression/backup was not simply forgotten; it has been moved toward a dedicated package boundary
Classification:
- good extraction, though not yet proof that it is integrated into the active session lifecycle
17.2 Active runtime still does not appear to implement the richer launch features declared in the event map
Evidence:
packages/core/src/createClient.tspackages/core/src/transport/Transport.tspackages/core/src/events/eventMap.ts
Observed contrast after targeted searches:
- event map declares launch/license/patch/reinject/stale-session/compression semantics
- active inspected startup path still mainly does:
- initialize browser
- navigate
- wait for QR
- inject WAPI (stub-like)
- mark ready
Interpretation:
- the audit concern is now more precise:
- v5 contract vocabulary is ahead of implementation
browser.ignore.tsdoes not close that gapsession-syncextraction does not close that gap unless integrated into startup/session lifecycle
Classification:
- implementation gap remains real
17.3 Current client.start() confirms the active bootstrap is still only a thin wrapper over core startup
Evidence:
packages/client/src/Client.ts
Observed behavior:
client.start()simply delegates to_client.start()from core- no additional client-layer finalization equivalent to legacy
loaded()is visible in the inspected method
Interpretation:
- this strengthens the current audit position that legacy “constructed vs really ready” semantics are not yet fully rebuilt in the active path
Classification:
- likely missing readiness/finalization depth
flowchart LR
subgraph Legacy
LCreate[initializer.ts create entry]
LBrowser[browser.ts]
LAuth[auth.ts]
LPatch[patch_manager.ts]
LChecks[launch_checks.ts]
LClient[Client.ts]
LEvents[events.ts + EventManager.ts]
LCLI[cli/index.ts + server.ts + setup.ts]
LPopup[popup/*]
LCollectors[Collector.ts / MessageCollector.ts]
LSessionBackup[session data backup/compression ideas]
end
subgraph V5[V5 package/layer destinations]
VWA[wa-automate\nmain composition package]
VCLI[cli + apps/cli\nEasy API host wrapper]
VCore[core\nlifecycle / transport / session / plugins]
VClient[client\nSDK facade]
VSchema[schema\ncontracts / docs / manifests]
VAPI[api\nshared HTTP/socket/docs host]
VDomain[domain\ncollectors]
VDrivers[driver-puppeteer / driver-playwright]
VSessionSync[session-sync\ncompression / backup]
VDash[dashboard-neo]
VOrch[orchestrator + orchestrator-cli + orchestrator-dashboard]
end
LCreate -->|intended split| VCore
LCreate -->|composed and surfaced through| VWA
LBrowser -->|intended destination| VDrivers
LAuth -->|intended destination| VCore
LPatch -->|intended destination| VCore
LChecks -->|intended destination| VCore
LClient -->|split into| VClient
LClient -->|method contracts extracted into| VSchema
LClient -->|server concerns extracted into| VAPI
LEvents -->|typed transport + plugin events| VCore
LEvents -->|shared event infra| VWA
LCLI -->|opinionated host layer| VCLI
LCLI -->|composed from| VWA
LPopup -->|likely CLI/session-host concern| VCLI
LCollectors -->|extracted| VDomain
LSessionBackup -->|extracted| VSessionSync
VCLI --> VDash
VOrch -->|manages multiple CLI sessions| VCLI
classDef improved fill:#153,stroke:#4ad,color:#fff;
classDef missing fill:#431,stroke:#f66,color:#fff;
classDef partial fill:#543,stroke:#fc3,color:#fff;
class VSchema,VAPI,VDomain improved;
class VCore,VClient,VCLI partial;
class LPatch,LChecks,LAuth missing;
- Improved: schema/docs/API extraction and collectors/domain separation look like real wins.
- Partial: core/client/CLI layering is mostly right, but active behavioral parity is incomplete.
- Missing or not yet active: launch/auth/patch/integrity depth from legacy is not yet convincingly present in the active runtime path.
This matrix is intended to tighten the audit language. A behavior should only be called a true regression once:
- the intended v5 owner is identified,
- the active codepath for that owner is inspected,
- the legacy-relevant behavior is still absent there.
Until then, findings should be classified as one of:
- Active — visibly implemented in the active runtime path
- Declared only — event/schema/contract exists, but active implementation is not yet evidenced
- Parked — draft or migration-era logic exists in non-active files/packages
- Not yet evidenced — no active or parked implementation was found in this pass
| Legacy capability / contract | Intended v5 owner | Current evidence state | Notes |
|---|---|---|---|
| Main npm composition entrypoint | wa-automate |
Active | Package metadata and root exports confirm this role. |
| CLI as Easy API host | wa-automate + cli + apps/cli |
Active | Clear composition/wrapper chain exists. |
| SDK/client as lower-level session surface | client + core |
Active but incomplete | Structure exists, behavioral depth still under audit. |
| Schema-based client contracts | schema |
Active | Strongly evidenced. |
| Shared API/docs/socket host | api |
Active | Strongly evidenced. |
| Collector/listener abstractions | client + domain |
Active | Preserved in modular form. |
| Dashboard alongside CLI host | api + apps/dashboard-neo |
Active | Sidecar launcher and app package exist. |
| Orchestrator managing CLI sessions | orchestrator + apps/orchestrator-cli |
Active | Strong evidence. |
| Orchestrator dashboard | apps/orchestrator-dashboard |
Active | App exists; deeper linkage still to inspect later. |
| Rich launch/auth/session event vocabulary | core/events |
Declared only | Event map is rich; active runtime emits only a subset in inspected path. |
| Session state richness comparable to legacy | core/session |
Active but thin | Active owner inspected; currently much thinner than legacy. |
| WAPI injection in active startup | core/transport or adjacent active transport owner |
Active but thin | Active injectWapi() exists in the startup path, but currently appears stub-like and no richer alternate active path was evidenced. |
| Session validity / stale-session detection | likely core/session + core/transport |
Declared only | Event vocabulary exists; active behavior not evidenced. |
| Reinject / recovery loops | likely core/session + core/transport |
Declared only / parked | Event map declares it; parked browser draft implies old ideas; active path not evidenced. |
| Patch lifecycle during launch | likely core transport/bootstrap |
Declared only | Events declare it; active launch path does not yet show it. |
| License lifecycle during launch | likely core transport/bootstrap |
Declared only | Same pattern as patch lifecycle. |
| Integrity / launch checks | likely core bootstrap |
Not yet evidenced | No active equivalent found in inspected startup path. |
| Popup/QR side UI | likely CLI/Easy API host + dashboard surfaces | Active but changed | /qr endpoint and dashboard QR views exist; popup-style observer semantics are not one-to-one with legacy. |
| Session compression / backup | session-sync |
Active as package, integration not yet evidenced | Package exists, but startup/runtime integration not yet proven. |
| browser.ts-era Puppeteer bootstrap depth | driver-puppeteer + core boundary |
Parked | browser.ignore.ts exists as migration material, not active parity. |
- Do not call something a full regression if it is only “declared only” or “parked”.
- Do treat “active but thin” findings as the highest-confidence parity problems.
- Do prioritize capabilities where the intended owner is already obvious and the active implementation is already inspected.
The next pass should now focus on the highest-value unresolved questions:
- inspect whether
browser.ignore.tsis intended for migration, replacement, or deletion - inspect whether active WAPI injection exists outside
Transport.injectWapi() - inspect whether auth/session repair logic exists elsewhere in active codepaths
- inspect how
eventRegistryin schema relates toListenerManagerand listener parity coverage - inspect the API/debug routes and compatibility/deprecation surfaces for what was intentionally not carried forward
- inspect whether the SDK/client/core layer exposes a clear low-level session bootstrap contract that
wa-automatecan re-export appropriately - inspect whether
@open-wa/wa-automateshould re-export more of the SDK/client layer than it currently does
This section records which earlier “next steps” are now materially resolved by later passes, and which remain open.
Current status:
- resolved enough for now
What we now know:
- it is not part of the active inspected startup path
- it contains parked legacy-heavy Puppeteer bootstrap logic plus draft/dev-era concerns
- it should be treated as migration material, not as evidence of active parity
- package-planning notes point toward
driver-puppeteeras its likely conceptual destination
Current status:
- resolved enough for now
What we now know:
- the active inspected
corebootstrap is still centered oncreateClient.ts+transport/Transport.ts core/src/controllers/does not currently provide another active launch/auth controller beyond parked material
Current status:
- resolved enough for now
What we now know:
- these concerns were extracted into
packages/session-sync - that is a real architectural move, not simple omission
- what remains open is lifecycle integration, not package existence
Current status:
- still open, but narrowed
What we now know:
- the active inspected
Transport.injectWapi()remains stub-like - no alternate active implementation was evidenced in the searched active paths
- parked code does not close this gap
Current status:
- still open, but increasingly likely to be a real active-path gap
What we now know:
- rich legacy auth/session repair semantics exist in benchmark docs and legacy code
- the active inspected v5 path does not yet evidence comparable state richness or repair loops
- event vocabulary alone is not enough to count as parity
Current status:
- partially resolved
What we now know:
- the shared API server exposes an active
/qrroute whenezqris enabled dashboard-neoactively renders QR/session state in its main session overview route- the older dashboard app also has a dedicated
/qrroute - what remains open is whether popup-style local auth observer behavior is intentionally replaced by these QR surfaces or still expected as a separate capability
Current status:
- partially resolved
What we now know:
@open-wa/coreactively exportscreateClient,OpenWAClient, events, plugins, session, and transport primitives@open-wa/clientactively exports theClientfacade plus collector/domain types- this is enough to say the low-level bootstrap/SDK contract exists below
wa-automate - what remains open is its behavioral completeness and whether
wa-automateshould re-export more of that surface
After the additional scans and oracle review, the audit is on firmer footing:
- package boundaries and product layering look increasingly intentional and aligned with the clarified architecture
- some earlier concerns have been downgraded from “possible regression” to “parked code / extracted subsystem / composition nuance”
- the remaining highest-confidence problems are concentrated in the active SDK/core bootstrap path itself, especially around injection, auth/session richness, and final readiness depth
So the current best reading is:
the architecture is converging in the right shape, but the active lower-level runtime still does not yet convincingly satisfy the legacy behavioral benchmark in its bootstrap path.
Evidence:
packages/schema/src/events/registry.tspackages/client/src/events/EventManager.tspackages/api/src/routes/meta.ts
Observed behavior:
schemaowns a distincteventRegistryfor listener-facing event contracts and metadataclientListenerManagerimportseventRegistryfrom@open-wa/schema- listener registration is validated against event schemas and bridged from typed runtime events
- API meta routes expose listener inventories using that same registry
Interpretation:
- this means listener parity is more mature than some earlier high-level wording might suggest
- there is now a single event-contract path from schema -> client listener manager -> API explorer/docs
- the remaining open question is not whether listener parity machinery exists, but whether the underlying runtime emits enough of the expected events with legacy-comparable richness
Classification:
- good architectural implementation with remaining runtime-depth questions
Evidence:
packages/api/src/routes/debug.tspackages/api/src/routes/meta.tspackages/api/src/compat/deprecation.ts
Observed behavior:
- dashboard-focused debug endpoints exist for memory, config inspection, process info, and integration config CRUD
- deprecated legacy surfaces are not silently dropped; they return redirects or
410JSON with explicit replacement guidance - examples include:
/swagger-stats/meta/codegen/:language/meta/process/exit/meta/process/restart/disengage
Interpretation:
- this is a positive sign of migration discipline
- some legacy features are being intentionally closed or replaced, rather than merely omitted without explanation
Classification:
- good intentional change with explicit migration signaling
Evidence:
packages/client/src/index.tspackages/core/src/index.tspackages/wa-automate/src/index.ts
Observed behavior:
@open-wa/clientexports the SDK facade and domain collector types@open-wa/coreexportscreateClient,OpenWAClient, events, plugins, session, and transport primitives@open-wa/wa-automatecurrently exports:WAServerAPILifecycleManagerSessionManager- CLI helpers
- config/schema helpers
- API server helpers
@open-wa/wa-automatedoes not currently re-export obvious SDK/client entrypoints likeClientorcreateClient
Interpretation:
- this does not make the architecture wrong, but it does mean the top-level product package has not yet fully realized the “main entrypoint re-exporting CLI, SDK, etc.” vision the user described
Classification:
- likely composition/export-shape gap rather than runtime regression
Evidence:
- dashboard surfaces exist
- no active popup-equivalent auth UI has yet been evidenced in inspected v5 runtime files
Interpretation:
- dashboards are not the same thing as the old popup auth observer contract
- this capability should remain open in the audit until a concrete replacement or deliberate non-goal is evidenced
Classification:
- still open
Evidence:
packages/api/src/createApiServer.tsapps/dashboard-neo/src/routes/index.tsxapps/dashboard/src/routes/qr.tsx
Observed behavior:
- the shared API server exposes
/qrand returns the latest QR payload whenezqris enabled dashboard-neorenders QR and session connectivity directly in its main session overview- the older dashboard app contains a dedicated
/qrroute that fetches from the Easy API host
Interpretation:
- the old popup capability does have active replacement surfaces in v5
- however, those surfaces are API/dashboard-oriented rather than a local popup observer server with legacy semantics
- so parity here is better described as active but changed rather than “missing” or “fully preserved”
- based on later product clarification, the old temporary/local QR popup server should be treated as a legacy hack and not as a required parity target;
ezqr-style QR surfacing is the intended forward direction, with local-only options to be reconsidered later if needed
Classification:
- active replacement surface exists; local popup parity is an intentional non-goal for now
Evidence:
packages/core/src/index.tspackages/client/src/index.tspackages/client/src/Client.ts
Observed behavior:
@open-wa/coreexportscreateClient,CreateClientOptions,OpenWAClient, plus event/plugin/session/transport primitives@open-wa/clientexports theClientfacade and collector/domain helpersClientexplicitly composesOpenWAClientplusTransportplus domain-specific method modules
Interpretation:
- the lower-level SDK/bootstrap contract is not missing; it is already distributed across
coreandclient - the remaining questions are:
- whether that contract is behaviorally complete enough relative to legacy
- whether the top-level
wa-automatepackage should re-export more of it for ergonomic reasons
Classification:
- resolved in structural terms; still open in behavioral completeness and top-level export ergonomics
Evidence:
packages/core/src/index.tspackages/client/src/index.tspackages/wa-automate/src/index.ts
Observed behavior:
- the lower-level contracts already exist in dedicated packages
wa-automatecurrently re-exports only a narrower composition subset
Interpretation:
- the unresolved issue here is no longer “missing SDK layer”
- it is “whether the main product package should surface more of the already-existing SDK/core entrypoints”
Classification:
- composition/export-shape gap, not structural absence
Evidence:
packages/wa-automate/src/index.tspackages/cli/src/index.ts- user-clarified architecture intent recorded earlier in this document
Observed behavior:
wa-automatecurrently exposes CLI helpers, API helpers, config/schema, and server/session-manager pieces- it does not currently re-export the obvious lower-level SDK/client entrypoints that already exist in
@open-wa/coreand@open-wa/client @open-wa/cliis currently just a thin wrapper over@open-wa/wa-automate
Interpretation:
- if the clarified architecture is treated as authoritative, then the current
wa-automateexport shape likely falls short of the intended “main package re-exporting CLI and SDK” ergonomics - this is not a runtime failure, but it does look like a real composition gap relative to the desired product surface
Classification:
- high-confidence ergonomics/composition gap
Evidence:
packages/core/src/transport/Transport.tspackages/driver-puppeteer/src/index.tspackages/driver-playwright/src/index.ts- targeted searches across active
driver-*andcorepackages
Observed behavior:
- the active startup path calls
Transport.injectWapi() - that method currently emits before/after events and returns
success = truewithout visible injection logic - no alternative active injection implementation was evidenced in the inspected
driver-puppeteerordriver-playwrightpackage surfaces - the only active
window.WAPI...usage found incoreis the plugin proxy call path, not bootstrapping/injection logic
Interpretation:
- this meaningfully strengthens the earlier audit concern
- the item should no longer be treated as merely “not yet adequately evidenced” in a vague sense
- it is better classified as an active-path implementation that currently appears too thin to satisfy legacy-equivalent injection behavior
- later product clarification also upgrades the severity of this finding: preserving runtime WAPI injection is not optional in v5, it is a must-preserve core contract
Classification:
- high-confidence active-path gap
Evidence:
packages/core/src/createClient.tspackages/core/src/transport/Transport.ts- targeted searches across active
coreanddriver-*packages
Observed behavior:
- the active startup/auth path is still limited to:
- browser init
- navigation
- QR wait
- WAPI injection
- ready state
- no active equivalents were evidenced for:
- stale session / nuke detection
- phone-out-of-reach differentiation
- repair/reinject loops as active behavior
- deeper authenticated-vs-QR-required branching comparable to legacy auth flow
Interpretation:
- this does not rely solely on the absence of code in one file anymore
- after targeted scans of the active lower layers, the likelihood that these are genuine active-path gaps is now higher
- this gap matters even more because the legacy launcher’s injection/repair behavior was tightly coupled to maintaining a live, patched runtime rather than just reaching a nominal READY state
Classification:
- high-confidence active-path gap
Evidence:
packages/core/src/createClient.tspackages/client/src/Client.tspackages/wa-automate/src/cli-runtime.tspackages/wa-automate/src/server/lifecycle-manager.ts
Observed behavior:
createClient().start()still transitions directly from QR wait and stub-like WAPI injection toREADYclient.start()in@open-wa/clientis only a direct delegation to core startup- CLI binds the client into the API server after
client.start()returns and then prints readiness state APILifecycleManagercomments explicitly note that hybrid mode is not yet the more advanced implementation it may eventually become
Interpretation:
- this strengthens the remaining concern that legacy-style “constructed vs truly finalized and ready” semantics are not yet deeply rebuilt in the active path
- the issue is not just missing auth richness; it is also the absence of a visibly deeper post-bootstrap finalization layer comparable to legacy
loaded()/final checks/final patching semantics - the legacy pseudo docs and improvement notes also make clear that patch and license overlay belong in this deeper finalization contract, not as optional postscript behavior
Classification:
- high-confidence active-path gap
- popup/local QR server parity: intentional non-goal; replaced directionally by ezqr/dashboard/API surfaces
- low-level SDK/bootstrap contract: exists clearly across core + client
- whether the current
wa-automateexport breadth should be treated as a required product-surface change in this migration - how the must-preserve WAPI + patch + license-patch lifecycle should be re-established in the active lower-level runtime path
- active WAPI injection in the current startup path appears materially underimplemented
- active auth/session repair richness in the current startup path appears materially underimplemented
- final readiness/finalization depth in the current startup path appears materially underimplemented
wa-automateexport breadth appears materially narrower than the clarified target architecture
- temporary/local popup QR server parity should not be treated as a required migration target;
ezqr-style replacement is the current intended direction
This is a significantly tighter unresolved set than earlier passes.
The following should now be treated as authoritative guidance for subsequent migration work:
- The old temporary/local QR popup server was always a disliked stopgap and should not drive parity requirements.
ezqr-style QR surfacing is the intended replacement direction for now.- The WAPI injection lifecycle is core runtime behavior and must be preserved in v5.
- Live patch and license-patch application are also core runtime behavior and belong inside the lower-level runtime bootstrap/finalization contract.
This changes the priority ordering of remaining work:
- highest priority runtime gaps:
- WAPI injection
- patch lifecycle
- license-patch lifecycle
- auth/session repair richness tied to the above
- final readiness/finalization depth
- lower priority parity concern:
- local popup observer UX
This section defines the target contract for the lower-level v5 runtime bootstrap, meaning the session/bootstrap behavior that should exist below the Easy API host layer and below dashboard/orchestrator concerns.
It is intentionally written as a runtime contract, not an implementation recipe. The goal is to specify what v5 must guarantee and what it may intentionally change.
This contract applies to the layer currently distributed across:
@open-wa/core@open-wa/client- the active transport/driver bootstrap path
This contract does not prescribe:
- exact browser library choices
- exact injection techniques
- exact patch transport/storage mechanisms
- exact terminal/TUI presentation
- exact dashboard/UI implementation
The following are required runtime obligations and must be preserved in v5:
- ordered bootstrap phases
- WAPI/runtime injection as a first-class bootstrap concern
- live patch lifecycle as a first-class bootstrap/finalization concern
- license-patch lifecycle as a first-class bootstrap/finalization concern
- auth/session restoration and repair depth materially sufficient to avoid shallow false-readiness
- a strict readiness gate that opens only after required runtime obligations are satisfied
- externally observable lifecycle events and failure signals
The following may vary without counting as regressions:
- update-check transport/mechanism
- exact QR/dashboard/local surfacing mechanics
- exact progress UX / terminal output
- extra diagnostics or extra repair heuristics beyond the minimum contract
- exact internal state object layout, provided the observable guarantees survive
The following are explicitly not required parity targets for now:
- the old temporary/local QR popup observer server
- legacy MD/non-MD compatibility branching
- preserving legacy internal sequencing where it has no observable contract impact
- preserving legacy implementation shape purely for familiarity
The lower-level runtime should expose or internally satisfy the following ordered phases.
Required outcome:
- runtime inputs are normalized enough that browser/session bootstrap can begin deterministically
Must include:
- resolved session identity
- resolved environment/config inputs
- resolved driver/transport prerequisites
- resolved policy inputs relevant to bootstrap (timeouts, session persistence, patch/license policy, readiness policy)
Must not do:
- start browser/page work before bootstrap-critical config is normalized
- silently accept contradictory runtime policy without normalization or explicit override rules
Required outcome:
- a live page/browser runtime exists and is capable of navigation and later runtime injection work
Must include:
- browser initialization
- page creation
- initial navigation to WA Web
- enough page setup that auth detection and injection can proceed
Must not do:
- declare session readiness merely because a browser and page exist
Required outcome:
- the runtime knows which of the materially different session/auth states it is currently in
At minimum, the contract should distinguish:
- already authenticated / restored session is valid
- interactive auth required
- persisted session invalid or stale
- timeout/offline/unreachable-style auth blockers
Must not do:
- collapse all non-success states into the same generic failure bucket
- proceed as though QR-generation alone implies a healthy session
Required outcome:
- the in-page runtime required for client method execution actually exists and is usable
This phase must treat WAPI/runtime injection as a real bootstrap obligation, not a ceremonial event emission.
Must include:
- actual runtime injection or equivalent runtime activation
- a verifiable success condition stronger than “no exception thrown”
May include:
- early injection and final injection as separate subphases
- idempotent reinjection behavior when needed
Must not do:
- emit successful injection lifecycle events without an actual corresponding runtime capability being established
Required outcome:
- required runtime overlays are applied only after the page/session is sufficiently valid to receive them
This phase should preserve the contractual pattern from legacy:
- preload/fetch if needed
- validate applicability
- inject/apply
- expose success/failure outcome
Must include separate handling for:
- live patch lifecycle
- license patch lifecycle
Must not do:
- blur WAPI injection, patch application, and license-patch application into one unobservable black box
- silently skip required overlays while still advancing to “ready”
Required outcome:
- the runtime has verified that the session is actually usable, and if repair is needed, the repair path has either succeeded or terminated clearly
Must include some equivalent to:
- session validity confirmation beyond raw page presence
- repair/retry/reinject path where appropriate
- integrity verification or capability verification after injection/overlay steps
Must not do:
- transition to ready immediately after a thin injection step if the runtime has not yet proven operational usability
Required outcome:
- only now may the runtime expose itself as operationally ready to upstream consumers
The readiness gate must mean more than “startup function finished.”
A valid READY should mean:
- browser/page boot completed
- auth state is resolved enough to proceed
- runtime injection is actually usable
- required patch/license overlay obligations are satisfied or explicitly classified as non-blocking
- session validation/finalization obligations are satisfied
- public client exposure is safe
- The runtime must not emit or expose a public ready state while required bootstrap obligations remain incomplete.
- CLI/dashboard/server presence must not be confused with session readiness.
- A server may be up earlier, but runtime readiness for session-backed operations must remain separately gated.
- Major phase entry, success, degradation, and terminal failure should be externally observable through events/logs/health signals.
- WAPI injection, patch application, and license-patch application must correspond to actual runtime effects, not only event declarations.
- The runtime should not leave callers guessing whether it is waiting for QR, offline, stale, repaired, or actually ready.
The contract should classify failures by their effect on readiness.
These forbid readiness entirely:
- browser/page bootstrap failure
- unrecoverable auth/session invalidity
- required WAPI/runtime injection failure
- required patch/license overlay failure when those overlays are mandatory for runtime safety
- terminal integrity/finalization failure
These may delay readiness, but should not be silently collapsed:
- recoverable stale session state
- reinjection candidates
- transient page/runtime instability
- retryable patch/license fetch failures where cached or alternate strategy exists
These are allowed only if explicitly classified and surfaced as such:
- optional diagnostics unavailable
- optional non-core overlays skipped with explicit degraded status
The runtime should emit lifecycle events for:
- browser/page init begin/end
- navigation begin/end
- auth check begin/end
- interactive auth / QR or link-code state changes
- WAPI injection begin/end
- patch lifecycle begin/end
- license lifecycle begin/end
- session repair/reinject begin/end when applicable
- finalization/readiness begin/end
- terminal bootstrap failure
Event ordering requirement:
- no “ready” event may precede completion of required bootstrap obligations
Event quality requirement:
- event declarations without runtime emission in the active path are insufficient to count as parity
For audit purposes, the target v5 bootstrap should only be considered behaviorally acceptable if the lower-level runtime can answer all of the following:
- What phase is bootstrap currently in?
- If not ready, what exact blocker class is preventing readiness?
- Has runtime injection actually happened, or has only a placeholder step completed?
- Have patch and license overlay obligations run, and what were their outcomes?
- Was session validity actively established, repaired, or merely assumed?
- Why is the runtime considered ready right now?
This contract does not require:
- recursive restart style identical to legacy
- exact legacy update-check library/mechanism
- exact legacy popup server UX
- exact legacy patch transport endpoints or cache file names
- exact legacy class/file boundaries
It does require preserving the observable operational guarantees those mechanisms supported.
This section changes the next audit standard:
- future runtime work should be judged against this contract first
- implementation details should only matter when they affect the observable guarantees above
- the current active v5 path should now be read as falling short specifically in:
- Phase D runtime injection bootstrap
- Phase E patch/license overlay lifecycle
- Phase F session validation and repair/finalization depth
- Phase G strict readiness gate
This section compares the currently inspected active v5 bootstrap path against the target contract defined in Section 27.
The active path compared here is the code directly evidenced in:
packages/core/src/createClient.tspackages/core/src/transport/Transport.tspackages/core/src/session/index.tspackages/client/src/Client.tspackages/api/src/createApiMiddleware.tspackages/wa-automate/src/cli-runtime.tspackages/wa-automate/src/server/lifecycle-manager.ts
High-level active sequence currently evidenced:
- construct logger/events/session/transport/plugin host
- initialize browser/driver
- navigate to WA Web
- set session state to
AUTHENTICATING - wait for QR
- call
injectWapi() - set session state to
READY - emit
core.startedandclient.ready - CLI binds client/server surfaces and reports readiness
- Pass — active path materially satisfies the target phase contract
- Partial — active path covers some required behavior, but important contract obligations are missing
- Declared-only — events/contracts/schema exist, but active runtime behavior is not sufficiently evidenced
- Absent — no meaningful active-path evidence for the required behavior
| Target phase | Active v5 evidence | Status | Audit reading |
|---|---|---|---|
| A. Config and runtime preconditions | createClient() resolves sessionId, logger, events, session manager, transport, plugin host; CLI resolves config via resolveConfig(...) before starting server/client. |
Partial | Inputs are normalized enough to start, but active lower-level bootstrap does not yet show richer bootstrap-policy normalization equivalent to the legacy launcher contract. |
| B. Browser/page bootstrap | Transport.initialize() launches browser and page; Transport.navigate() goes to WA Web; emits begin/end browser and navigation events. |
Pass | This phase is present and real in the active path. It is comparatively simple, but the minimum contract for browser/page bootstrap is materially satisfied. |
| C. Auth/session state determination | Active path sets state to AUTHENTICATING, then waitForQr() polls QR DOM and may emit QR-generated or auth-timeout events. No active evidence of restored-session-valid / stale-session / phone-unreachable distinctions. |
Partial | There is active auth-related behavior, but it is far thinner than the target contract. The runtime does not yet appear to classify the materially distinct auth/session states required by Section 27. |
| D. Runtime injection bootstrap | createClient().start() calls transport.injectWapi(). Active implementation emits before/after events and returns hardcoded success = true without visible runtime injection logic. |
Absent (effective) | There is a named step, but no evidenced actual runtime effect strong enough to count as satisfying the contract. This phase is effectively absent as a real operational guarantee. |
| E. Patch and license overlay lifecycle | Event vocabulary exists in eventMap, config accepts licenseKey, but no active fetch/apply/inject path was evidenced in active runtime files. |
Declared-only | Contracts and config vocabulary exist, but the active bootstrap path does not currently satisfy the overlay lifecycle contract. |
| F. Session validation and repair/finalization | Session state manager exists but is minimal; no active integrity-check pass, no stale-session repair path, no reinjection flow, no post-bootstrap loaded()-style finalizer in active path. |
Absent | This is one of the largest remaining gaps relative to legacy. The active path does not yet show the deeper finalization and repair semantics the target contract requires. |
| G. Readiness gate and public exposure | createClient().start() sets READY immediately after QR wait + stub-like injectWapi(); client.start() is a direct delegate; CLI then reports ready; API middleware does block invocation while disconnected unless lifecycle is immediate. |
Partial | There is some lifecycle gating at the API layer, which is good. But the lower-level runtime still appears to inflate readiness before the deeper bootstrap obligations from Sections 27.D–27.F are satisfied. |
Current status: not satisfied
Reason:
- active path reaches
READYafter QR wait and stub-like injection, without evidenced patch/license/integrity/finalization completion.
Current status: partially satisfied
Reason:
- CLI/server presence is somewhat separated from method availability because API middleware can block invocation pre-connection.
- however, lower-level runtime readiness itself still looks too shallow.
Current status: partially satisfied
Reason:
- event vocabulary and emitted lifecycle steps exist for browser/navigation/QR/injection.
- but many richer lifecycle obligations are still only declared in the event map, not fully evidenced in active behavior.
Current status: not satisfied
Reason:
- WAPI injection is currently not evidenced as real runtime work.
- patch/license overlay lifecycle is not evidenced as active runtime work.
Current status: not satisfied
Reason:
- active path still appears too ambiguous between “QR surfaced”, “runtime ready”, and “session truly usable”.
| Failure class from target contract | Active v5 handling status | Notes |
|---|---|---|
| browser/page bootstrap failure | Present | Browser/page methods throw and startup would fail if initialize/navigate fail. |
| unrecoverable auth/session invalidity | Weak / partial | Timeouts exist at QR wait level, but deeper invalidity classes are not evidenced. |
| required WAPI/runtime injection failure | Missing | Injection does not appear to have a meaningful failure path because the active implementation is stub-like. |
| required patch/license overlay failure | Missing | No active overlay lifecycle is evidenced. |
| terminal integrity/finalization failure | Missing | No active integrity/finalization stage is evidenced. |
| repairable stale-session / reinject candidates | Missing | Declared in events, not evidenced in active flow. |
| degraded-but-runnable explicit mode | Weak / unclear | Some API lifecycle modes exist, but lower-level bootstrap degradation semantics are not yet explicit. |
- browser init before/after
- navigation before/after
- QR requested/generated/timeout
- WAPI inject before/after
core.startedclient.readysession.state.changed
- patch lifecycle events
- license lifecycle events
- reinjection/session-stale/session-repair events
- richer launch finalization events
- the event surface is ahead of the active behavior it is meant to describe.
The target contract says READY should only mean all of the following are true:
- browser/page boot completed
- auth state resolved enough to proceed
- runtime injection actually usable
- required patch/license overlay obligations satisfied or explicitly non-blocking
- session validation/finalization obligations satisfied
- public client exposure safe
Current active v5 path appears to satisfy:
- 1 browser/page boot completed — yes
- 2 auth resolved enough to proceed — only partially
- 3 runtime injection actually usable — not evidenced
- 4 patch/license obligations satisfied — not evidenced
- 5 session validation/finalization satisfied — not evidenced
- 6 public client exposure safe — only partially supported through API lifecycle gating
Conclusion:
- the current active readiness gate should be treated as premature relative to the target contract.
The current active v5 bootstrap path is best summarized as:
- solid enough at browser/page startup structure
- partially present at auth/QR surfacing
- materially underimplemented at runtime injection
- not yet materially implemented at patch/license overlay
- not yet materially implemented at validation/repair/finalization depth
- too shallow at the point where it declares readiness
This comparison makes the implementation priorities unambiguous.
If the runtime is to satisfy the target contract, the highest-priority work is:
- replace the current thin injection placeholder with a real runtime injection bootstrap
- restore a real patch lifecycle
- restore a real license-patch lifecycle
- rebuild session validation / repair / finalization depth around those steps
- only then reconsider whether
READYis being emitted at the correct moment
The audit is now more precise in three important ways:
-
Listener and documentation plumbing are stronger than the launch path
- eventRegistry + ListenerManager + meta routes are coherent
- docs/deprecation surfaces are deliberate
-
Top-level export composition is still likely lagging behind the intended architecture
wa-automatehas the right role- but not yet the likely desired breadth of re-exports
-
The remaining highest-confidence deficits are increasingly concentrated
- active WAPI injection path
- active auth/session repair richness
- readiness/finalization depth below CLI host
- popup/QR observer replacement clarity
This is a better place to continue from than the earlier broader “v5 is underbuilt” framing.