Skip to content

fix(cli): apply the documented mex timeline --type filter - #148

Open
tonydzi wants to merge 1 commit into
mex-memory:mainfrom
tonydzi:fix/timeline-type-filter
Open

fix(cli): apply the documented mex timeline --type filter#148
tonydzi wants to merge 1 commit into
mex-memory:mainfrom
tonydzi:fix/timeline-type-filter

Conversation

@tonydzi

@tonydzi tonydzi commented Aug 26, 2026

Copy link
Copy Markdown

Disclosure: this patch was researched and written with an AI assistant (Claude Code), reviewed and submitted by me. Every claim below is from a live run on this branch, not from a model's guess.

What was broken

mex timeline --type <kind> is documented as "Filter by event type" and does nothing.

Commander parses the flag into opts.type, but runTimeline reads TimelineOpts.kind. The action passed the parsed options straight through, so kind stayed undefined and this line in runTimeline never filtered anything:

const kind = opts.kind ? normalizeKind(opts.kind) : null;

The log command, ten lines up in the same file, already does the mapping the way it should: runLog(config, message, { kind: opts.type, ... }). timeline was the one that forgot.

How I checked it

Fresh clone of main at 4f315c7, npm install && npm run build, a scratch project with three events (one decision, one risk, one note):

$ mex timeline --type decision
2026-08-26 note plain note
2026-08-26 risk watch out for the wasm heap
2026-08-26 decision picked sqlite for the store

All three, for a filter that should return one.

The second symptom is the one I'd care about more:

$ mex timeline --type session_start
2026-08-26 note plain note
2026-08-26 risk watch out for the wasm heap
2026-08-26 decision picked sqlite for the store
$ echo $?
0

session_start is not an event kind and never can be — EVENT_KINDS is decision | note | risk | todo, and readEvents drops any line whose kind is outside that set. mex log --type session_start says so plainly:

Unknown event type "session_start". Use decision, note, risk, or todo.   (exit 1)

timeline answered a nonsense filter with unfiltered output and exit 0. Anything reading that output — a person or an agent — gets a confident wrong answer instead of an error.

Control: --since 2030-01-01 correctly printed "No events found", so this is not options-passing broken in general. Only the kind option was misnamed across the boundary.

What changed

One line of behaviour in src/cli.ts — pass kind: opts.type explicitly instead of spreading opts. That restores both halves of the intended design: the filter filters, and an unknown kind is rejected by the existing normalizeKind with the same message mex log prints.

Tests:

  • test/cli.test.ts — the existing assertion was expect(runTimeline).toHaveBeenCalledWith(config, { ..., type: "risk" }), which encoded the bug. It now asserts kind: "risk", and the in-file program copy mirrors the real wiring.
  • test/cli.test.ts — a new spawn test drives the built dist/cli.js end to end, next to the existing spawn tests: --type decision returns 1 of 2 events, --type session_start exits 1 with the mex log message.
  • test/events.test.tsrunTimeline filtering and unknown-kind rejection covered directly.

Proof the tests bite

Reverting only the src/cli.ts change, leaving the tests alone, and rebuilding:

× built CLI main-module guard > filters the timeline by --type through the real binary
  → expected [ { …(5) }, { …(5) } ] to have a length of 1 but got 2

Suite state

npm run typecheck clean, npm run build clean.

npm run test on this branch: 517 passed, 4 failed. The same command on untouched main on the same machine: 514 passed, 5 failed. The failures are the same set either way — compiler-extraction, engine, and graph-v2-integrity cases timing out at the default 5000 ms on my laptop, and the set shifts run to run. They are load-related and unrelated to this change; nothing under src/graph/ is touched here. The 3 added tests are the delta in the totals. Happy to attach the full control output if useful.

The new spawn test carries an explicit 30_000 timeout, matching the convention already used in graph-integration.test.ts and friends, so it does not join that flaky set on a loaded runner.

`mex timeline --type <kind>` was silently ignored. Commander stores the
flag as `opts.type`, but `runTimeline` reads `TimelineOpts.kind`, so
spreading the parsed options left `kind` undefined and the filter matched
every event.

Two visible effects:

  mex timeline --type decision       # listed notes and risks too
  mex timeline --type session_start  # exit 0, listed everything

The second one is the worse half: `mex log --type session_start` rejects
that value with `Unknown event type "session_start". Use decision, note,
risk, or todo.`, while `timeline` accepted it and answered with unfiltered
output. `--since`, `--limit`, and `--json` were unaffected — only the kind
option was misnamed across the boundary.

The `log` command in the same file already does this mapping
(`{ kind: opts.type }`); `timeline` did not.

Tests:
- test/cli.test.ts now asserts the handler is called with `kind`, and the
  in-file program copy mirrors the real wiring. The previous assertion
  (`type: "risk"`) encoded the bug.
- a spawn test drives the built `dist/cli.js` end to end: `--type decision`
  returns 1 of 2 events, and `--type session_start` exits 1 with the same
  message `mex log` prints.
- test/events.test.ts covers `runTimeline` filtering and unknown-kind
  rejection directly.

Reverting only the `src/cli.ts` change turns the spawn test red with
"expected 2 events to have a length of 1".

Assisted-by: Claude Code / claude-opus-5
Machine: MacBook-Anton
Account: a
Operator: robot:git-s3-docs-fix-lane
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants