Skip to content
GRPNR.

Stakeholders & journey — work-ledger adoption inside the two-lead fleet

Scope: internal system-of-record, ~2 human stakeholders + an agent fleet. Commercial funnel stages (awareness, marketing, pricing, purchase-intent) are N/A — internal — no one discovers work-ledger through a channel, no one pays for it, there is no trial. The adoption journey below substitutes the real internal gates: a lane grant, a walking skeleton, and a trust relationship with two humans who read numbers at high-stakes, low-frequency moments.

Confidence key used throughout: fact (grounded in code/docs cited), interpretation (supported reading of grounded facts), hypothesis (plausible, not yet evidenced), unknown (flagged, not fabricated).


1. Stakeholders

Six stakeholders. Two are on the write path (fleet agents), four are read-only or gate-keeping. Only Tomas holds economic decision authority over work-ledger’s existence and placement.

Stakeholder Role Interaction Goal Frustration / friction Failure mode Authority
Robert’s fleet agents Primary users, write path — v1 = non-Temporal external Claude Code sessions, not workflows (architect addendum #1–2, 00-SYNTHESIS.md) claim() / transition() / block() via Authorization: Bearer grpn_<prefix>_<random> (repo recon §6) Get one unambiguous unit, do the work, report truthfully, get unblocked fast when stuck Ambiguous state, a claim someone else already holds, an error that doesn’t name which invariant it broke Silent duplicate work from a non-atomic or non-durable claim (prior-art digest: locks-alone reproduces the highest redundant-work count of any tested condition) None — pure API consumer
Robert Operator; “buyer-equivalent” — his attention is the currency, not dollars Writes the service, ramps concurrency 10→50→64 gated on ledger metrics, watches Grafana (queue depth, stall, cost/merged-unit, rework rate), resolves what triage routes to him Run 10→64 agents without manually reconciling state per agent; trust the dashboards enough to make ramp/kill calls Two-lead coordination overhead (research/12 §1); review throughput below fleet output (AI-authored PRs wait 4.6x longer, 32.7% acceptance, research/12 §1.7) Reverts to manual SELECT-spelunking or tribal knowledge after a trust-breaking incident DRI for the factory lane and everything in it
Tomas Zaruba Economic decision-maker at the lane grant; read-only stakeholder afterward (a) Grants/denies the CODEOWNERS-partitioned internal-plane lane — the actual “purchase” decision, made over the research/14 DM thread; (b) reads the disposition table at kill gates M4/M8/M12 Not be slowed down — “víc agentů mi nepomůže,” his human hours ARE the rulebook (research/12 §1); go/no-go a domain with evidence, not vibes, without personally auditing Robert’s fleet Any factory service that leaks process into his domain; a negotiated PR that stalls his queue; a dashboard he has to learn to operate instead of just read A1 rejected outright, or granted-then-revoked after a boundary violation (an agent writes outside factory/**) DRI for repo placement and anything inside monorepo-development’s core plane
Business + engineering scope panel Zaruba’s doctrine: signs scope, burden of proof on keeping a capability, HOT/WARM/COLD/DARK bucket per legacy capability (01-deep-dive.md [E1]) Indirect only — never calls the API or opens Grafana; consumes disposition evidence (MIGRATED/DROPPED/DEFERRED/DEAD + evidence link) as relayed by Tomas or Robert, likely folded into the same kill-gate artifact Tomas already presents Defensible scope decisions with an audit trail, not an agent’s unverified claim that a capability is dead Evidence links resolving to something they can’t parse (a raw diff, an agent’s scratch notes) — MVP scope is explicitly “links only, no summary” (01-initial-recommendation.md §“What should NOT be in MVP”) Panel treats a disposition as unverifiable and falls back to asking Tomas to re-derive it by hand — the audit trail exists but isn’t legible to the audience it’s for None over work-ledger; full authority over the scope decisions it records
Future second fleet (Tomas’s agents) Hypothesis, not confirmed01-initial-recommendation.md §“Prior to be tested” #3 lists this as an explicitly untested open question; v1 is single-fleet by design If it materializes: Tomas’s agents run as internal-plane Temporal workflows on his substrate, so their claim/attempts/blocking-question would reuse Temporal task queues + tasks natively — structurally different from Robert’s external-claim SKIP LOCKED path (architect addendum #2) (Hypothetical) same accounting guarantees Robert’s fleet gets, without adopting Robert’s non-Temporal claim convention Two claim mechanisms writing into one disposition/cost schema without an explicit reconciliation contract Two silently-diverging claim semantics under one table — a scoped-down replay of pre-mortem #3 (two sources of truth) inside work-ledger itself None today; would inherit Tomas’s DRI status over its own workflow-modelled units
Security stakeholder PII/PCI sign-off, consulted not DRI (research/12 §1 ADR consulted: convention) Gate-keeper on evidence_url content, not a regular reader. Grounded in architect addendum: “recorded legacy traffic = PII/PCI → security-architect sign-off on fixture retention/masking” — a harness-scoped finding that reaches work-ledger because evidence_url is exactly the durable, Grafana-exposed pointer into that fixture store No PII/PCI ever resolvable via a work-ledger evidence link without proper handling The ledger stores no payload itself, but a free-text URL field durably indexes a link into a store that might. Access control on the pointer matters even though the pointee is out of scope An unmasked legacy-traffic capture is discoverable by walking evidence links outward from a Grafana panel — work-ledger becomes an unintended index into sensitive data it never intended to hold (unknown severity — flagged for 10-architecture.md / 13-pre-mortem.md, not resolved here) Sign-off gate on fixture retention/masking; no authority over work-ledger’s schema itself

Agents as personas, stated plainly: the fleet agent is not a lesser stakeholder squeezed into a human-shaped journey template — it is the only stakeholder that touches the write path at all, at concurrency (10→64) no human stakeholder ever approaches. Every design decision in 01-initial-recommendation.md (DB-enforced transitions, atomicity as affordance, full-state-on-every-call, errors that name the violated invariant) is UX work aimed at this persona specifically. The journey stages below (§2) are staged from the agent’s and Robert’s actions; Tomas, the panel, and security only enter at specific gates.


2. Adapted journey — 8 stages

Internal analog to a commercial funnel: recognition replaces awareness, the A1 lane grant replaces purchase, the walking skeleton replaces setup, steady-state operation replaces the product’s actual use, the kill gate replaces renewal, and archival replaces offboarding. No stage has a price.

flowchart TD
  S1[1. Problem recognition] --> S2[2. A1 lane negotiation]
  S2 -- granted --> S3[3. Service scaffold]
  S2 -- rejected --> F1[Failure path A: A-lite fallback]
  F1 --> S3
  S3 --> S4[4. First claimed unit]
  S4 -- crash mid-claim --> F2[Failure path B: stale-claim recovery]
  F2 --> S4
  S4 --> S5[5. First verified unit + cost]
  S5 --> S6[6. Steady-state fleet operation]
  S6 -- drift found --> F3[Failure path C: projection drift]
  F3 --> S6
  S6 --> S7[7. Kill-gate disposition review]
  S7 -- numbers doubted --> F4[Failure path D: Tomas distrusts the numbers]
  F4 --> S7
  S6 -.-> F5[Failure path E: billing gate never clears]
  F5 -.-> S6
  S7 --> S8[8. Program end / archival]

Stages 1–4

Stage Commercial analog Goal Action Owner
1. Problem recognition Awareness Recognize that unclaimed, untracked work at fleet scale destroys trust before it happens, not after an incident Robert names the failure mode from existing evidence: two half-finished stranglers already rotting in-house ([E6]), 64-agent concurrency ceiling ([E9]) Robert
2. A1 lane negotiation Purchase Get work-ledger a legal home in monorepo-development’s internal plane Robert sends the research/14 DM (already drafted): division of labor, three rules (“apps never write to Core, live in own paths, add decisions to the 07 log”), asks for the CODEOWNERS partition Robert → Tomas
3. Service scaffold Setup Deployable local-first walking skeleton, no billing-gate dependency registerInternalService, Drizzle schema/migration, atomic-claim test, 3 endpoints (claim/transition/block) (00-SYNTHESIS.md “First implementation steps” #1–2) Robert
4. First claimed unit Onboarding One agent successfully claims one real unit with zero collision Agent authenticates with a minted grpn_... token, calls claim(), gets full unit state back Fleet agent
Stage Friction Failure state Required capability Metric
1 Failure mode is invisible until it’s already cost tokens — recognized reactively, not proactively, unless named ahead of time Collision/untracked-work risk stays theoretical until a real double-work incident forces it None yet — this stage is diagnosis, not build Qualitative only; the evidence is [E6] + [E9], not a number to be produced
2 A1 is Tomas’s decision alone; no negotiation leverage beyond receipts-not-adjectives credibility (research/14) No OWNERSHIP.md agreement within 2 weeks of the DM landing (00-SYNTHESIS.md pre-mortem #1) A credible, receipts-based ask — already built (research/14) Time-to-OWNERSHIP.md agreement; 2-week trigger for fallback
3 Correction from repo recon: the “vitest+Docker-PG integration test” pattern cited as house convention does not exist anywhere in the codebase — every service test mocks its repository; real DB exercise is a manual pnpm backend:core + MCP-tool pass. This test must be invented, not copied Atomic-claim test either isn’t written (ships an unproven claim) or invents a pattern that drifts from house convention it was supposed to match A genuinely new Docker-PG concurrency test, deliberately labeled as new infrastructure, not a copy of an existing pattern Schema + atomic claim proven under 2 concurrent claimers within ~1 day (01-initial-recommendation.md “fastest prototype”)
4 Auth header collapsed to one scheme same-day (eada68c, 2026-07-18) — any doc or example still showing g-api-key is stale and will break a first-time agent Two agents claim the same unit because the claim wasn’t actually atomic, or a claim never releases because the agent crashed (→ Failure path B) Working grpn_... bearer auth + SKIP LOCKED (or advisory-lock) claim, proven, not assumed Zero collisions in first N claims; time from fleet start to first successful claim()

Stages 5–8

Stage Commercial analog Goal Action Owner
5. First verified unit + cost attribution First value Prove the “accounting system” premise: a real unit closes with a real, attributable cost Agent transitions to verified with parity evidence; cost recorded per attempt via OTEL_RESOURCE_ATTRIBUTES="worktree=…,agent=…" tagging (research/12 §2) Fleet agent → Robert
6. Steady-state fleet operation Actual use Run the fleet at whatever concurrency the evidence supports, unattended Agents claim/transition/block continuously; triage routes blocking questions via the existing INFORMATION_REQUEST + assigneeGroupSlug queue (architect addendum #3, zero new PRs); Robert watches queue depth/stall/rework/cost Fleet + Robert
7. Kill-gate disposition review Renewal Tomas decides go/no-go per domain with evidence, at M4/M8/M12 Tomas reads the disposition table + evidence links; panel consumes the relayed summary Tomas (+panel, indirect)
8. Program end / archival Offboarding Give the program’s disposition history a permanent, post-decommission home Largely undefined — flagged, not designed here. No doc specifies an archival procedure Unassigned — gap for 12-prd.md / 13-pre-mortem.md
Stage Friction Failure state Required capability Metric
5 Without per-worktree/per-agent OTel tags, cost-per-unit silently collapses into cost-per-session (research/12 §2) — the exact failure that would gut the “accounting system, not an app” premise Cost isn’t attributable per unit; the ledger degrades to a status board that happens to also show a session-level dollar figure Cost written per attempt (not just per unit — a crash-and-reclaim must show as two attempts, not one silently-overwritten number) Cost/merged-unit visible as the first custom Grafana panel (00-SYNTHESIS.md TDD step 3)
6 Review capacity, not claim throughput, is the real ceiling — a 5x PR increase just moves the bottleneck to review (research/12 §1.7; independently corroborated by OpenAI’s Symphony, competitive digest) Rework rate climbs with concurrency undetected because ledger metrics aren’t wired into the ramp-gating decision (00-SYNTHESIS.md risk register: “fleet sized beyond evidence”) Queue depth, stall detection (claude_code.active_time.total plateau), rework rate, cost/merged-unit, all feeding the 10→50→64 ramp gate Rework rate held flat (or explained) as concurrency rises per ramp step
7 Kill gates are months apart; Temporal’s own visibility store purges closed-workflow data at 72h retention (temporalCase digest B1) — if any disposition/cost data lived only in Temporal, it would already be gone by M4 Disposition or cost data unavailable at the gate because it was conflated with Temporal’s purged visibility store instead of work-ledger’s durable table A durable table (Postgres, not Temporal) that survives retention by construction, plus confidence tags per number (Zaruba’s MEASURED/MODELED convention) Dispositions readable + evidence-linked at M4/M8/M12 with zero retention-driven gaps; weekly reconciliation-mismatch count = 0
8 No doc in this plan or 00-SYNTHESIS.md specifies what “done” looks like for work-ledger itself — ironic, given it absorbs the decommission ledger as a row type (00-SYNTHESIS.md per-app verdict #8) Work-ledger just stops being read; institutional memory (dispositions, evidence, cost history) becomes orphaned data nobody formally closes out Unknown — plausibly work-ledger applies its own disposition model to itself (a hypothesis worth carrying into 12-prd.md, not a designed feature) Final disposition coverage % of the legacy estate sample (26 repos, [E6]) with a terminal disposition assigned

3. Failure-path journeys

Five paths, each grounded in a specific risk already named elsewhere in this plan or its sources — none invented for this doc except where explicitly marked hypothesis.

A — A1 rejected → A-lite fallback

Trigger: no OWNERSHIP.md agreement within 2 weeks of the research/14 DM landing (00-SYNTHESIS.md pre-mortem #1, assumption A1 fallback in the same doc and in 03-options.md Option A/C comparison).

Path: work-ledger ships as a standalone Robert-owned service outside monorepo-development — “same portfolio, different placement.” If it ever needs cross-plane data, it follows the only write pattern actually observed in the codebase: direct RPC to a Core-exposed internal endpoint via a grpn_... bearer token (repo recon §1, §6) — not the submit/validate/apply/audit “proposal endpoint” flow that root CLAUDE.md describes but that has zero code instances (confirmed independently by Tomas himself in research/14 message 3: “proposal endpointy existuji 0”).

Consequence for the architecture: the external-claim SKIP LOCKED path (already the v1 design for non-Temporal agents) stops being a special case and becomes the only claim mechanism — there is no internal-plane Temporal substrate to ever plug into. This doesn’t add work; it removes an optional future path.

B — Agent crashes mid-claim → stale-claim recovery

Trigger: any of 10→64 concurrent Claude sessions dies mid-unit (process kill, host reboot, context exhaustion) while holding a claim.

Path: the strongest evidence found in prior-art research applies directly here — a June 2026 arXiv preprint (priorArt digest §2, §4) found that advisory-lease-only claim conditions produced the highest redundant-rediscovery count of any tested condition (180 instances): mutual exclusion stops two agents from colliding live, but does nothing to stop the same unit being silently re-claimed and re-done after the original claimant vanishes without a durable record of what happened. A bare lock is not claim-before-work; a lock plus a durable attempt/completion record is.

Recovery design implication (not new build, already implied by the schema): claim carries a TTL/heartbeat; a stale-claim sweep releases expired claims back to the queue; every claim is an appended attempt row, not an overwritten pointer — so a recovered claim shows up as attempt #2, not an invisible do-over. This is the same reasoning that makes the claim table double as the attempts table by design, not by accretion.

C — Projection drift discovered

Trigger: a reconciliation audit (weekly, per 00-SYNTHESIS.md pre-mortem #3 mitigation) finds work-ledger state disagreeing with execution truth.

Path, with a v1-specific correction: the pre-mortem’s original framing is ledger-vs-Temporal drift. Repo recon changes what that means in practice for v1: the workflow-proxy interceptor hook point is a single hardcoded file with zero real fleet-unit traffic today — only one toy workflow on the internal-plane substrate (the stream work-ledger would project from) exists; Core’s merchant-contract-signing runs on Core’s own workers, irrelevant to the projection point (repo recon §3). There is nothing to drift from yet at the Temporal-projection layer, which is precisely why that projection is correctly excluded from v1 MVP scope (01-initial-recommendation.md §“What should NOT be in the MVP”). The v1-real version of this failure path is narrower: work-ledger’s own claimed/transitioned state disagreeing with the agent’s actual progress — an agent reports verified but the dual-run harness’s parity check disagrees, or a stale claim (Failure path B) gets counted as still-active.

Recovery: Temporal-owned fields (once they exist) stay projection-only by construction, enforced by code review, never manually overridden (architect addendum, 00-SYNTHESIS.md risk register); for the v1-real version, the harness’s parity result is the tie-breaker written back as evidence, not a manual state edit.

D — Tomas distrusts the numbers

Trigger (hypothesis, but concretely composed from named risks above): at a kill gate, Tomas hits a number that doesn’t add up — most plausibly a double-counted cost from a crash-and-silent-reclaim (Failure path B unmitigated), or an evidence_url that resolves to nothing durable, or a disposition that appears to have changed with no visible reason.

Failure state: he stops treating the disposition table as evidence of record and reverts to asking Robert to justify each decision by hand — precisely the “worse Linear no one uses” failure the initial recommendation names as the thing to avoid from day one (01-initial-recommendation.md §“The temptation to resist”).

Recovery, by design not by patch: (1) cost written per attempt so a crash-and-reclaim is visible, not hidden (ties to Failure path B); (2) every disposition change is append-only, supersede-never-edit — the exact discipline already trusted in the codebase for ADRs (research/12 §1 item 4) — never an in-place update; (3) confidence tags per number, reusing Zaruba’s own MEASURED/MODELED convention rather than inventing a new one Tomas has to learn.

E — Billing gate never clears → local-first forever

Trigger: GCP billing/quota (human-only gate, 01-deep-dive.md [E5]) never clears; monorepo-infra’s Temporal cluster and cloud Grafana stay unprovisioned indefinitely (00-SYNTHESIS.md assumption A3).

Path: this path is lower-severity for work-ledger specifically than it sounds, and that’s a deliberate design property, not luck: the Postgres SSOT choice means work-ledger’s core value (claim, transition, disposition, cost) never depended on the Temporal cluster or cloud Grafana being live — “deployable local-first, no billing gate dependency” is stated as the walking-skeleton target from day one (00-SYNTHESIS.md TDD step 2, architect addendum: “v1 runs on local encore run”). What does stay blocked indefinitely: cloud-hosted Grafana (dashboards run local-first per the fleet-monitor verdict, research/12 §2) and any real internal-plane Temporal-workflow-modelled unit (Failure path C’s precondition).

Residual open issue (unknown, flag for 10-architecture.md): “local-first” Postgres reachable by 10→64 agent hosts is not the same claim as “runs on Robert’s laptop” — a fleet spread across multiple hosts needs that Postgres instance network-reachable beyond localhost, and no doc in this plan specifies how. Not fabricated here; carried forward as a gap.


4. Cross-persona touchpoint at the trust-critical boundary (stages 6→7)

The single highest-stakes handoff in the whole journey is steady-state operation feeding a kill-gate read Tomas has never had to verify by hand before. Worth diagramming on its own, small:

sequenceDiagram
  participant A as Fleet agent
  participant L as work-ledger
  participant R as Robert
  participant T as Tomas
  participant P as Scope panel
  A->>L: claim / transition / block (continuous)
  L->>R: queue depth, stall, cost/merged-unit, rework rate (Grafana)
  Note over R: ramps 10->50->64 gated on these metrics
  Note over L,T: M4 / M8 / M12 — months apart
  T->>L: read disposition table + evidence links (read-only, SQL/Grafana)
  T->>P: relay disposition evidence, summarized
  alt numbers check out
    T->>R: go / no-go per domain, trusted
  else numbers don't check out
    T->>R: Failure path D — trust breaks, manual justification demanded
  end

5. Open questions handed to later docs

Not re-litigated here — flagged so 12-prd.md and 13-pre-mortem.md inherit them rather than re-discovering them:

  • Stage 8 (program end / archival) has no designed procedure anywhere in this plan — genuine gap, not an oversight of this doc.
  • Security stakeholder’s evidence_url exposure risk (§1) needs an actual access-control answer in 10-architecture.md, not just a flag.
  • Future second fleet (§1) is untested per 01-initial-recommendation.md — if it becomes real, the dual-claim-mechanism reconciliation needs an explicit design, not an assumption that one schema absorbs both silently.
  • Local-first multi-host reachability (Failure path E) has no stated solution — carried forward as an open architecture question.