Waleed Barghouthi

I build systems that let a model propose and a machine decide.

I’m Waleed Barghouthi. I build Mo’eenAn Instagram-first order and conversation workspace for Palestinian and MENA small businesses. It turns Arabic, English and mixed customer messages into validated order drafts, with the merchant in control of every one.

The model proposes. My code decides.

The proof is directly below, and you can read the trace yourself.

Order validation sandbox

Watch it catch a confident mistake.

A customer sends a message in Arabic, English, or both at once. The model reads it and suggests an order. Nothing it suggests reaches the merchant until deterministic code has checked every field against the catalogue and the rules.

Inbound message
1 · Pre-filter
pass

Looks like an order. Sent to the parser.

  • Contains a quantity token
  • Matches at least one catalogue term
  • Not a greeting-only message
  • Not a duplicate of a message seen in the last 60s
2 · Parse — the model's proposal
Model confidence0.91Edit anything below — the gate re-runs as you type.

Delivery requested for tomorrow.

3 · Validate — deterministic, running in your browser
needs a human

Draft created with 1 open question. Nothing is confirmed until answered.

total 122.00
  • pass

    lines[0].sku

    SKU exists in the catalogue. KNF-004 — Knafeh tray, large.

  • pass

    lines[0].quantity

    Quantity within the catalogue maximum. 2 of a possible 10.

  • pass

    lines[0].unitPrice

    Price matches the catalogue. 45 matches.

  • pass

    lines[1].sku

    SKU exists in the catalogue. BKL-011 — Baklava box, 500g.

  • pass

    lines[1].quantity

    Quantity within the catalogue maximum. 1 of a possible 15.

  • pass

    lines[1].unitPrice

    Price matches the catalogue. 32 matches.

  • needs a human

    customerName

    Required before the order can be confirmed. Not in the message. The merchant is asked, never guessed at.

  • pass

    address

    Resolves to a served delivery area. Al-Bireh is in the merchant’s delivery zone.

The parse above is pre-computed — there is no model call on this page. The validation below it is not: that is validateOrder() running here, the same pure function its unit tests cover. It has no access to the confidence score, which is why editing the price to whatever the customer claimed still gets refused.

Note

The parse step is the only part a model touches. Everything after it is ordinary code with ordinary tests: catalogue lookup, quantity bounds, price reconciliation, address completeness. A confident wrong parse is still caught, because the validator does not care how confident the parse was.

Query console

I write SQL against real data.

Not “familiar with SQL”. Here is a schema shaped like the one Mo’een runs on, and here are queries I actually write against it.

SyntheticSynthetic data, shaped like the real schema. Pilot merchants’ orders are theirs, not mine to publish.

Schema

merchants

One row per tenant. Everything else hangs off this.

  • iduuidprimary key
  • handletextInstagram handle
  • citytext
  • joined_attimestamptz

messages

Every inbound message, whether or not it became an order.

  • iduuid
  • merchant_iduuidtenant key — never optional
  • bodytext
  • scripttext'ar' | 'en' | 'mixed'
  • received_attimestamptz

orders

A draft becomes an order only once the merchant confirms it.

  • iduuid
  • merchant_iduuidtenant key
  • message_iduuidwhat it was parsed from
  • statustext'draft' | 'confirmed' | 'rejected'
  • parse_confidencenumeric
  • needed_editbooleandid the merchant change it
  • created_attimestamptz

order_lines

One row per line item.

  • order_iduuid
  • skutext
  • quantityinteger
  • unit_pricenumeric
Query
-- Was the parse good enough to leave alone?
-- Bucketed by the model's own confidence, so we can see whether that
-- number means anything. The tenant predicate is not optional.
select
  width_bucket(parse_confidence, 0.5, 1.0, 5) as confidence_bucket,
  count(*)                                    as orders,
  round(100.0 * avg(case when needed_edit
                    then 0 else 1 end), 1)    as pct_untouched,
  round(100.0 * avg(case when status = 'confirmed'
                    then 1 else 0 end), 1)    as pct_confirmed
from orders
where merchant_id = current_tenant()
  and created_at >= now() - interval '90 days'
group by 1
order by 1;
Result
Order outcomes bucketed by the parser’s reported confidence
confidence_bucketorderspct_untouchedpct_confirmed
0.50–0.604122.051.2
0.60–0.708835.268.2
0.70–0.8016451.879.9
0.80–0.9029768.488.6
0.90–1.0041274.591.3

Confidence correlates with being left alone, but it flattens badly at the top: a quarter of the model’s most confident parses still needed a human edit. That flattening is the entire argument for the validation gate.

Note

The schema mirrors production: orders, order lines, merchants, and the message each order was parsed from. Multi-tenant, so every query has to be ownership-aware — the tenant predicate is not optional and is enforced in the database as well as the API.

Queue worker

I ship production systems, not demos.

Mo’een’s worker processes every inbound message through a queue with leases, retries, dead-lettering and heartbeats. The interesting part is not the happy path. It is what happens when a worker dies holding a lease.

Architecture
Mo’een queue worker, showing lease, retry and dead-letter pathsAn inbound message becomes a row in a jobs queue. A worker claims it by taking a lease with an expiry, and holds that lease open with periodic heartbeats. On success an order draft is written and the merchant sees it. If the worker dies, it stops sending heartbeats, the lease expires, and the job returns to the queue for another worker to claim. Failures are retried with backoff, bounded; a job that exhausts its retries is written to a dead-letter table together with its error rather than being dropped.heartbeat — extends the leaseinboundmessagejobsqueue tableworkerholds a leaseorder draftmerchant sees itclaimokworker dieslease not renewedno heartbeatlease expiredretrybounded, backed offrequeueddead letterkept, with errorexhausted
Inject a failure
tick 0job queuedlease noneattempt 0
Trace
  1. 00jobsMessage arrives. Row written to the jobs table.
Stack
  • Next.js 16
  • React 19
  • TypeScript
  • Tailwind v4
  • Supabase
  • Postgres
  • Provider-neutral AI adapter, so no model vendor is load-bearing
  • Queue-backed worker with leases, retries and dead-letter handling
  • Multi-tenant, with ownership enforced at both the database and the API layer

Note

A lease is a claim with an expiry, so a worker that dies mid-job cannot block the queue forever — the lease lapses and the job is reclaimed. Retries are bounded and back off; anything that exhausts them goes to the dead-letter table with its error, where it can be inspected instead of silently disappearing.

Similarity explorer

I understand retrieval, not the buzzword.

Documents get chunked, embedded, and searched by cosine similarity. I wrote the cosine by hand rather than pulling a library, because the interesting decisions are in the chunking and the cutoff, not the dot product.

Query

What happens if the supplier misses the delivery date?

Controls
4 retrieved of 6 consideredAll of them actually bear on the question.
Ranked by cosine
  • c-114MSA §7.2 — Delivery0.891

    Where the Supplier fails to deliver the Services by the Delivery Date, the Customer may claim liquidated damages of 0.5% of the Charges per week of delay, up to a maximum of 5%.

  • c-118MSA §7.4 — Delay notification0.847

    The Supplier shall notify the Customer in writing within two Business Days of becoming aware that a Delivery Date is at risk, stating the revised date and the cause.

  • c-131MSA §9.1 — Termination for cause0.782

    Either party may terminate this Agreement immediately where the other commits a material breach which is not remedied within thirty days of written notice.

  • c-092MSA §5.3 — Acceptance testing0.751

    The Customer shall have ten Business Days from delivery to conduct Acceptance Tests and notify the Supplier of any failure to meet the Acceptance Criteria.

  • c-076MSA §4.1 — Charges0.719

    The Charges are payable within thirty days of the date of a valid invoice. Late payment attracts interest at 2% above base rate.

    Scores respectably. Answers nothing.

  • c-155MSA §12.6 — Notices0.706

    Any notice under this Agreement shall be in writing and delivered by hand or sent by pre-paid first class post to the address set out in the Particulars.

    Scores respectably. Answers nothing.

The two chunks below the line score in the low 0.7s and are worthless for this question — they are contract boilerplate that reads like every other clause. That is what similarity measures: whether two passages talk alike, not whether one answers the other. Set the cutoff too low and you retrieve fluent noise, which is worse than retrieving nothing, because it is what the model will confidently cite.

cosine.ts
// No library. It is eight lines, and the interesting
// decisions are elsewhere.
function cosine(a: Float32Array, b: Float32Array): number {
  let dot = 0, na = 0, nb = 0
  for (let i = 0; i < a.length; i++) {
    dot += a[i] * b[i]
    na  += a[i] * a[i]
    nb  += b[i] * b[i]
  }
  return dot / (Math.sqrt(na) * Math.sqrt(nb))
}

Note

Similarity is not relevance. A high cosine score means two chunks talk alike, which is why the cutoff matters more than the ranking: past a certain score, you are retrieving noise that reads plausibly, and that is worse than retrieving nothing.

Cohort retention

I turn data into decisions.

Retention by weekly cohort. The question is never “what is our retention” — it is which cohort, measured from when, and what you plan to do differently depending on the answer.

SyntheticSynthetic cohorts, modelled on pilot-shaped retention. The pilot’s real numbers are not mine to publish.

Definition — change it and watch the number move
Retained means
Week-4 retention, averaged23.8%over 7 cohorts
Retention by cohort
Retention by signup-week cohortW01, 14 merchants: week 0 100%, week 1 50%, week 2 29%, week 3 36%, week 4 14%, week 5 29%, week 6 21%. W02, 18 merchants: week 0 100%, week 1 56%, week 2 39%, week 3 28%, week 4 22%, week 5 33%, week 6 22%. W03, 22 merchants: week 0 100%, week 1 59%, week 2 45%, week 3 32%, week 4 27%, week 5 36%. W04, 19 merchants: week 0 100%, week 1 63%, week 2 42%, week 3 47%, week 4 32%. W05, 26 merchants: week 0 100%, week 1 69%, week 2 50%, week 3 46%. W06, 24 merchants: week 0 100%, week 1 71%, week 2 58%. W07, 31 merchants: week 0 100%, week 1 74%02550751000123456weeks since signupW01 · n=14W02 · n=18W03 · n=22W04 · n=19W05 · n=26W06 · n=24W07 · n=31
Fixed by the pipeline
Cohorted by
Week the merchant connected their Instagram account
Excludes
Merchants who never completed onboarding

Switching the definition moves week-4 retention by about nine points without a single number in the underlying data changing. That is the point: “retention” is not a measurement until you say what it counts. Note the cohort sizes too — at n=14 one merchant is seven points, so a week-to-week swing here is one person going quiet, not a trend. Later cohorts holding better than earlier ones is the only part of this chart that is evidence the product changed rather than the customers.

Note

Cohorting by signup week rather than by calendar week is what makes the curve mean anything: it separates “our product got better” from “we acquired different people”. The window definition changes the number more than most product changes do.

Timeline

Track record.

Work, study and cities, on one axis. The overlap is the information — the master’s and full-time work ran at the same time, in a different country from where I started.

Timeline
Work, study and cities over timeBSc Computer Science at ELTE, Budapest, 2018-09 to 2021-06. MSc Business Informatics at Corvinus University, Budapest, 2021-09 to 2023-06. Data Engineering Intern at ASAL Technologies, Ramallah, 2022-06 to 2022-09. Product Management Specialist, Consumer at Jawwal, Ramallah, 2024-01 to present. Founder at Mo’een, Ramallah, 2025-01 to present.20192020202120222023202420252026BSc Computer ScienceELTE · BudapestMSc Business InformaticsCorvinus University · BudapestData Engineering InternASAL Technologies · RamallahProduct Management Specialist, ConsumerJawwal · RamallahFounderMo’een · Ramallah
  • 2024-01now

    Product Management Specialist, Consumer · Jawwal, Ramallah

    Fintech products, fixed and mobile features, campaign delivery.

  • 2025-01now

    Founder · Mo’een, Ramallah

    In pilot with 8 merchants.

  • 2021-092023-06

    MSc Business Informatics · Corvinus University, Budapest

    Stipendium Hungaricum scholarship.

  • 2018-092021-06

    BSc Computer Science · ELTE, Budapest

  • 2022-062022-09

    Data Engineering Intern · ASAL Technologies, Ramallah

    ETL pipelines, AWS, analytics integration.

Tools

  • SQL / PostgreSQL
  • Python
  • TypeScript
  • Databricks
  • Power BI
  • SAP
  • Supabase
  • Vercel

Note

Two of these overlap by two years. That was the point: the degree was in business informatics while the work was in data engineering, and each was the reason the other made sense.

Scoped work

Here is what I would build for you.

Scoped, with a deliverable and a timeline rather than a day rate and a vague promise.

  • Document to structured data

    A pipeline that turns your PDFs, invoices or messages into validated rows, with a review step for anything it is unsure about.

    Includes the validation layer, not just the extraction. The failure mode you care about is a confident wrong answer, and that is what the gate is for.

    Typically3–4 weeks
  • Churn and cohort analysis

    Cohorted retention over your actual data, with the queries handed over so you can re-run them without me.

    You get the SQL and the definitions, not a dashboard you cannot change. The definitions are the deliverable.

    Typically2 weeks
  • Arabic and MENA-language AI systems

    Extraction or classification that works on mixed Arabic/English text, evaluated on your data rather than on a benchmark.

    Mixed-script, dialectal and code-switched text breaks most off-the-shelf pipelines. I have shipped this and I know where it breaks.

    Typically4–6 weeks

Describe the problem — I’ll tell you if I’m the wrong person for it.

Note

Each of these is something I have already built once. The timeline is what it took, not what I hope it would take.