Darkwood · PHP · agents · Flow

The Thanks
Agent

When orchestration guarantees
execution, not value

Execution
≠
Value
@matyo91

The question

What happens when an
orchestration system executes
work that has no value?

Not rhetorical. An engineering experiment.

01 | question @matyo91

The experiment · content/thanks-agent

Five useful. One useless.
Same runtime.

FetchDocs

Value +25

Github

Value +40

PHP

Value +30

Mozilla

Value +20

Cost

Value +15

Thanks

Value +0

+ SummaryAgent (+15) after fan-in

02 | experiment @matyo91

ThanksAgent

Always says “Thanks.”

return [
  'output'   => 'Thanks.', // or Looks good. / Good job.
  'tokens'   => 2,
  'messages' => 28,
  'didWork'  => false,     // value forced to 0
];
No tools · no context · no work
Still scheduled · metered · logged
03 | thanks-agent @matyo91

Thesis

Activity is not throughput

execution ≠ value
messages ≠ work
visibility ≠ outcome

The scheduler cannot distinguish
productive work from performative work.

04 | thesis @matyo91

Cost is plural

What an agent consumes

Scheduler

WIP / MaxIpStrategy

Tokens

Simulated in demo

Messages

Chatty acknowledgements

Context

Prompt / index slices

Logs

Observability volume

Attention

Decision queue

05 | consumption @matyo91

Flow today · PHP ≥ 8.5

Linear async pipeline.
Not a DAG engine.

flowchart LR
  IP[Ip] --> Job[Job]
  Job --> Driver[Driver]
  Driver --> Events[PUSH PULL POP ASYNC]
  Events --> Job
FlowFactory · MaxIpStrategy
FiberDriver · StreamSelectDriver

Many IPs in flight ≠ graph joins.

06 | flow @matyo91

Scatter / gather · demo pattern

Multiple IPs. Shared bag. Sync join.

flowchart LR
  Ips[Multiple Ips] --> Stage[ExecuteAgentJob]
  Stage --> Store[RunStore]
  Store --> Summary[SummaryAgent]
  Summary --> Report[Scoreboard]

MaxIpStrategy caps concurrency · fan-in is application state

07 | scatter-gather @matyo91

Scoreboard · FiberDriver · PHP 8.5.4

Value Δ = 0

Without Thanks

Value 145
Cost 0.012
Messages 19
Events 5/5/5/5

With Thanks

Value 145
Cost 0.022 · +0.010
Messages 48 · +29
Events 6/6/6/6

Useful output unchanged. Resources up.

08 | scoreboard @matyo91

Economics

Cost without value

Cost / request

Looks tiny on the invoice line

Cost / useful result

Thanks → tends to ∞

Cheap useless work is not cheap.
It is subsidized noise.

09 | cost @matyo91

Bottleneck moves

Supervision is scarce too

Model concurrency

Calls you can fire

Runtime concurrency

IPs in flight

Human supervision

Open contexts

Validation capacity

Reject / accept bandwidth

Stop counting running tasks.
Count decisions waiting. · SupervisionBudget

10 | supervision @matyo91

thanks-agent:bench-io · synthetic I/O · PHP 8.5.4

Async is waiting efficiently

sequential

~600 ms · value 130

stream_select

~167 ms · value 130

Flow StreamSelect

~179 ms · value 130

PHP 8.6 Poll

skipped on 8.5.4

~3.6× wall improvement. Same emptiness from Thanks.

11 | async @matyo91

Editorial callback

Polling is not
value either

A better poller can execute
useless work faster.

Performance amplifies whatever
the system is optimizing.

12 | amplify @matyo91

Terminal lifecycle

The unhappy path must be billed

flowchart TB
  Exec[Execute] --> Success[Success]
  Exec --> Failure[Failure]
  Exec --> Abandon[Abandon]
  Success --> Complete[CompleteEvent]
  Failure --> Error[ErrorEvent]
  Abandon --> Hole[Accounting hole]
  Complete --> Ledger[CostLedger]
  Error --> Ledger

Happy-path-only FinOps lies.

13 | terminals @matyo91

What changed in Flow

Shipped · next

Promoted

CostLedger · ValueTag
Complete / Error
SupervisionBudget
PollerInterface · Duration

Roadmap

Cancel · abandon terminal
True DAG joins
Decision-queue metrics
CodeMap · AgentRouter

Value and cost belong in the runtime vocabulary.

14 | flow-delta @matyo91

Closing

We already know how
to make agents run.

The harder problem is deciding
which work should exist at all.

The next optimization is not another agent.
It is a better definition of value.

Activity
→
value
@matyo91