WordloopWordloop
Work

How We Work

A streamlined process for outcome-driven delivery, mapping strategic problems straight through to test-driven execution.

How We Work

This section describes how we move from an observed problem to shipped customer value. The process is lean by design, enforcing that technical execution is strictly bound to clear intent and verified by automated tests from the very beginning. It answers the fundamental question: How do you move fast without skipping the discovery that stops you building the wrong thing?

Work flows through four stages, each more concrete than the last:

Rendering architecture map...

Inside each stage

1. Problem Statement

Most wasted work is caused by excellent execution of the wrong thing. Skipping from idea to solution — without pausing to understand the problem — leads to building with false confidence.

A Problem Statement captures observed pain — real, evidenced, specific — alongside an appetite: a judgment about how much time this problem is worth solving.

  • Appetite is not an estimate of how long a solution will take. It is an opportunity cost judgment made before the solution is defined. You are betting that the problem is worth that much time.
  • Problem statements do not accumulate indefinitely. They are a curated list, updated as understanding evolves and retired when no longer relevant.
  • Platform and infrastructure problems are valid problem statements. The "who experiences it" can be internal — the engineering team, the system's reliability, the business's compliance posture. Feature bets routinely surface infrastructure gaps (e.g., a missing event backplane, no deletion cascade). The right response is to extract the gap as its own problem statement — not to expand the feature bet. The feature bet declares the constraint explicitly; the platform bet solves it.

2. Pitch

Unformed ideas become backlogs. Backlogs create the illusion that everything is captured and considered, when really they are lists of things nobody explicitly said no to.

Before a problem reaches the build phase, it is shaped into a Pitch. A pitch links a validated problem to a rough solution proposal. It is concrete enough to execute against but stays away from micro-detail.

A pitch must contain:

  • The problem — what was observed, who experiences it, why it matters now.
  • The appetite — how much time to spend.
  • A rough solution sketch — the general approach to the solution.
  • Rabbit holes — approaches already considered and ruled out. Include plausible-looking approaches that would blow the appetite or the scope, and infrastructure assumptions the bet makes (e.g., "we assume sticky sessions, not a backplane").
  • Explicit no-gos — what is completely out of scope. Include both obvious exclusions and natural extensions that users would reasonably expect but that don't belong in this version (e.g., pause/resume, mobile support, export/download). Vague no-gos invite scope creep — be specific about what's excluded and why.

A funded pitch becomes a Bet — a commitment bounded by the appetite.

3. TDD: Foundations

Technical Design bridges the intent of the pitch to parallel execution. We start by laying the technical foundation so that progress isn't blocked later by misaligned interfaces.

UI Design

The UI Design doc translates the pitch's rough solution sketch into concrete, screen-level detail. It answers: what exactly will the user see and do?

Organise it by screen — not by feature, not by user story. Each screen the bet touches gets its own section with:

  • A wireframe — even a rough sketch. This is the anchor; the text describes it.
  • Layout — the regions on screen and what content lives in each one.
  • States — what the user sees during loading, active use, empty states, errors, and degraded conditions.
  • Key interactions — what the user can do and what happens in response.

After the screens, map the user journeys between them (how the user moves from entry point to final outcome), and list edge cases (anything unusual the system needs to handle visibly).

Be specific about data objects. If a screen shows tasks, define what a task is: which fields it has, which are required, whether they nest, what states they can be in. If a screen has a text editor, say whether it's rich text or plain, whether it auto-saves or has a save button. These details directly determine the API contracts and database schema that come next.

Stay at the user level. If you're specifying which service owns the logic, how the frontend integrates, or where data persists — you've gone too far. The UI Design doc describes what the user experiences, not how the system delivers it. System concerns belong in the Data Flow doc.

The output feeds directly into: Data Flow diagrams (which service calls which), API contracts (what fields and endpoints exist), and database schemas (what gets stored). If someone can't design those artefacts from the UI Design doc alone, the doc isn't detailed enough.

Data Flows

The Data Flow doc maps every user interaction from the UI Design through service boundaries. It answers: what calls what, what data crosses each boundary, and what happens when something fails. It is the primary input for API contracts and database schemas — if someone can't design those artefacts from this doc alone, the doc isn't complete.

Start with a system context graph. Before drawing any sequences, draw the topology: which services exist, which protocols connect them, which data stores each service owns. This is a static map — it orients readers and makes the scope of the bet explicit.

Name flows after what triggers them. Group related flows into logical Parts (e.g., "Session Lifecycle", "Streaming Processing", "Failure Modes"). A flow name describes what the user does or what system condition fires — not the implementation.

Use descriptive operation labels — never endpoint paths. Diagram labels should read like Create task (idempotent, echo-suppressed) not POST /meetings/{id}/tasks. Header names, field names, and HTTP methods all belong in the Contracts doc. Each arrow in a flow is a contract boundary (what shape the data takes) and a sequencing constraint (downstream cannot build until upstream is agreed). Naming the operation is enough — the Contracts doc defines the shape precisely.

Failure modes are required, not optional. For every significant service boundary in the bet, there must be at least one flow describing what happens when that boundary fails. If the UI Design doc models a "Degraded" or "Connectivity Lost" state, the Data Flow doc must show the recovery sequence. Resilience is a first-class design concern — not an afterthought.

Close with two required sections:

  • Design Decisions — tradeoffs made, alternatives ruled out, constraints that drove choices. Captures reasoning that isn't visible in the diagrams.
  • Boundary Inventory — a table of every service-to-service boundary in the doc. Five columns: Boundary | Flows | From → To | Protocol | Data shape. Each row here becomes a contract entry in the Contracts doc.

Contracts & Schemas

The agreed API contracts (REST, WebSocket, Pub/Sub) and database schemas (PostgreSQL, object storage). Downstream UI can mock against the contract; upstream Core can build against it.

4. TDD: Execution

Once the technical foundation is set, the bet is decomposed into deliverable units.

  • Integration Milestones: Points of user-visible value. This is the integration of multiple pieces that results in a cohesive feature or state change for the user.
  • Domain Slices: The smallest independently buildable and testable units of work. We never slice horizontally (e.g. building all databases, then all APIs, then all UI). We always slice vertically. A vertical slice could be a full feature connecting App -> Core -> ML, or a complete vertical slice completely within a single domain (e.g., being able to do CRUD on a Meeting in Core via the API). Slices must be independently deployable and verifiable.

Tests as Proof of Delivery

Every milestone and slice has its test overview properly documented, and corresponding empty test stubs are generated in the test runner before any production code is written.

These tests serve as the single source of truth for progress signaling. Red means work to do; green means proven.

  1. Service/system tests (permanent) — implemented in the service repo or tests/system/ during the build.
  2. Bet progress suite (temporary) — mirrored in tests/bets/<slug>/, run on demand via ./dev test bet <slug>.

Bet Operations

By utilizing the Golden Path CLI tools, documentation is kept exactly in sync with the integration testing layout.

Start a new bet

./dev new bet <slug>

Promotes a pitch into an active bet at work/<slug>/ and creates the baseline test boundary suite in tests/bets/<slug>/. The slug must be lowercase kebab-case (e.g. speaker-navigation). A pitch must exist first — run ./dev new pitch <slug>.

Scaffolding Architecture (TDD)

# Scaffolds architectural boundaries
./dev new contract <bet-slug> <service> <protocol>
./dev new schema <bet-slug> <service> <database-tech>

# Scaffolds milestones and domains
./dev new milestone <bet-slug> <milestone-slug>
./dev new slice <bet-slug> <milestone-slug> <domain> <slice-slug>

Generating a slice or a milestone will drop corresponding placeholder testing boundaries in tests/bets/.

Run bet progress tests

./dev test bet <slug>

Runs the bet progress suite on demand. Watch the test output to verify that your delivery is progressing as intended.

Archive a delivered bet

./dev archive bet <slug>

Moves the bet directory to _archive/ and the associated test suite to tests/bets/_archive/<slug>/. URL routing is preserved.

On this page