Skip to content

feat(cli): rehome cline-cli and codex throughput, with the schema sweep and decode tests it needs - #940

Open
ozymandiashh wants to merge 3 commits into
getagentseal:feat/core-extractionfrom
ozymandiashh:fix/rehome-new-files
Open

feat(cli): rehome cline-cli and codex throughput, with the schema sweep and decode tests it needs#940
ozymandiashh wants to merge 3 commits into
getagentseal:feat/core-extractionfrom
ozymandiashh:fix/rehome-new-files

Conversation

@ozymandiashh

Copy link
Copy Markdown
Collaborator

Draft until independent review completes.

Upstream added two files under the old src/ path that have no counterpart on this branch: the cline-cli provider (448d470, plus its follow-up c642787) and tool-excluded active throughput metrics for Codex (a6bf81f).

Why this is not just a missing feature

Files added on one side only produce no merge conflict. When main is merged into this branch, git will happily create both at src/… — a path npm workspaces does not build and no registry imports. Green build, no conflict marker, and a whole provider quietly does not exist.

That is the failure mode this PR exists to prevent, and it is invisible by construction.

What landed

cline-cli follows the phase-8 recipe: discovery and I/O host-side, pure record decode in core, registered alongside its neighbours, with the deduped-rollup follow-up folded in.

codex-throughput needed one repair the original did not. The mapper that writes provider calls into the session cache dropped activeDurationMs, activeGeneratedTokens and toolWaitMs, so the three fields never survived the round-trip — and the dashboard's Tok/s column could not have populated regardless of what was ported.

Worth being explicit that the consumer is real: the header, the anyActiveTiming gate, the calculation and the model-breakdown aggregation are all present on this branch. This is not a column ported into a void; the only broken link was the write hop.

The test goes end-to-end through parseAllSessions and asserts the exact shape the aggregation consumes. A mapper unit test would have passed while the column stayed empty — which is precisely how the gap survived the original port.

Verification

Core 521. Seven targeted CLI files, 50 tests, covering the cache round-trip, throughput, the TPS surface, codex providers, rich capture and cache invalidation.

@ozymandiashh
ozymandiashh force-pushed the fix/rehome-new-files branch from 5bec4a6 to ebdb9f8 Compare August 5, 2026 13:19
@ozymandiashh
ozymandiashh marked this pull request as ready for review August 5, 2026 13:39
@ozymandiashh
ozymandiashh marked this pull request as draft August 5, 2026 14:10
…ayout

Upstream added two files under the old `src/` path that have no counterpart
here: the cline-cli provider (448d470, with its follow-up c642787) and
tool-excluded active throughput metrics for Codex (a6bf81f).

Files added on one side only produce no merge conflict. When main is merged
into this branch, git will happily create both at `src/…` — a path npm
workspaces does not build and no registry imports. Green build, and a whole
provider quietly does not exist. Nobody gets a conflict marker to notice.

cline-cli follows the phase-8 recipe: discovery and I/O host-side, pure record
decode in core, registered alongside its neighbours.

The throughput port needed two repairs the original did not, both of which
would have left the dashboard's Tok/s column empty.

First, the write hop: the mapper that converts provider calls into cached turns
dropped activeDurationMs, activeGeneratedTokens and toolWaitMs, so the three
fields never survived the round-trip. Fixed in providerCallToCachedCall, with
the read-back in cachedCallToApiCall carrying them too.

Second, append-resume: a parse that ends mid-task (the live-session case)
cached the task's calls with no timing, and when the appended task_complete
arrived the decoder's per-pass timing window had already been discarded — the
fields stayed missing until a full re-parse. The decoder now threads the task
window through its serialized state (taskResultStart / taskGeneratedTokens /
taskToolIntervals / taskStartedAt / openToolStarts), and a task_complete that
closes a window opened in an earlier pass returns a timing patch the CLI applies
to the concatenated prior+new calls. CODEX_CACHE_VERSION 10 and the codex
session-cache parse version bump once so already-cached sessions re-derive.

Both links are covered end-to-end rather than by mapper unit tests that would
pass while the column stayed empty: a parseAllSessions round-trip test (cold +
warm), an end-to-end append case through parseAllSessions, a CLI resume test
asserting the mid-task-cut append equals a cold decode of the grown file, and a
core split-invariant test that the timing survives ANY two-pass split with the
serialized state threaded.
… keys

Three contract defects in the published observation surface, and a fourth that
the first attempt at fixing them created.

**`model` and `pricingModel` were unbounded free text** — `z.string().min(1)`,
no max, no pattern — inside a schema whose docstring states that no field can
hold free text. For vercel-gateway the value arrives from a fetched report.

The first attempt bounded them with a pattern. Review proved that wrong: real
providers emit display names, not identifiers. Antigravity reads
`payload.model.display_name` directly, Warp's alias map is a closed ten-entry
list that returns anything unmapped verbatim, and devin emits the same shape.
A pattern would have rejected the envelope for those providers, and the next
Warp model to ship would have broken decoding — a breaking narrowing of a
contract already published at 0.9.20.

So the value is normalized at the observation boundary instead, which is what
this package already does for tool names, rather than validated and rejected.

**The smuggling test asserted the leak survives** — it planted a prompt in
`model` and checked it was still there. Inverting that assertion exposed the
real carrier: `dedupKey` is built from the model string, so bounding the model
while the key is derived from it is half a fix. The secret rode through the
key.

**`sourceRef` was documented as an opaque fingerprint while every caller passed
a raw absolute path**, and five decoders folded it straight into dedup keys —
which are observation output. A reviewer produced a schema-valid envelope
containing a real home directory path. Rather than rewriting the contract text
to match the leak, the decoders now fingerprint it: codebuff, lingtai-tui,
zerostack, pi/omp and grok all route through the keyed helper. That also
matters for getagentseal#931, which derives sync span ids from these keys.

**Cross-PR review: the fingerprint was keyed NOWHERE on the production path.**
The first version of this change added `sourceRefFingerprint` with an unkeyed
SHA-256 fallback, justified by the CLI bridge's old comment that the rich
decoder "never consumes" the privacy key. That comment was overtaken by this
very change — the decoders consume the key precisely via the dedup keys being
fingerprinted here, so the fallback shipped dictionary-attackable digests of
absolute paths in the same dedup keys, one layer down from the raw-path leak
it replaced. The bridge now threads the host privacy key (getHostPrivacyKey,
per-install stable, already used by the optimize detectors) into the rich
decode, and `sourceRefFingerprint` now requires a key and throws on an empty
one (decision D1, like every other fingerprint in the module) — an empty key
can no longer silently degrade to an unkeyed digest. The bridge parity goldens
derive their expected dedup keys under the same host key, and the session /
daily cache bumps below still fire exactly once: the only released key shape
is the raw-path one, so the re-parse drops those keys and lands the keyed
fingerprint shape in the same pass.

The codebuff golden pinned the raw-path form. It is updated with the derivation
shown, and a comment recording that the raw path was the defect — the same trap
the kiro golden set in a sibling PR.
Carries the regression tests from getagentseal#928, which is closed in favour of this
branch. That PR reduced to tests alone once review established its source
fixes were already here — and the tests are the part this branch was missing:
it restored the behaviour without anything proving it stays restored.

Each pins one restoration and fails against a decoder without it: custom tool
calls reaching the turn, the eight-type fork-replay skip in both directions,
the Buffer path synthesizing info and invocation, and exec mapping to Bash.
@ozymandiashh ozymandiashh changed the title feat(cli): rehome cline-cli and codex throughput into the workspace layout feat(cli): rehome cline-cli and codex throughput, with the schema sweep and decode tests it needs Aug 5, 2026
@ozymandiashh

Copy link
Copy Markdown
Collaborator Author

This PR is now stacked, and absorbs #928. Three commits:

  1. the rehome itself
  2. fix(core): bound the model field, and stop the smuggling test certifying the hole #933's commit, carried underneath — the new cline-cli provider calls normalizeModelIdentifier, which arrives with fix(core): bound the model field, and stop the smuggling test certifying the hole #933. Without it this branch does not typecheck, so the two are genuinely coupled rather than merely ordered. Cross-review flagged exactly this as a gap that fell between the two PRs and was therefore nobody's.
  3. the codex regression tests from fix(codex): restore decode behaviour lost in the extraction #928, which is closed in its favour. Review established fix(codex): restore decode behaviour lost in the extraction #928's source fixes were already here in full — but its tests were not, so this branch was restoring behaviour that nothing proved stayed restored. Merging them one file into three duplicate helper definitions was the alternative.

Green as it stands: core 545, targeted CLI 69. Previously it was red on its own and would have stayed red until #933 landed — which is not a PR anyone should be asked to merge.

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.

1 participant