Project history
The second operator is the test
sprintctlThe CLI and schema that own sprint work, dependencies, reservations, and handoffs. and actionqThe PostgreSQL-backed queue that owns actions, sessions, claims, and outcomes. enforce useful execution discipline, but five current invariants rely on one operator remaining the only source of identity, authority, and audit judgment.
Agent workflow / Published Jul 19, 2026 / Revised Jul 22, 2026
- Project: vuoro
- Vuoro
- The public label for this family of small, separately owned agent-workflow tools.
- sprintctl
- The CLI and schema that own sprint work, dependencies, reservations, and handoffs.
- actionq
- The PostgreSQL-backed queue that owns actions, sessions, claims, and outcomes.
On this page
No second human operator, no coordination system. Only disciplined self-management.
Within the Vuoro project, sprintctl owns work items, claims,
dependencies, and handoffs; actionq owns queued machine actions and their
execution lifecycle. Both can arbitrate concurrent worker sessions. That is not
the same as arbitrating between people. Their current contracts assume one human
authority behind every actor string, claim token, queue worker, and completion
decision. Here N=2 means two independent human authorities, not two agents
operating for the same person. The single-operator assumption is load-bearing in
five places.
The claimant can certify completion
An active exclusive execute claim is sufficient completion authority.
item done-from-claim
checks the claim type, exclusivity, expiry, ID, and token, then moves the work
item to done and normally releases the claim. The
work_item schema
has one status and no submission, review, or acceptance relation. With one
operator, execution proof and the decision that the work is sufficient can be
the same act. At N=2, the implementer can certify their own result and the
system cannot express a reviewer disagreeing without rewriting the item state by
convention.
Names stand in for principals
Actor labels are descriptive text, not authenticated identity. The sprintctl
schema stores work-item assignee, event actor, and claim agent as
text,
while its own operating guide says actor, instance, host, and process metadata
are
advisory only.
Actionq likewise stores created_by, claimed_by, and event actor as
TEXT,
and its CLI accepts the worker and actor labels from the caller. With one
operator, a name is a useful note because the reader already knows who caused
the event. At N=2, either operator can write the other’s name, assignment cannot
grant permission, and the audit log records a claim about identity rather than
identity established by the system.
Expired ownership is disposable
Update, 2026-07-19 — partially fixed. PostgreSQL expiry now marks active claims
expiredand retains their rows. Reacquisition preserves the old row before creating its replacement. The current verification note also states the remaining boundary: SQLite expiry still deletes, and proof-bearing release still deliberately deletes an active claim. The original paragraph below records the behavior at the audited commit; it is no longer the complete PostgreSQL behavior.
Expired sprintctl claims are deleted, not retained as claim history. The SQLite
maintenance path executes
DELETE FROM claim,
and the PostgreSQL path does the
same
for rows past backend time. The documented remote-mode checklist still tells an
operator to schedule that purge. No retained claim-history model exists in these
paths: claim creation and expiry purge do not append matching lifecycle events.
With one operator, deletion is tolerable because the person reconstructing the
incident is the person who held the claim. At N=2, expiry erases who occupied
the work, when their authority lapsed, and which later attempt replaced it; the
remaining item state cannot reconstruct the deleted lease.
Expiry disciplines the holder but does not fence them
Update, 2026-07-19 — schema landed, fencing did not. Sprintctl now stores a
lease_epoch: remote token rotation increments it, and remote reacquisition advances it across retained claim rows. The completion note says there is noexpected_epochcommand input and no downstream enforcement. The old “no epoch” statement is now historical. The invariant in this section remains: expiry still cannot fence a stale holder’s external work, and actionq still does not bind terminal transitions to its current worker.
A claim deadline is a coordination cue, not a fencing epoch. Sprintctl’s
claim ownership protocol
states that expiry cannot reject stale downstream work, and its retained direct
backend admits a stale heartbeat after another owner has claimed the item; the
opt-in remote arbiter repairs that renewal history but still makes no downstream
fencing claim. The claim schema has tokens and expiry but no epoch. Actionq is
looser: its
complete, fail, and reject transitions
check only that the action is currently claimed, not that the caller is the
current claimed_by worker, and its protocol names this limitation explicitly.
With one operator, TTL and sweep are self-discipline. At N=2, a timed-out worker
can continue external writes or win a terminal transition after reassignment, so
the newer claim does not make the older execution harmless.
Repository identity carries project authority
The repository is both storage scope and authority scope. PgStore carries a
repo_id that is
prepended to every query as a tenant discriminator,
and backend resolution derives that ID from the repository directory or marker.
Actionq’s dispatch server requires one concrete repo_id and writes it directly
into the action’s
project
field. There is no separate project, membership, or principal boundary in these
schemas. With one operator, project equals repository because both names point
to the same personal scope. At N=2, a project spanning repositories has split
authority, two projects sharing a repository cannot have separate policy, and
database access to a repository tenant is indistinguishable from permission to
operate all of it.
Five things, not one
The conceptual repair is small even if an implementation would not be: assignment names the accountable party; a claim grants temporary execution rights; an attempt records one session and its artifacts; a submission presents an attempt for judgment; acceptance is the authorized decision that the work item is complete. None implies the next. This is what a multi-operator fix would have to express, not a statement of build intent.
Verification boundary
This inventory was checked against sprintctl commit
11519c4
and actionq commit
85b72bd
on 2026-07-19. Code, current schema, tests, and protocol documents outrank the
project narrative. The claims above are limited to those two revisions. The N=2
consequences and five-part resolution are analysis, not implemented state. The
dated updates were checked against sprintctl commit
80aaa97;
actionq remained at the audited revision.
Coordination infrastructure without a second operator is design theater. The correct output is the analysis.
Optional exploration template
Portable task language, not part of the note.
A post-hoc prompt for applying and extending this note. It is not a reconstruction of how the note was written.
This note is superseded by "Design internal pipelines for succession, not just operation", which absorbs its inventory into a succession model with the operating drill it motivated; read that first. This note remains the project-history record of the audited findings. The transferable question: which of your system's invariants quietly depend on one person being the only source of identity, authority, and audit judgment? The worked case audited two coordination tools against specific commits and found five such invariants, then made a small conceptual repair: assignment names the accountable party, a claim grants temporary execution rights, an attempt records one session and its artifacts, a submission presents that attempt for judgment, and acceptance is the authorized decision that the item is complete -- and none of those implies the next. The note is careful about its own standing: the inventory is verified against named revisions, while the consequences and the five-part resolution are analysis rather than implemented state. Its conclusion is that coordination infrastructure without a second operator is design theatre, and the correct output was the analysis rather than a build. Apply the question to a system you operate alone. Audit it against a specific revision, list what collapses if a second principal appears, and say which of the five your model conflates. Then read the successor for what to do about it.