Oko/Docs

Operations

Frustration register

Every moment the operator lost patience: his words, how many times he had already asked, what the agent did to cause it, and the revision that removed the cause.

Frustration register#

Every moment the operator lost patience with his own agents is recorded in Oko: his words verbatim, why the reading fired, how many times he had already asked for the same thing, what the agent did to cause it, and the revision that removed the cause.

Why a count was not enough#

Oko's model reads every operator message once (oko tasks read, and each control pass): what kind of message it is, and whether it shows frustration with the agent. The Activity screen counts the prompts read as frustrated over the last day, week and all time, and says how many prompts are not read yet, since those count in no window. No word list decides it, so a message in any language or phrasing is read the same way.

A count says a number went up. It cannot say what the session was doing to him when it did, whether anybody named the cause, or whether the cause was ever removed. The moments themselves are kept here.

A moment is not a defect#

A defect is a fact about a product. A moment of frustration is a fact about what the product did to the person using it, and the two are not the same record: several moments can come from one defect, and a moment can have a cause that is nobody's defect at all — a session that answered a question and left the work undone, for instance.

They are tied by defect: when a moment forced a defect into the open, the identifier is stored on it and checked against the defect register, so a moment can never point at a record that does not exist.

Tama's lesson for moments linked to the same defect carries that identifier beside each source and offers oko defects show <id> to inspect the observed failure and repair plan. An unlinked named cause offers oko frustration show <moment-id> instead. The link does not close the moment or install a rule.

Commands#

CommandWhat it does
`oko frustration scan {--session ID \--transcript PATH} [--json]`Read a session's own turns and record every moment they carry. Reading the same session again updates what was measured instead of writing a second set of records.
oko frustration list [--open] [--session ID] [--json]Every moment, newest first, with whether its cause is named and which revision answered it.
oko frustration show <id> [--json]One moment in full: his words, the reading, the repetition, the cause, the linked defect and the revision that answered it.
oko frustration record --session ID --quote "…" [--ordinal N] [--repeats N]Write a moment by hand, for what a transcript cannot hold — something said out loud, or on another channel. A record without his words is refused.
oko frustration cause <id> --cause "…" [--defect DEFECT_ID]Say what the agent did that caused it. A defect identifier is resolved against the defect register and refused when it names nothing.
oko frustration answer <id> --revision R --detail DClose the moment with the revision that removed its cause. Refused while the cause is unnamed, and refused a second time once it is answered.
oko frustration reopen <id> --reason RTake an answer back: the revision named did not remove the cause. The moment is open again with its cause still named, and the register keeps which answer failed and why. Refused when the moment is not answered.

oko index sync records the moments of every session it rewrites whose transcript is on this machine, with the same reading as scan, so the register fills as sessions are indexed and nobody has to run scan by hand. Its JSON answer carries frustration_moments, how many moments that pass recorded, and frustration_unreadable, each session whose transcript could not be read and why.

To keep the register current, schedule index on a registered local host after oko index sync --json has completed successfully there. For example, give it its own retained UUID and run oko routines create --id <index-uuid> --name transcript-intake --action index --cron '0 8 * * *' --tz Europe/Warsaw --host <registered-local-host> --enabled. Read its terminal receipt with oko routines inspect <job-id> --json; a fired schedule is not proof that the shared catalogue or frustration register was updated. Keep the delivery routine later than intake, so a completed intake can contribute new evidence before Tama prepares proposals.

An enabled rules routine delivers Tama's new proposals without a manual scan. Create it with oko routines create --id <uuid> --name learned-proposals --action rules --cron '<five-field schedule>' --tz <IANA zone> --host <operator Mac> --enabled, then inspect a completed occurrence with oko routines inspect <job-id>. It reads tama rules digest --json and offers each new or changed proposal through a Mac notification and the suggestions Slack channel when configured.

For a daily 09:00 local delivery, retain a UUID and use:

Example
oko routines create --id <uuid> --name learned-proposals --action rules \
  --cron '0 9 * * *' --tz Europe/Warsaw --host <registered-local-host> --enabled
oko routines list --json
oko routines inspect <job-id> --json

Use the host's registry name, not the resolved address printed on an existing schedule. Creation refuses an unknown or nonlocal host. enabled and nextDueAt prove a schedule exists, not that a notification arrived. After an occurrence, inspect its terminal job and result.rules: delivered names proposals that reached at least one channel, channels names those channels, and notDelivered explains failures such as an unreadable Slack credential. A failed Slack leg does not erase a successful Mac notification; fireCount alone proves only submission.

A lesson is new when its correction identities or the explanation and action shown to the operator change, even if its count stays the same. Existing identity-only delivery records gain a content baseline without replaying an unchanged lesson. Older count-only records still need the lesson's count to exceed the recorded count before identity tracking begins. The receipt distinguishes delivered proposals from pending ones, names failed channels, and includes Tama's unreadable evidence sources. Malformed delivery history or a digest without a proposals/unreadable array is a refusal, not an empty list; failed proposals are not marked delivered.

Tama keeps moments without a named cause in the separate cause:unexplained proposal. The routine delivers that proposal when new moment identities appear; it does not claim they share a cause. oko frustration list --open lists the moments to inspect before naming a producing process.

How a turn is read#

Two readings, either of which records a moment, each named on the record so a reader can disagree with it:

  • the model's reading — Oko's model read the turn as frustrated; the marker names the model and its confidence. A turn in capitals is read by the model like any other; no letter count decides it. A turn not read yet carries no such marker until oko tasks read reaches it;
  • repetition — the same demand already made earlier in the session, compared with case, punctuation and spacing removed, so napraw to and NAPRAW TO!!! are one demand made twice.

Repetition is the measurement no count had. A first napraw to is an instruction. The fourth is a complaint about the three that were ignored, and the register stores how many came before it.

Naming the cause is required#

A moment cannot be answered until somebody says what the agent did. A revision attached to an unexplained moment records that something was done near the anger, not that the reason for it is gone — and the next session repeats the evening. That refusal is the point of the register.

What a record holds#

session_id, ordinal, at, quote, markers, repeats, then cause, cause_at and defect once somebody explains it, and answered_at, answered_in and answer_detail once the cause is gone. A moment is open exactly while answered_at is absent.

The register is stored at ~/Library/Application Support/Oko/frustration.json. OKO_FRUSTRATION_REGISTER moves it, which is what a test uses and what a second machine points at its own copy. Like the defect register it is published nowhere: it quotes the operator verbatim, and those quotes name products, hosts and people.

The register is owned by oko, the one Oko program. oko frustration list, show, scan, record, cause and answer each take --json. scan reads the transcript and records each moment in the same register oko frustration record writes. record takes --at as an ISO 8601 time and --marker once for each reason the reading fired.

In Oko Desktop#

Frustration, under Work, shows the same records: how many are recorded, how many have no cause named, how many are still unanswered, and the worst repetition in the register, then each moment with his words, the reading, the session it happened in, the cause and the revision that answered it. Unanswered moments carry two buttons — name the cause, and answer with a revision — and the second stays disabled until the first is done, which is the same refusal the CLI performs. An answered moment carries The answer did not hold — reopen, which asks why and runs oko frustration reopen. The sidebar carries the number of unexplained moments beside the row, so a cause still sitting in the product is visible from every screen.

Migrated from src/content/docs/frustration-register.md