When You Can't Read the Source: The Decompilability Test
Convergence mining is not a WordPress trick. It is a property of many independent implementations of the same integration — and a route that matches how readable that ecosystem actually is.
The plugin-mining argument landed hard when the corpus was a public directory you could open, compare, and recompile. The honest reader question is the one that remains after that: does the argument survive contact with an ecosystem I cannot just read? Salesforce AppExchange listings, Zapier apps, ERP adapters, browser extensions — most of the connector surface of a real stack is not shaped like WordPress plugins. If the method only works when the source is open, it was a niche trick. If it works because of a deeper property, you need a test for that property and a map of the routes when source is closed.
This piece is a transfer claim. The evidence that convergence mining works was assembled where the corpus is web- and plugin-shaped. The companion piece — AI Doesn't Drive the CMS — It Unbundles It — owns the mechanism in full: why a plugin is a fossilised integration investigation, why you never copy one, the multi-plugin convergence method, the Stripe worked example, the integration-construction hierarchy, evidence-not-authority, and the plugin-to-pattern-bazaar value migration. One short hop there is enough. This article owns only what changes when the connector ecosystem is not web-shaped and not openly readable.
The property was never the platform
The WordPress plugin directory was never the point. The point was many independent implementations of the same integration. When several builders who did not copy each other still converge on the same distinctions — which identifier is authoritative, when a write is final, what must be idempotent — agreement is evidence about the domain, not about one vendor's product taste. One implementation can mislead. A population of independent ones can reveal invariants no single vendor documents cleanly.
That property travels. Any mature connector ecosystem that hosts many solutions for the same join — AppExchange packages, Zapier apps, ERP adapters, browser extensions — carries a latent corpus of solved integration problems. Installable software is the packaging. The AI-era value, when the property holds, is the tuition encoded across the population: what must not be conflated, which failure modes recur, which fields are load-bearing. That is the same value migration that turns a shelf of plugins into a pattern bazaar — complete application code falls in relative value; domain distinctions rise — without requiring the corpus to live on wordpress.org.
Treat the marketplace as a parts-and-priors library. Copy discoveries, not destiny.
Name adjacency only: this is not semantic decompilation — that recovers structured meaning from prose and idea systems. Ecosystem decompilation mines software implementations of integrations for verified invariants. Shared word; different job.
The Decompilability Test
This is what the test gives you: a way to decide, before you commit effort, whether an ecosystem can actually pay you back in evidence. Before you “mine the connectors,” score the candidate ecosystem. The output is a route, not a yes/no verdict.
| Property | What you score | Why it matters |
|---|---|---|
| 1. Population and independence | Are there many implementations of the same integration? Were they built independently, or are they forks of one vendor SDK wearing different skins? | Agreement is evidential only when independence is plausible. A hundred wrappers of one sample client are copying, not convergence. |
| 2. Readability | Open source? Distributed as source? Readable JS in a package? Binary / managed package / partner-gated? | Sets the upper bound on how directly you can compare implementation choices versus schemas and folklore. |
| 3. Verifiable live contract | Sandbox, test mode, replayable events, documented object model you can call? | A mined invariant is a hypothesis until checked against the current provider. Without a contract you can exercise, the loop's last step fails. |
| 4. Observability when closed | If you cannot read source: public schemas, API traffic, community Q&A, integration guides, field-mapping folklore? | Determines whether a closed ecosystem still offers a weaker but usable evidence channel. |
Score honestly. Different ecosystems land on different routes. The test is useful precisely when it forbids a fantasy of full source-level convergence in a partner-gated binary marketplace.
Three ecosystems, three routes
Named ecosystems below are analysed outside-in from public surfaces — market commentary, not claimed engagements.
Route A — Readable source: browser extensions
Chrome / Firefox extension stores → closest non-CMS analogue to open plugins
Population: many independent extensions that touch the same sites and APIs (CRM sidebars, form fillers, calendar joins). Independence is often real: different authors solving the same browser-to-SaaS problem.
Readability: high. Chrome documents extensions as built with HTML, CSS and JavaScript; the package is the logic surface, with a required manifest.json declaring permissions and scripts.1 Firefox WebExtensions follow the same web-technology model.2
Live contract: depends on the upstream SaaS the extension talks to — score that provider separately.
Confidence loss: low relative to WordPress plugins. You still discard UI chrome and store-specific packaging; you still never copy one extension as destiny. You can compare implementations the same way you compare plugins.
Route B — Public schema without source: Zapier apps
Zapier platform → the schema converges even when the code is hidden
Population: a large public catalogue of apps and integrations on Zapier's surface (shape-statement only — no invented counts).3
Readability of implementation: usually low for commercial apps. Partners ship integrations into Zapier's runtime; you do not get their private source as a textbook.
Readability of schema: high. The platform defines integrations as triggers, searches and creates, each with display labels and operation definitions, plus input and output fields that become the mappable surface in the editor.4 Trigger design is documented as polling versus REST Hook, with first-class deduplication behaviour for polling.5
What you mine: not algorithms — schemas. Which fields appear across “Create Contact” or “New Invoice” actions for the same domain? Which identifiers are required? Which statuses show up as enums? Schema agreement across independent apps is weaker evidence than source agreement, but it is still evidence about how the domain is practised at the integration boundary.
Confidence loss: medium. You cannot see retry internals, secret handling, or the reasons a field was added. You can still form hypotheses about entities, required keys and lifecycle labels — then verify them against the provider contract, not against Zapier's packaging.
Route C — Closed documentary and behavioural evidence: AppExchange (and the ERP family)
Salesforce AppExchange → install marketplace, not open corpus
Population: large enterprise marketplace of ready-to-install apps, solutions and consultants that extend Salesforce.6
Readability: low for the consumer. Listings are sold and installed as packages; partner-gated distribution is the product model. Treating AppExchange as a readable plugin directory is a category error.
Evidence that remains: Salesforce object models and API docs; listing descriptions and admin configuration surfaces; community Q&A; observed API traffic from a sandbox install; consultant folklore written down as field maps. For ERP-class adapters (SAP, NetSuite, Microsoft Dynamics), the same pattern intensifies: invariants often live in reconciliation rules and vendor integration guides rather than in multi-vendor open source.
Confidence loss: high. You are reconstructing from documentation and behaviour. Independence is harder to establish — many connectors may share one partner SDK or one Salesforce sample. Always downgrade “convergence” claims unless you can show the specimens were not the same template reflected three times.
Same test, three landings: extensions invite source-level mining; Zapier invites schema-level mining; AppExchange and ERP adapters invite careful documentary and behavioural mining. The method does not vanish. The confidence budget does.
What does not transfer
Failure mode — name it or the claim is marketing
The loop fails when any of three conditions hold. Thin corpus: too few independent implementations of the same join — you are reading anecdotes, not a population. Non-independent corpus: every connector is a thin skin over one vendor SDK or one sample project; agreement is copying, not convergence. No verifiable live contract: no sandbox, test mode, or replayable surface against which to check a mined invariant. In those cases you are back to reading official docs and building carefully. That is not a lesser path. It is the honest path when the evidential step cannot run.
The rule that still holds everywhere — including when you only have Route C scraps — is the same rule that article defends for plugins: the corpus is evidence, never authority. “Three connectors do X” is a hypothesis. “The current provider contract accepts X under these tests” is a decision. Never reason “a popular listing does it this way, therefore it is correct.” Reason “several specimens suggest this distinction; I will verify it against the live contract and encode a test.”
That posture is the open-source consumption move after regeneration got cheap: reuse commodity contracts; generate the mission-shaped join; do not inherit an alien North Star just to avoid writing code. Platform escape is a related selective question — when configuration-heavy CRM and industry suites stop earning their keep — but it is a different essay; the CRM-shaped version lives with the leverage and escape work.
Worked specimen: HubSpot contact / lead sync
Not Stripe. Payments were that article’s laboratory. Here the domain is the everyday non-web join: push a lead or contact into a CRM without creating duplicates, without double-writing on retry, and without treating soft-delete as hard-delete. Specimens for this domain exist across Zapier CRM apps, CRM browser extensions, and marketing-tool connectors. The table below is not a fabricated multi-plugin survey. It is the invariant/local discrimination you would fill by reading specimens and the current HubSpot contract — then encoding tests. Provider facts are from HubSpot's own developer documentation, fetched for this piece.
| Concern | Candidate invariant (domain) | Local choice | HubSpot contract check |
|---|---|---|---|
| Deduplication key | One natural key for “same person” across systems; do not create a second record for the same key. | Email vs phone vs external customer id as the business key; secondary keys for merge. | Email is recommended as the primary unique identifier for contacts; product dedup also discusses domain, record ID and custom unique IDs.78 |
| Upsert vs create | Sync paths that may re-fire must not blindly create; prefer create-or-update on the natural key. | Always-create for pure intake forms that guarantee uniqueness upstream; upsert for bidirectional or retried sync. | Batch upsert endpoint with idProperty of email or custom unique property; exists → update, missing → create.7 |
| External-id ownership | Store the provider's record id separately from the local entity id; never overwrite local identity with provider identity. | Which side is system of record for each field; which system wins on conflict. | HubSpot assigns id / hs_object_id; retrieve and update by Record ID or by email via idProperty=email. Local system should keep its own key and map. |
| Sync direction and conflict | Direction is a business rule, not an API feature. Unidirectional intake differs from bidirectional enrichment. | Last-write-wins vs field-level authority (CRM owns lifecycle; form owns email). | Lifecycle stage can only move forward via API without clearing first — a domain trap if you blindly overwrite stages from a form.7 |
| Soft-delete handling | Provider “delete” is often archive; re-sync must not recreate ghosts without policy. | Propagate deletes, ignore deletes, or tombstone locally. | DELETE moves contacts to the recycling bin (restorable) — soft-delete semantics, not hard erase by default.7 |
| Rate limit / backoff | Respect provider limits; treat 429 as signal, not as “retry harder immediately.” | Batch size, concurrency, queueing strategy. | Public OAuth apps: 110 requests / 10 seconds per installing account (Search excluded); 429 with RATE_LIMIT; headers expose remaining capacity where applicable.9 Batch operations max 100 records per request.7 |
| Idempotency of retried writes | Network retries must not create duplicate contacts or double side-effects. | Client-generated idempotency keys if the provider supports them; otherwise natural-key upsert as the practical stand-in. | Upsert on email/custom unique id is the HubSpot-native way to make retried contact writes converge; do not rely on bare create for retried paths. |
Read the table left to right. The middle column is what you might see recurring across Zapier CRM apps and extensions. The right column is what turns a pattern into a decision for this provider. Rows where local choice remains local (conflict policy, which secondary keys) stay out of the adapter's hard-coded “truth” — they belong in config or in the business North Star.
Minimal adapter sketch
The adapter this table implies is deliberately narrow. It is not a HubSpot plugin. It is the join you own:
Intent: form or intake → one HubSpot contact, no duplicates on retry
Surfaces:
- HubSpot CRM Contacts API (create / upsert / get-by-email)
- Local lead record (your id, email, payload, sync_status)
Adapter (one module):
1. Normalise email; reject empty key
2. Upsert via batch/upsert idProperty=email
(or get-by-email then patch/create)
3. Persist hubspot_id + last_synced_at on local record
4. Map 429 → backoff queue; never tight-loop
5. On local "delete" policy: archive remote or leave —
never assume hard delete
Tests before production:
- same email twice → one HubSpot contact
- retry after timeout → still one contact
- 429 fixture → backoff, no data loss
- lifecycle field: do not regress stage without explicit clear
- delete policy fixture matches product decision
That is “buy the capability, own the join” at adapter size. If a connector marketplace sold you a maintained pattern package — domain model, fixtures, threat notes, current API interpretation — you would still run the same verification step. The package is prior. The contract and the tests are authority. And if the provider is not agent-addressable enough to expose state, actions and consequences cleanly, you will feel it here: verification becomes UI theatre instead of a grant the agent can exercise.
Monday morning: score your stack
- Pick one connector ecosystem you actually depend on (Zapier gallery, AppExchange category, extension store niche, ERP adapter family).
- Run the four properties. Write the route in one sentence: readable source / public schema / documentary-behavioural only.
- Name the independence risk out loud. If everything forks one SDK, stop calling it convergence.
- Pick one provider join (contact sync, invoice push, booking update). List five specimens you can actually open — source, schema pages, or docs.
- Fill an invariant-vs-local table. Verify every candidate invariant against the live contract. Encode three tests. Generate one narrow adapter. Do not install a general connector “just in case.”
If step 2 lands on a thin or non-independent corpus, or step 5 has no sandbox, you already have the answer: read the vendor docs and build carefully. The method did not fail you. The ecosystem failed the decompilability test — and naming that is how you stay honest.
Any mature connector ecosystem is worth more as a corpus of solved integration problems than as installable software — when agreement is independent, readable by some route, and checkable against a live contract. Score first. Mine second. Verify always.
The companion piece showed the method where the evidence lives. This piece only had to answer whether it generalises — and how you tell. It does, as a property test, not as a promise that every marketplace is a free textbook. When you cannot read the source, you do not abandon the method. You pick the route your ecosystem can actually support, pay the confidence cost in the open, and still leave with a domain-invariant table and one narrow adapter instead of another black-box connector in the stack.
References
- Chrome for Developers. “Chrome Extensions Get started.” https://developer.chrome.com/docs/extensions/get-started — Extensions are built with HTML, CSS and JavaScript; required
manifest.jsonin the package root. Fetched 2026-08-05. - MDN Web Docs. “Your first extension.” https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_first_WebExtension — WebExtensions use standard web technologies. Fetched 2026-08-05.
- Zapier. “Apps.” https://zapier.com/apps — Public app/integration catalogue surface (shape-statement only; no invented counts). Fetched 2026-08-05.
- Zapier Platform. “Build with CLI” / platform schema. https://docs.zapier.com/platform/reference/cli-docs — Integrations define triggers, searches and creates with input/output fields as the mappable surface. Fetched 2026-08-05.
- Zapier Platform Docs. “Trigger.” https://docs.zapier.com/platform/build/trigger — Polling and REST Hook triggers; design around user interaction; platform deduplication for polling. Fetched 2026-08-05.
- Salesforce. “AppExchange.” https://appexchange.salesforce.com/appxStore — Enterprise cloud marketplace for ready-to-install apps, solutions and consultants. Fetched 2026-08-05.
- HubSpot Developers. “CRM API | Contacts.” https://developers.hubspot.com/docs/api/crm/contacts — Email as recommended primary unique identifier; batch upsert with
idProperty; soft-delete to recycling bin; batch limit 100; lifecycle stage forward-only. Fetched 2026-08-05. - HubSpot Knowledge Base. “Deduplicate records in HubSpot.” https://knowledge.hubspot.com/records/deduplication-of-records — Email, company domain, record ID and custom unique IDs. Fetched 2026-08-05.
- HubSpot Developers. “API usage guidelines and limits.” https://developers.hubspot.com/docs/api/usage-details — Publicly distributed OAuth apps: 110 requests every 10 seconds per installing account;
429/RATE_LIMIT. Fetched 2026-08-05.
Related LeverageAI pieces (frameworks presented as author voice in the body; listed for transparency): AI Doesn't Drive the CMS — It Unbundles It (219) · Open Source Shortcut Trap · Generative Design Patterns · Agent Addressability · Start Leveraging AI · Semantic Decompilation (name adjacency only).
