Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/trajectories/typescript-bun-migration/RESUME.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Trajectory — TypeScript / Bun migration

**Status**: Active (Lane B slice 19 merged — [#902](https://github.com/Lucent-Financial-Group/Zeta/pull/902))
**Milestone**: 40 ported. Budget cluster (14/18/19) and peer-call cluster (15/16/17) both complete. Bucket B reduced to 2 unported files (`tools/git/batch-resolve-pr-threads.sh` 390L + `tools/pr-preservation/archive-pr.sh` 674L)both mutating-side, deserve careful porting. Bucket C reduced to 2 (`tools/hygiene/check-github-settings-drift.sh` + `tools/hygiene/snapshot-github-settings.sh`).
**Status**: Active (Lane B slice 19 merged — [#902](https://github.com/Lucent-Financial-Group/Zeta/pull/902); slice 20 in flight — `lane-b/ts-bun-slice-20-batch-resolve-pr-threads-2026-04-30`)
**Milestone**: 40 ported + 1 in-flight = 41 total. Budget cluster (14/18/19) and peer-call cluster (15/16/17) both complete. After slice 20 lands, Bucket B reduces to 1 unported file (`tools/pr-preservation/archive-pr.sh` 674L — bash+Python mix). Bucket C: 2 (`tools/hygiene/check-github-settings-drift.sh` + `tools/hygiene/snapshot-github-settings.sh`).
**Current blocker**: None.
**Next concrete action**: Two natural next slices: (a) slice 20 — `tools/git/batch-resolve-pr-threads.sh` (390 lines, mutates PR thread state via gh GraphQL), or (b) slice 20 — `tools/pr-preservation/archive-pr.sh` (674 lines, mutates gh API). Both are state-mutating and warrant extra equivalence-test discipline. Per Gate B: read-only scope first when possible — but neither remaining Bucket B file is purely read-only.
**Next concrete action**: After slice 20 merges, slice 21 = `tools/pr-preservation/archive-pr.sh` is the last Bucket B file (674 lines, bash+Python mix — most complex remaining). Per Gate B: read-only scope first when possible — but the remaining file is state-mutating (gh API + writes drain logs).
**Last updated**: 2026-04-30

## Why this trajectory exists
Expand Down
34 changes: 34 additions & 0 deletions docs/trajectories/typescript-bun-migration/slice-audits.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,40 @@ Per-port pattern checklist:

Slice 6 passes audit. No new patterns recorded — all reused from prior slices.

## Slice 20 — 1 port (git/batch-resolve-pr-threads — last git-cluster port) (PR pending — `lane-b/ts-bun-slice-20-batch-resolve-pr-threads-2026-04-30`)

**Slice files**:

- `tools/git/batch-resolve-pr-threads.{sh→ts}` (the batch-classifier + resolver for PR review threads matching dangling-ref + name-attribution patterns)

**Comparison points**: identical to slice 19. Within Gate B 30-day window. tsc gate active per #890.

### Code-pattern audit (per-port)

- **`batch-resolve-pr-threads.ts`** (390 → 415 lines): bash GraphQL pagination loop preserved 1:1 — same `first: 50, after: $cursor` shape, same `pageInfo.hasNextPage`/`endCursor` termination. Bash `gh api graphql -F owner=$x -F name=$y ...` shape preserved verbatim via `spawnSync("gh", ["api", "graphql", "-F", "owner=...", ...])` — positional `-F` args avoid the bash parameter-expansion-quote pitfall and the TS shape avoids the same string-concat-into-GraphQL footgun. jq pipelines (`[.comments.nodes[].body] | join("\n---\n")`) become typed `commentNodes.map(c => c.body ?? "").join("\n---\n")`. Pattern classification splits into three pattern arrays (DANGLING_REF_PATTERNS / NAME_ATTRIBUTION_DIRECT_PATTERNS / NAME_ATTRIBUTION_FUZZY_NAME × NAME_ATTRIBUTION_FUZZY_RULE) — same shape as the bash `for pat in "..." "..." ; do [[ ]]; done` loops; the fuzzy-combination check uses `.some()` × 2 rather than the bash `&&` of two `||`-OR groups. Same conservative semantics: unknown threads left unresolved.
- **GraphQL response error checking**: bash `graphql_check_errors` (inspect `.errors // [] | length`) maps to TS `if (page.errors !== undefined && page.errors.length > 0)`. Same fail-fast on partial-failure responses where gh exits 0 but GraphQL carried errors.
- **Reply templates verbatim**: the two reply markdown strings (REPLY_DANGLING_REF + REPLY_NAME_ATTRIBUTION) preserved character-for-character from bash. These get posted to live PR threads, so byte-equivalence matters.
- **Apply-mode mutations**: `addPullRequestReviewThreadReply` then `resolveReviewThread` mutations preserved 1:1. Per-thread error handling: `ResolveError` discriminated record with `stage: "reply" | "resolve"` so callers see exactly which step failed.
- **Truncation warning**: bash counts threads with `comments.totalCount > 50` (per-thread comment fetch limit); TS mirror via `truncationWarnings++` in classifyThreads. Same stderr warning format.

### Equivalence audit

Diff'd against bash output on this repo state (2026-04-30 main, run against PR #902 with 4 unresolved threads):

- **Argument-validation paths**: byte-equivalent across 3 sampled paths — no args (exit 2 + usage), `abc` (exit 2 + bad-pr-number message), `906 --aply` (exit 2 + unknown-second-arg message).
- **Live dry-run on PR #902** (4 unresolved threads): byte-equivalent — `diff <(bun ...) <(./...sh)` empty diff. Same thread classification (0 dangling-ref / 0 name-attribution / 4 unknown), same thread IDs printed in same order.
- **Apply-mode**: not exercised in this audit (would mutate live PR state). Code path verified by inspection — reply-mutation + resolve-mutation calls match bash; per-mutation error classification preserved.

### Behavioural note vs bash original

- The bash `command -v gh && command -v jq` dependency probe drops to just `command -v gh` in TS — `jq` is not needed because JSON parsing is native (`JSON.parse` replaces all jq pipelines).
- All bash safety rails preserved: positive-integer pr-number validation, exact-`--apply` second-arg check, GraphQL `errors` array inspection, null-pullRequest detection, paginated thread fetch, paginated per-thread comment fetch (50 max — same truncation warning).
- Exit-code contract identical (0 success / 1 API failures / 2 argument errors).

### Outcome

Slice 20 passes audit. **Last git-cluster port** (slice 13 push-with-retry + slice 20 batch-resolve-pr-threads — both gh-API-mutating ports now TS). Bucket B 2 → 1 (only `tools/pr-preservation/archive-pr.sh` 674L remains; bash+Python mix — slice 21). Shape lessons reusable for slice 21: GraphQL pagination + classification + apply-mode mutation.

## Slice 19 — 1 port (budget/project-runway — budget cluster closes) (PR #902, merged 2026-04-30, commit `bfdadd9`)

**Slice files**:
Expand Down
Loading
Loading