@open-matrix/system-tickets (1.1.32)
Installation
@open-matrix:registry=npm install @open-matrix/system-tickets@1.1.32"@open-matrix/system-tickets": "1.1.32"About this package
system.tickets
@open-matrix/system-tickets stores builder tickets in PostgreSQL. tickets.file, tickets.list,
tickets.get, and tickets.summary resolve the caller from a verified bus token and stay within that
home. Only platform.operator may list across homes or read tickets.smells; units may use the
worker transition path described below.
The service stamps principal, display name, home, role, current capability grants, environment, release, and filing time. Ticket text and approved excerpts pass through the shared credential-span redactor before storage. A signature over operation, code, target, and feature merges repeated reports in one home.
The verified operator role is the only filing authority that may choose a board list or position.
Every other caller is appended to Standing order; sender-written perspective and board-control fields
are ignored and reported in ignoredFields. The board attributes the request to the verified
principal's display name without trying to infer whether its client was a person, agent, or application.
Its browser module supplies editable proposal cards (including the
approved excerpt, priority, and drop control) and an open-ticket board. component.describe returns
the built module's content digest and build provenance, and component.module.get serves those exact
bytes.
Board-mutating filings and transitions enter a runtime-local FIFO for their authority root before
acquiring a transaction connection. Another home has its own FIFO, and ordinary reads do not enter
one, so same-home contention cannot occupy the shared pool while waiting. PostgreSQL's transaction
advisory lock remains the cross-process authority. The native contention case in
tickets.spec.ts proves the 200-concurrent and 10,000-sequential
board workload plus independent-session locking and unrelated-home headroom. The existing
Demos S30 Fleet program consumes
this owner behavior; this internal pool repair does not introduce another program or workflow owner.
Filing and transition append an outbox row in the same transaction as the ticket mutation. Each request
delivers at most one bounded outbox page to system.audit, using the event id as its idempotency key;
later requests continue durable unsent rows without duplicating the management event.
Transitions to deployed, verified, or closed require a classified fix. Exact retries do not
duplicate it. tickets.smells {since} counts fixes by class and groups non-empty smell names by
frequency, owner, and ticket so builders can promote repeating patch causes into design work.
Every ticket carries a revision that advances with each change to the case (a board move does not
advance it); tickets.transition {expectedRevision} is refused with TICKET_REVISION_CONFLICT once the
ticket has moved on. An operator filing may name programs (stable identities such as program:fleet;
tickets.list {program} selects them). Membership never starts work. An operator binds an admitted
workflow with workflow {recipe, revision, basis, reason}; Tickets stamps who and when, and refuses a
rebinding while its execution is active. A worker unit may bind only with basis: 'policy', the
dispatcher applying the registered routing policy; an explicit choice is an operator's.
execution {claim: true, route, claimant} with expectedRevision admits the ticket's one execution
generation: one claimant wins, the same claimant repeating its claim observes the same execution, and any
other claim is refused with TICKET_EXECUTION_ACTIVE. Reports name that generation and carry separate
references: task, attempt, agent mount, Matrix and native session, worktree, base, candidate and checks,
then combined head, served head and target. Only the unit that claimed the execution (or an operator)
reports its own references (TICKET_EXECUTION_NOT_CLAIMANT). Integration evidence (combined head, served
head, target) and the close it carries come from an operator, or from a unit holding an active
tickets.integrate grant (TICKET_INTEGRATION_CAPABILITY) whose resource subject is
ticketIntegrationSubject(home, target). The grant is read from capability.list; claiming or
orchestrating the execution never implies it. The stored source principal (claimedBy) cannot supply
integration evidence or finish its execution, even with an integration grant or operator authority.
Evidence names the current candidate; a newer candidate drops
the older one's checks and integration evidence, and evidence about the replaced candidate is refused with
TICKET_CANDIDATE_STALE. Any other unit, the claimant included, cannot move a ticket with an active execution
to deployed, verified or closed (TICKET_SELF_CLOSE_REFUSED). A granted unit closes with the current
candidate, its checks, the combined head, the target, and a served head equal to the combined head; an
operator closes with the current candidate and its combined head. Integration evidence stands in for the fix
record, and the close finishes the execution. Package dispatch (@open-matrix/codex-agent) passes over any ticket
with a bound workflow or a claimed execution.
The verified owner of a ticket's home can read its exact execution session references
through tickets.get, the paged board and integration observation. This makes the
existing Work/Watch view and canonical Demos S30 useful without platform-operator
privileges. Ordinary members still receive results without session IDs; another
home's ownership confers no visibility. These are references, not session access or
control grants: the selected agent remains responsible for admitting those actions.
Board placement remains operator/unit-only. The real actor/store regression in
src/__tests__/ticket-execution.spec.ts covers owner/member/foreign-home reads,
caller-written visibility flags and unchanged transition refusal; S30's installed
walk checks that the retained Matrix and native session IDs actually appear.
tickets.integration.admit {id, generation, candidate, mode, busToken} is a read-only submission
boundary, published under tickets.desk. It verifies the existing bus caller and reads only that home.
An enrolled unit must match the stored execution's claimedBy; a verified person owning that home or
a same-home platform operator may hand off on its behalf. Admission requires the exact stored generation
and candidate and nonempty stored checks. mode: 'submit' requires an active execution;
mode: 'observe' also accepts the same finished tuple so a lost close reply can be read.
The reply contains ok, verified principalId, authorityRoot, and the visible execution snapshot,
never the token. Unknown fields (including caller-written claimedBy or checks), malformed tuples,
wrong callers/homes and stale candidates refuse. Admission changes no state, grants or credentials;
it does not authorize integration or source self-approval.
The home facade supplies authorityRoot and matching namespaceRoot routing fields;
Tickets accepts that envelope but Auth must still authorize the requested home from
the caller's proof. It does not accept caller-written execution evidence. Canonical
Demos S30 exercises this handoff; S27 reads its retained integration result.
Ticket and comment fields use the following canonical external mapping. Jira status names are workflow configurable; the values below are the interchange defaults. Labels and assignees are intentionally not stored by this service yet, so an importer must not invent either value.
| Record | Our field or value | GitHub Issues | Jira |
|---|---|---|---|
| Ticket | id |
number (with id retained as external metadata) |
key (with id retained as external metadata) |
| Ticket | title |
title |
summary |
| Ticket | statement |
body |
description |
| Ticket | status |
state |
status |
| Ticket state | filed |
open |
To Do |
| Ticket state | triaged |
open |
To Do |
| Ticket state | scheduled |
open |
To Do |
| Ticket state | in-progress |
open |
In Progress |
| Ticket state | in-review |
open |
In Progress |
| Ticket state | deployed |
open |
In Progress |
| Ticket state | verified |
open |
Done |
| Ticket state | closed |
closed |
Done |
| Ticket state | blocked |
open |
Blocked |
| Ticket state | declined |
closed |
Won't Do |
| Ticket state | duplicate |
closed |
Duplicate |
| Ticket | not stored | labels |
labels |
| Ticket | not stored | assignee |
assignee |
| Ticket | perspective.filedAt |
created_at |
created |
| Ticket | updatedAt |
updated_at |
updated |
| Comment | id |
id |
id |
| Comment | author |
user |
author |
| Comment | body |
body |
body |
| Comment | createdAt |
created_at |
created |
| Comment | updatedAt |
updated_at |
updated |
Dependencies
Dependencies
| ID | Version |
|---|---|
| @open-matrix/contracts | 1.1.32 |
| @open-matrix/core | 1.1.32 |
| @open-matrix/system-postgres | 1.1.32 |
Development Dependencies
| ID | Version |
|---|---|
| @matrix/test-utils | 1.1.32 |
| @types/node | ^20.0.0 |
| esbuild | ^0.25.0 |
| tsx | ^4.0.0 |
| typescript | ^5.3.0 |