Skip to content

[Bugfix #1137] Fix gitea forge preset against the real tea CLI - #1

Closed
pseudoseed wants to merge 4 commits into
mainfrom
builder/bugfix-1137
Closed

[Bugfix #1137] Fix gitea forge preset against the real tea CLI#1
pseudoseed wants to merge 4 commits into
mainfrom
builder/bugfix-1137

Conversation

@pseudoseed

Copy link
Copy Markdown
Owner

Summary

Fixes cluesmith#1137

The gitea forge preset was authored against the Gitea REST API JSON shape
but invoked the tea CLI, whose tea <entity> list/view output is a
flattened, --fields-limited view (and in some cases the referenced
flag/field/subcommand doesn't exist). Every read concept either errored or
emitted a shape that didn't match forge-contracts.ts.

Root Cause

tea exposes two divergent JSON surfaces:

  1. tea <entity> list/view --output json — flattened/limited (head/base are
    strings, no body/description, merged state synthesized, whoami has no JSON).
  2. tea api <endpoint> — a raw passthrough returning the canonical Gitea REST
    shape that codev's jq normalizers + forge-contracts.ts already assume.

The scripts read from (1); the contracts expect (2).

Fix

Route the read concepts through tea api:

Concept Change
user-identity tea api user | jq .login (tea whoami has no --output json)
pr-view tea api repos/<repo>/pulls/NPrViewResult
pr-list tea api repos/<repo>/pulls?state=openPrListItem[]; now also populates real reviewRequests/isDraft/body
pr-exists tea api repos/<repo>/pulls?state=all with nested .head.ref + .merged bool
issue-view tea api repos/<repo>/issues/N + a second call for the comments ARRAY (Gitea's issue object reports comments as an int count, which would crash consumers' .comments.filter(...))
recently-merged tea api repos/<repo>/pulls?state=closed, filter .merged, use real .merged_at
issue-comment tea comments add (tea issues has no comment subcommand)

tea api needs an explicit owner/repo path segment (unlike tea <entity>,
which auto-detects it from the local git remote), and most concepts are invoked
without CODEV_REPO set (e.g. pr-exists receives only CODEV_BRANCH_NAME),
so each api-based script derives owner/repo from the origin remote, honoring
CODEV_REPO when present.

Left issue-search untouched: it isn't in the issue's broken list, and its only
difference from the working issue-list is an unverified body field — changing
working/unverified code on assumption would violate minimal-change.

Test Plan

Note on the full test suite

The full npm test run shows 9 failures in unrelated files
(team-update collectEvents ×7, team-github, team-cli) — all 5s-timeout I/O
that hangs in this resource-starved worktree/environment. Confirmed failing on
the clean base without these changes, so they are pre-existing and
environmental (they pass in CI). This PR touches none of those files.

🤖 Generated with Claude Code

pseudoseed and others added 4 commits July 6, 2026 13:06
The gitea preset invoked `tea <entity> list/view/whoami/comment`, whose
flattened `--fields` output (or missing flags/subcommands) doesn't match the
Gitea REST shape that forge-contracts.ts and the jq normalizers assume. Route
the read concepts through `tea api`, the raw REST passthrough that returns
exactly that shape:

- user-identity: `tea api user | jq .login` (`tea whoami` has no --output json)
- pr-view:  `tea api repos/<repo>/pulls/N` → PrViewResult
- pr-list:  `tea api repos/<repo>/pulls?state=open` → PrListItem[]
            (now also populates real reviewRequests/isDraft/body)
- pr-exists: `tea api repos/<repo>/pulls?state=all` with nested .head.ref/.merged
- issue-view: `tea api repos/<repo>/issues/N` + a second call for the comments
             ARRAY (Gitea's issue object reports `comments` as an int count,
             which would crash consumers' `.comments.filter(...)`)
- recently-merged: `tea api repos/<repo>/pulls?state=closed`, filter .merged,
             using the real .merged_at
- issue-comment: `tea comments add` (`tea issues` has no `comment` subcommand)

`tea api` needs an explicit owner/repo path segment (unlike `tea <entity>`,
which auto-detects it from the local git remote), and most concepts are invoked
without CODEV_REPO set, so each api-based script derives owner/repo from the
origin remote, honoring CODEV_REPO when present.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stubs a fake `tea` on PATH answering `api <endpoint>` with captured Gitea REST
fixtures (tea isn't in CI, per cluesmith#920), points the scripts at a throwaway repo
with a gitea remote, runs each real script, and asserts the normalized output
conforms to forge-contracts.ts — incl. comments-as-array, merged-only filtering,
open/merged/closed pr-exists cases, and CODEV_REPO override.

Also updates the cluesmith#568 pr-exists assertion for gitea to match the new
`state=all` query param (was `--state all` flag).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pseudoseed

Copy link
Copy Markdown
Owner Author

Superseded by the upstream bugfix PR cluesmith#1146 (same branch, targeting the codev repo). Closing this fork-internal duplicate.

@pseudoseed pseudoseed closed this Jul 6, 2026
pseudoseed pushed a commit that referenced this pull request Aug 14, 2026
…cker, perf bound, CJS interop)

Iteration 2 of Phase 2, addressing the iter-1 3-way review (Gemini + Claude APPROVE, Codex REQUEST_CHANGES):

- Codex #1 (missing claude-picker fixture): add a synthesized claude `/model` picker fixture (claude-picker.busy.txt) whose highlighted row starts with the same ❯ glyph as the composer marker, with normal-intensity model names. Pins that a picker's selection-cursor + list classifies busy via the user-text path, never a false-clean; mirrors the real codex-picker capture (`› 1. …`). Wired into the required-states assertion; suite now 23/23. Documented as synthesized in the fixtures README (sandbox claude is the ez-cli shim, same reason as claude-idle).
- Codex cluesmith#2 (perf assertion too loose): replace the single cold-run < 500ms with warm-up + best-of-5 min < 75ms. The min strips JIT/GC/scheduling noise (42.7ms cold vs 14.5ms native steady-state here), so it validates the spec's ≤~50ms seed-cap budget (measured best-of-5 = 19.2ms) instead of flaking. 5x tighter than before; 75ms is the CI-noise ceiling, not a near-budget claim (the logged value is the evidence).
- Bonus latent production bug, found while grounding the perf measurement against the compiled dist under native node: @xterm/headless resolves to its CommonJS entry (no exports map / type:module) with non-analyzable named exports, so `import { Terminal }` throws "Named export 'Terminal' not found" under native-node ESM — how the compiled bins run in production. Masked by vitest (vite interop) and dormant until Phase 4 wires the gate. Switch to the default-import form (codebase convention, cf. `import Database from 'better-sqlite3'`) plus a type-only alias for the one type-position use.

Refs cluesmith#1313.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
pseudoseed pushed a commit that referenced this pull request Aug 14, 2026
…-ceiling+memo

All three reviewers (Gemini/Codex/Claude) returned REQUEST_CHANGES; all agreed the
over-ceiling removal itself is correct and shippable. Fixes:

- Memo stale-verdict across a same-agentKey PTY respawn / RingBuffer.clear() (all
  three, HIGH): the ringToken (currentSeq:partialBytes:...) is only unique WITHIN one
  monotonic ring, so a token can alias across session instances. CachedVerdict now
  binds the live session instance too (hit = cached.session===session && token);
  getSession(tid) is stable per live terminal, so it hits across ticks and misses
  after a respawn. Test added.

- CPU regression: the memo does NOT help the expensive case (Claude #1; Codex OOM).
  A BUSY held ring repaints every tick -> token changes every tick -> the memo always
  misses exactly when the ring is largest (~230ms/tick/agent, await-serial). Added a
  cost-aware backstop backoff: after a big (> BIG_RING_UNITS=4M) not-clean render, the
  backstop skips re-classifying that agent for an exponential span (<=8 ticks). NEVER a
  hold - scheduleDrain still classifies fresh the instant the line clears, so delivery
  latency is unaffected. Test added.

- OOM doc corrected (Codex + Claude): the residual is a possible Tower OOM/crash
  (unbounded allocation), not merely an event-loop stall (xterm chunks + yields). No
  holding cap added (it would just reintroduce the outage); robust fix = off-thread
  classify / cluesmith#1047 persistent xterm, out of scope.

- Interrupt Ctrl+C was OUTSIDE the submitToSession lock (all three): a concurrent
  submission's Ctrl+C could kill another composer / run in the 100ms gap. Now the
  Ctrl+C + settle (via writeMessageToSession delayOffset) + write are one atomic locked
  section. Corrected the overstated anti-fusion claim (serializes interrupt-vs-escape
  only, not vs a concurrent mailbox delivery).

- spec-1280 T16 predicate (all three): my manifest-dir-touch scoping silently skipped
  the forgot-the-manifest-entirely case + had a Windows path.sep bug (always skipped).
  Adopted Claude's portable predicate (/1280/ branch OR touches codev/projects/1280).

- stop() now clears verdictMemo/notCleanStreak/scheduledDrains/classifyBackoff
  (Codex + Claude). cron test asserts target via objectContaining (Claude).

Deferred/flagged for the architect: off-thread/memory-bounded classify (cluesmith#1047); the
mailbox write edge taking the per-terminal lock to kill interrupt-vs-delivery fusion;
the interrupt-throw -> re-deliver duplicate (minor).

Full unit suite: 4261 pass / 48 skip / 0 fail. tsc clean.
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.

gitea forge preset is broken against the real tea CLI (0.14.2)

1 participant