Skip to content

Parse records Observer already reads: direction blocks, Codex durations, Grok MCP, read success, Codex Read #128

Closed

Description

@lukemaj

What: Observer parses records it already reads but currently drops or misreads: current AgentsMD direction blocks, Codex command durations, Grok MCP start/completion records, failed reads counted as reads, and Codex Read function calls.
Why: a measured gap inventory on bestia (2026-10-19, see #21) found these parser defects silently blank fields that open Issues need (version comparisons for #52, timing for #25, procedure-read evidence for the Cue adoption report).
So what: an agent implements the five parser fixes with fixtures; no user decision is needed.

Outcome

Each listed native record shape is imported with its real meaning, old ledgers re-derive the fields on the next sync, and anything still unparsed stays visible as a gap, never as a silent NULL.

Contribution to the Objective: native records durably cover usage, tool, skill, read and execution events (Objective "Done when", first bullet).

Measured gaps (bestia ledger, 2026-10-19 13:23-13:55 Warsaw, installed 1.2.6 and checkout c1b563e)

Gap Evidence Needed by
BLOCK_RE (agent_observer/identity.py) requires the end marker right after the JSON, so current sectioned direction blocks are rejected 1,781 headers / 212 Claude sessions; 1,753 / 917 Codex sessions AgentsMD version breakdowns (#52, compare)
Codex _duration accepts only numbers; native durations are {secs, nanos} objects 61,556 Codex exec results with NULL duration (rechecked by the coordinator) #25
Grok MCP start/completion records are quarantined in import_errors 1,095 starts / 234 files; 1,092 completions with duration, success, timeout and retry #25
Failed or pending commands still produce skill_read Codex 109 skill reads on exit 1/2; Grok 14 on error, 5 without a result Cue adoption report (did the agent successfully read the procedure)
Codex function_call named Read stays a tool_call, never read/skill_read Parser branch confirmed; 0 local occurrences on bestia, unknown on rocky and cavallo Cue adoption report

Elon record

Acceptance criteria

  • The current direction block (with section markers and the nonce-carrying end marker) yields validated instruction identity; the old format still parses; marker-shaped free text still fails closed.
  • Codex {secs, nanos} durations become duration_ms; numeric forms keep working.
  • Grok MCP start/completion records import as tool timing and outcome, joined by call ID to existing tool events without double counting.
  • A read event carries attempted, failed, pending or successful state; reports that count procedure reads count only successful ones.
  • A Codex Read function call with a successful result becomes read, or skill_read under a Skill directory.
  • Re-sync of an existing ledger fills these fields idempotently; the capability matrix describes the result.

Design review

  • Independent review: Sol (gpt-6.1-sol, medium) gap inventory with read-only queries, 2026-10-19; Grok (grok-4.7, medium) design review found the Codex Read and failed-read defects. Changes inside existing adapters, no new component.
  • User decisions: fill important measured gaps, drop the rest (the user, 2026-10-19).

Non-goals

New hooks, ContextMD import (separate Issue), quota parsing (#6), inferring anything a record does not state.

Blockers

None.

Required proof

Fixture tests for each shape (failing first), full suite output, and before/after counts of the queries above on a ledger copy, recorded on this Issue.

Activity

  1. lukemaj commented on Oct 19, 2026

    @lukemaj
    ContributorAuthor

    What changed: The five native parser gaps are implemented in PR #130, with read-state reports and old-source replay.
    Why: Existing records were dropping direction identity and timing or overstating successful procedure reads.
    So what: The tested and independently reviewed implementation is ready for the merge decision; merge and release remain unperformed.

    Candidate and authority

    • Worktree: /home/luke/dev/toolboxmd/agent-observer-worktrees/128-parser-gaps; branch feat/128-parser-gaps.
    • Base: 1fbbb0fe3098842d19e04bc5a6b35a3667ecda90; head: 8647f156de05bc506f574ae94f28024fd5d3d5d7, pushed to origin.
    • VERSION and all plugin manifests unchanged at 1.3.0 by explicit user instruction; Unreleased changelog.
    • No ContextMD import or report.py changes. Shared ingest/privacy changes are limited to replayed durations, read-state enums and MCP metadata.

    Elon record

    Requirements and who asked: The user and #128 require the five measured parser repairs, failing-first fixtures, successful procedure-read counts and idempotent old-ledger repair, including the follow-up multipath review repair and Codex identity check.
    Deleted: New hooks, new importers, ContextMD work, release/version changes and new schema tables are unnecessary.
    Bottleneck: Correct derivation from existing native records.
    Checked myself: Read the exact parser paths, observed six new fixture tests fail on the base, passed the final 871-test suite, inspected native key/type aggregates and replayed only a read-only backup of the 1.3.0 ledger.

    Tests

    • Failing first: python3 -m unittest tests.test_parser_gaps on the original code ran six tests: five failures and one missing-identity error, one or more for each of the five Issue gaps. The same six then passed.
    • Expanded fixtures exercise numeric duration compatibility, malformed durations, legacy/sectioned direction boundaries, reimport idempotency, incremental Read output, MCP joins and timeout/retries, locationless completions, opaque JSON file contents and late instruction-version evidence.
    • Existing test fixture changes mark synthetic successful skill reads explicitly and expect current import revision 10; historical revision-9 seeds remain unchanged.
    • python3 -m unittest discover -s tests: exit 0 on 8647f156de05bc506f574ae94f28024fd5d3d5d7, one suite at a time:
    Ran 871 tests in 61.361s
    
    OK
    
    • Fifteen parser-gap fixture tests are included. No test runs remain active or planned.
    • python3 -m compileall -q agent_observer tests: exit 0 on 8647f15.
    • git diff --check: passed.

    Ledger-copy proof (historical candidate 634fb26)

    Audited bestia on 2026-10-19 at 634fb2671ece0522a40b7b45d3bf9827fedac4c0. These retained aggregates were not rerun for the follow-up; its new edge cases are fixture-verified and no live ledger was accessed. Waited for agent-observer --version to print 1.3.0, then used sqlite3.connect("file:<live-ledger>?mode=ro", uri=True).backup(scratch_connection) into ~/.local/state/agent-observer-scratch/128/observer.db. No live-ledger writes or sync. No prompt/transcript contents were printed.

    Replayed the captured source set using db.connect(scratch) / db.init_db, claude.import_claude_file, codex.import_codex_file, and grok.import_grok_session with the same shared _SyncCtx parent index used by sync. The set contains all 238 Claude and 1,064 Codex sources plus 391 Grok sessions owning tool/read evidence or unknown records: 1,693 import operations, 0 failed, 0 missing. Grok sources were restaged at import revision 9 in scratch to verify final-code repair; fixtures verify repeated imports without duplicate rows.

    The first disposable measurement counter mistakenly added the adapters' failed lists to an integer; this affected the instrument only. The corrected measurement completed with 0 failures. Reusing a shared Grok parent index avoids repeatedly scanning the containing tree.

    Native logs were still appendable while the ledger copy stayed isolated, so totals grew between baseline and replay. Count changes are reported explicitly rather than attributing all new events to parser repair.

    direction_identity

    SELECT harness,COUNT(*),SUM(instructions_sha256 IS NOT NULL),SUM(direction_status='ready') FROM sessions WHERE harness IN ('codex','claude') GROUP BY harness;

    Before: [["claude", 238, 0, null], ["codex", 1064, 0, null]]

    After: [["claude", 238, 217, 200], ["codex", 1064, 920, 901]]

    codex_exec_duration

    SELECT COUNT(*),SUM(duration_ms IS NULL) FROM events WHERE session_key LIKE 'codex:%' AND family='tool_result' AND name='exec';

    Before: [[61683, 61683]]

    After: [[61896, 0]]

    grok_mcp_errors

    SELECT COUNT(*) FROM import_errors WHERE harness='grok' AND error='unknown_record' AND line_excerpt IN ('call_id,server_name,timeout_sec,tool_name,ts,type','auth_retry_attempted,call_id,duration_ms,is_timeout,reconnect_attempted,server_name,success,tool_name,ts,type','auth_retry_attempted,call_id,duration_ms,error,is_timeout,reconnect_attempted,server_name,success,tool_name,ts,type');

    Before: [[2192]]

    After: [[0]]

    reads_by_state

    SELECT substr(session_key,1,instr(session_key,':')-1),status,COUNT(*) FROM events WHERE family='skill_read' GROUP BY 1,2;

    Before: [["claude", null, 329], ["codex", "completed", 5421], ["codex", "failed", 109], ["grok", null, 2994], ["opencode", "ok", 66]]

    After: [["claude", "ok", 336], ["codex", "failed", 109], ["codex", "ok", 5436], ["grok", "attempted", 7], ["grok", "failed", 13], ["grok", "ok", 2979], ["opencode", "ok", 66]]

    codex_Read_calls

    SELECT COUNT(*) FROM events WHERE session_key LIKE 'codex:%' AND family='tool_call' AND name='Read';

    Before: [[0]]

    After: [[0]]

    grok_tool_results

    SELECT COUNT(*),SUM(duration_ms IS NOT NULL) FROM events WHERE session_key LIKE 'grok:%' AND family='tool_result';

    Before: [[31471, 31145]]

    After: [[32056, 31728]]

    Direction columns are harness, session count, non-NULL instruction hash count and ready-direction count. Codex duration columns are total exec results and NULL durations. Skill-read columns are harness, state and count. Grok result columns are total results and results with timing. Successful procedure reports now exclude failed/attempted/pending states. Native Codex Read occurrences remain zero, so that shape is fixture-verified only.

    SELECT family,COUNT(*) FROM events WHERE session_key LIKE 'grok:%' AND ((family='tool_call' AND json_type(detail_json,'$.timeout_sec')='integer') OR (family='tool_result' AND json_type(detail_json,'$.is_timeout') IN ('true','false'))) GROUP BY family;

    Result: [["tool_call", 554], ["tool_result", 553]]

    SELECT COUNT(*) FROM (SELECT session_key,family,native_id,COUNT(*) n FROM events GROUP BY session_key,family,native_id HAVING n>1);

    Result: [[0]]

    SELECT error,COUNT(*) FROM import_errors WHERE harness='grok' GROUP BY error;

    Result: [["missing_id", 1], ["unknown_record", 116], ["usage_conflict", 110]]

    PRAGMA integrity_check;

    Result: [["ok"]]

    The 554 MCP call rows and 553 result rows are distinct native call identities; repeated start/completion witnesses join them rather than adding counts. Residual Grok diagnostics remain visible and outside these five fixes.

    Review follow-up

    Review response

    The Grok 4.7 medium finding against 634fb26 is reproduced: the exact two-path, two-update case observed only 17.3.1, dropping 17.1.0. The same loss occurred when completion arrived in a subsequent sync. Both cases have new real-adapter fixtures. The reader now remembers all validated paths by call ID and observes each once only on success. An incremental import rebuilds that state from the complete prefix already cached for usage replay. This introduces no new disk reads, schema or privacy detail fields.

    Codex check: _ingest_response_item already accepts call_id or id for tool-result events and Read call events, but its Read output lookup used only call_id. A real-adapter fixture with id-only call/result records reproduced attempted instead of ok. The output identity is now normalized once and used by both the result event and Read lookup/update. This proves the accepted adapter shape; it does not establish that a native Codex writer emits id-only Read outputs. Native Read occurrences in the previous bestia audit were zero.

    Proof

    • Failing first at 634fb26: all three new regression tests failed for the intended evidence/state mismatch.
    • python3 -m unittest tests.test_parser_gaps tests.test_grok: 64 tests passed.
    • Final full suite on 8647f156de05bc506f574ae94f28024fd5d3d5d7: 871 tests, OK, 61.361s. python3 -m compileall -q agent_observer tests: exit 0. Four new regressions in this follow-up ran failing first before their repairs.
    • Current delta touches only both adapters and tests/test_parser_gaps.py; VERSION/manifests unchanged.
    • Previous ledger-copy aggregate evidence remains recorded above for 634fb26. This follow-up's newly reproduced shapes are fixture evidence; no live ledger was accessed in this follow-up.

    The incremental path reconstruction also exposed the ledger's first-known-value policy: an existing version-A identity prevented newly completed version-B evidence from replacing it. The fourth new fixture reproduced this. The adapter now refreshes reconstructed path counts after replay while retaining other identity evidence and preferring a release mapped from the instruction hash. This preserves full-import/incremental equivalence without changing generic session-upsert policy or adding storage.

    Delivery state

    PR #130 is implemented and proved at 8647f156de05bc506f574ae94f28024fd5d3d5d7. Exact-head independent review round 5 passed with no blocking or nonblocking findings; the head has review/independent=success from lukemaj. No merge, version preparation, release, installation or deployment. Website/SEO impact: none, because no website or URL changes.

    The scratch database and its task directory were deleted and verified absent after retaining these aggregates. Disposable local proof files are removed after this record is published. Worktree and branch remain for the open PR; the merger retires them. Residual non-MCP diagnostics and seven attempted Grok reads remain visible. Native Codex Read coverage on bestia is fixture-only because no such calls occur in this ledger.

  2. added a commit that references this issue on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions