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
33 changes: 19 additions & 14 deletions plans/001-sdk-adoption-campaign.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,11 @@ moves.
snapshot, reverseOf — a receipt as data; writing it to disk stays in
gh-v1). gh-v1's tests for these move with them, rewritten against recorded
responses.
- **A6 CI and packaging** — GitHub Actions running `npm run verify` on PRs;
publish prereleases (`0.x`, `next` tag) to GitHub Packages under the
`@versionone` scope (or npmjs — decision below). Until then consumers pin a
git SHA or a tarball from `npm pack`.
- **A6 CI and packaging** — done: CI runs `npm run verify` on Linux (Node
20/22/24) and Windows (Node 24); `@versionone/agility-sdk` is on npmjs
(`1.0.0-alpha.0`, `alpha` dist-tag); `publish.yml` publishes later
versions from a `v*` tag through npm trusted publishing, gated by the
GitHub environment `npm` (an approval). Consumers install from npmjs.
- **A7 Attachments and embedded images** — gap 5's `attachment`/
`EmbeddedImage`, as part of the asset-update abstraction, not a side
channel. Two consumers to serve: gh-v1's `gh v1 attach` (list, get, add,
Expand Down Expand Up @@ -361,13 +362,17 @@ Strangler, starting below the call sites so nothing user-visible moves:
delegates to rooms' current axios instance (keeps the SSO refresh
interceptor and snackbar). Point `bulkApiService.tsx` at
`client.assets.*`. Rows arrive translated, so `getApiResults`' `IsReadOnly`
patch goes. This is the whole first PR. Needs A2 for parity of the
command-failure snackbar.
patch goes. This is the whole first PR. (A2 is done:
`CommandFailureError` carries what the snackbar needs.)
- **D2 Domain by domain.** Start with `src/domains/ai` (it already has
adapters and architecture tests), then retire string-boolean decodes per
feature (48 today). Jest + Playwright gate each PR.
adapters, architecture tests, and the injected `IHttpClient` /
`FakeHttpClient` seam), then retire string-boolean decodes per feature
(46 at the 2026-11-07 survey). Attachments and embedded images move to
`client.attachments` / `client.embeddedImages` (A7). Jest + Playwright
gate each PR.
- **D3 Native transport.** Swap the axios-backed Transport for
`createFetchTransport` with `credentials` + `onUnauthorized` (needs A1).
`createFetchTransport` with `credentials` + `onUnauthorized` (A1 is
done).
- **D4 Schema convergence.** Evaluate replacing parts of
`src/metaAssetStore/` field knowledge with the SDK `schema` service.

Expand Down Expand Up @@ -419,11 +424,11 @@ ESM" here means finishing the edges:
captured from the local dev instance (spec 000 §2a: fakes send what the
server sends — api/asset spells `"True"`, not `true`).

**agility-rooms** (slow; no handoff yet)
**agility-rooms** (slow; brief: `plans/004-adopt-sdk-agility-rooms.md`)

- **R1** Narrow the axios surface: route the 67 axios importers through
`utils/bulkApiService.tsx` and a small set of helpers, so D1 swaps one
module. Start when Track A2 lands; write the handoff then.
- **R1** Narrow the axios surface: route the axios importers (88 production
files at the 2026-11-07 survey) through `utils/bulkApiService.tsx` and a
small set of helpers, so D1 swaps one module.

## Operating model for the campaign

Expand Down Expand Up @@ -487,4 +492,4 @@ ESM" here means finishing the edges:
- [x] C2 gh-v1 rows translated through the schema; `isTrue`/`oidOf` gone — versionone/gh-v1#36
- [x] C3 gh-v1 resolve and batch on `client.resolve`/`client.batch` — versionone/gh-v1#37 (with the SDK fixes from #43)
- [x] C4 gh-v1 `gh v1 attach` on `client.attachments`, `blob` removed — versionone/gh-v1#38 (re-vendored at `d51fb16`; small files now upload inline); `raw` stays CLI-local
- [ ] D1–D4 agility-rooms
- [ ] D1–D4 agility-rooms — brief: `plans/004-adopt-sdk-agility-rooms.md` (first: decide rooms' rest-1 writes and Copy)
21 changes: 14 additions & 7 deletions plans/002-adopt-sdk-gh-v1.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# Plan 002: gh-v1 adopts `@versionone/agility-sdk` (Track C)

Brief for a session on `versionone/gh-v1`. Start once the SDK PR that adds
this file has merged into `proposed_type_script_api_version`. Source plan:
Brief for a session on `versionone/gh-v1`. Source plan:
`plans/001-sdk-adoption-campaign.md`, Track C.

**Status (2026-11-07): done.** C1–C4 merged (versionone/gh-v1#33, #35–#38);
gh-v1 then moved to the renamed, published package (#39, #40). gh-v1
reaches Agility only through the vendored SDK, apart from the `gh v1 api`
passthrough. The rest of this brief is the record of how.

## Goal

gh-v1 talks to Agility only through `@versionone/agility-sdk`. CLI behaviour and
Expand Down Expand Up @@ -33,15 +37,18 @@ runtime dependency, but its code ships inside the repo:

- `vendor/versionone-sdk/` holds the SDK's ESM build (`index.js`, which
imports nothing) and types (`index.d.ts`), plus `SOURCE.json` naming
the commit they came from. `lib/api.js` imports from there.
- `package.json` lists `@versionone/agility-sdk` under `devDependencies`, pinned
to a full commit, so the lockfile records exactly what was vendored.
the version they came from and each file's SHA-256. `lib/api.js`
imports from there.
- `package.json` lists `@versionone/agility-sdk` under `devDependencies`,
pinned to an exact published version (`1.0.0-alpha.0` today; before the
first publish it was a git commit), so the lockfile records exactly what
was vendored.
- To move the pin: change it in `package.json`, then
`npm install && npm run vendor:sdk`, and commit the copy.
`test/vendor.test.js` fails if the copy, `SOURCE.json` and the pin
disagree.
- Publishing the SDK to a registry (plan 001, *Decisions needed*) changes
only where the pin points; the copy stays.
- The SDK is on npmjs (plan 001, A6); that changed only where the pin
points. The copy stays, because gh never runs npm.

## Steps, one PR each, on branch `sdk-adoption`

Expand Down
21 changes: 13 additions & 8 deletions plans/003-adopt-sdk-k6i-agility-slack-bot.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# Plan 003: k6i-agility-slack-bot adopts `@versionone/agility-sdk` (Track B)

Brief for a session on `digital-ai/k6i-agility-slack-bot`. Start once the
SDK PR that adds this file has merged into `proposed_type_script_api_version`.
Source plan: `plans/001-sdk-adoption-campaign.md`, Track B. Work on
`bolt-migration` (branch `sdk-adoption` from it), never `main`.
Brief for a session on `digital-ai/k6i-agility-slack-bot`. Source plan:
`plans/001-sdk-adoption-campaign.md`, Track B. Work on `bolt-migration`,
never `main`.

**Status (2026-11-07): done.** S1–S4 (digital-ai/k6i-agility-slack-bot#21–#24)
and B1–B4 (#29, #30, #32, #34) merged; the bot installs
`@versionone/agility-sdk@1.0.0-alpha.0` from npmjs (#41). Its SDK requests
(group rows, a shared TypeCache, a registry release, number roots, Template)
are all answered. The rest of this brief is the record of how.

## Goal

Expand All @@ -20,15 +25,15 @@ hand-decoding and rest-1 write path go.
`findAssets` (rest-1 `find`/`findin`, `page` up to 200),
`fetchLocalizations` (loc-2), and `queryFor*` helpers built on
`lib/queries.js`. `test/v1-service.test.js` stubs global `fetch`.
- **S1–S4 are not done yet**: `jsconfig.json` still says `commonJS`/`es6`;
- **S1–S4 were not done yet** (then; all merged since): `jsconfig.json` still says `commonJS`/`es6`;
query bodies have no explicit page; `axios`, `botkit*`, `botbuilder-*` are
still dependencies and `lib/v1api.js` still exists. These come first.

## Dependency

No registry package yet. Pin a commit:
`"@versionone/agility-sdk": "github:versionone/VersionOne.SDK.JavaScript#<merge sha>"`.
The SDK's `prepare` script builds `dist` on install. The bot is ESM, so
`"@versionone/agility-sdk": "1.0.0-alpha.0"` from npmjs, an exact pin
(until the first publish it was a git commit, which needed `git` in the
image and wrote a `git+ssh` URL into the lockfile). The bot is ESM, so
`import { AgilityApiClient } from "@versionone/agility-sdk"`.

## Steps, one PR each
Expand Down
117 changes: 117 additions & 0 deletions plans/004-adopt-sdk-agility-rooms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Plan 004: agility-rooms adopts `@versionone/agility-sdk` (Track D)

Brief for a session on `digital-ai/agility-rooms`, a React/Vite SPA that
runs inside Agility (same-origin, cookie auth). Source plan:
`plans/001-sdk-adoption-campaign.md`, Track D. gh-v1 (plan 002) and the
slack bot (plan 003) have finished their adoptions; this is the last
consumer, and the slowest: a strangler that starts below the call sites so
nothing user-visible moves.

## Goal

Rooms talks to the Agility data endpoints (api/asset, query.v1, rest-1,
meta.v1, loc-2, attachments, embedded images) only through
`@versionone/agility-sdk`. Rows arrive translated, so its hand-decoding
goes. UI behaviour stays the same. Rooms' own routes (`api/*` reports,
tags, watch, rooms2config, LLM; `*.mvc` pages) are out of scope unless the
SDK already covers them.

## Where things stand (surveyed 2026-11-07 at `main` `0874590`, read-only)

Full survey: plan 001, *What the consumers do today*, the agility-rooms
re-survey paragraph. In short:

- **HTTP.** `src/utils/axios.tsx` builds the default instance (`baseURL`
the app root, `X-Requested-With`, cookie auth; on 401/403 an SSO popup
via `Account.mvc/Login`, then axios-auth-refresh replays). A response
interceptor turns api/asset `commandFailures` into a localized snackbar
and throws — but only when the URL is exactly `/api/asset`; 9 calls
written `api/asset` bypass it. `getAxiosInstance(...)` variants, a bare
`meta` instance and a plain `axios.create` in `src/navigation/routes.tsx`
skip some interceptors. 88 production files import axios.
- **Endpoints.** api/asset (111 call sites in 57 files), query.v1 (16),
rest-1 reads (4) **and writes** (5 `Data/{T}/{id}` attribute posts, 2
`?op=Copy`, plus `New/{T}?ctx=` templates), meta.v1, loc-2, `loc.v1`,
`config.v1`, attachments (`MultiValueRelations/Attachments.tsx`: inline
Base64 create, `attachment.img` download), embedded images
(`useImageUpload.ts` → `EmbeddedImage.mvc/Upload`).
- **Reads.** Positional `results[n]` with index constants
(`metaAssetStore/constants.ts`); some board and `ID=$Oids` reads are
unbounded (the SDK refuses an unpaged query).
- **Decoding.** 46 `"True"`/`"False"` comparisons; `NULL_OID` used 118
times; `massageApiAssetResponseObject` unwraps single relations. meta.v1
is loaded by `store/metaDefinition/useMetaDefinitionStore.ts`.
- **Tests.** Jest (222 files, module mocks, no MSW); the AI domain's
injected `IHttpClient` / `FakeHttpClient` is the cleanest seam.
Playwright (79 specs) runs against a live server.

## What the SDK offers rooms (1.0.0-alpha.0)

- `AgilityApiClient` with a pluggable `Transport` (D1 wraps rooms' axios),
or `createFetchTransport` with `credentials: "same-origin"` and
`onUnauthorized` (resend an idempotent request after re-auth; a write is
never resent), `signal` / `client.withSignal` for cancellation.
- `client.assets.query/queries/send` (rows translated through the schema;
a failed query throws; `CommandFailureError` carries each failure by
index for the snackbar), `client.queryV1`, `client.data` (rest-1 reads),
`client.localize`, `client.schema` / `TypeCache`, `client.resolve`,
`client.batch` (guarded sends, receipts, undo).
- `client.attachments` (list/page/info/get/add/put/remove/url; inline
Base64 up to 1 MB as rooms does, two-step above) and
`client.embeddedImages` (upload/url/normalize).
- Browser-safe: no `node:` imports, no Buffer. Install
`npm install @versionone/agility-sdk@1.0.0-alpha.0` (an exact pin; it is
an alpha).

## First: a decision for Jim

Rooms writes through rest-1 (attribute posts with `act`, `?op=Copy`) and
reads `New/{T}` templates, which plan 001 assumed no consumer needed.
Before D1, find out (live, on v1sdktesting) whether api/asset covers each:
an update for the attribute posts (likely), an `execute: "Copy"` or similar
for Copy, and whether `New/{T}` has an api/asset equivalent. Report what you
find to the SDK session and Jim, with a recommendation: move them to
api/asset, or have the SDK grow a narrow rest-1 write path.

## Steps, one PR each against `main`, from its own branch

1. **R1 Narrow the axios surface.** Route the axios importers through
`utils/bulkApiService.tsx` and a small set of helpers, so D1 swaps one
module. Fix the `api/asset` vs `/api/asset` interceptor gap on the way.
2. **D1 SDK under the existing axios.** A `Transport` that delegates to
rooms' axios instance (keeps the SSO refresh and the snackbar); point
`bulkApiService.tsx` at `client.assets.*`. Rows arrive translated, so
`getApiResults`' `IsReadOnly` patch goes.
3. **D2 Domain by domain.** Start with `src/domains/ai`, then retire the
string-boolean and `NULL_OID` decodes per feature; attachments onto
`client.attachments`, embedded images onto `client.embeddedImages`;
positional `results[n]` onto named or `queries` results; page every read.
4. **D3 Native transport.** Replace the axios-backed Transport with
`createFetchTransport({ credentials: "same-origin", onUnauthorized })`,
the SSO popup as the hook.
5. **D4 Schema convergence.** Evaluate replacing parts of
`src/metaAssetStore/` and `useMetaDefinitionStore` with the SDK's
`schema` / `TypeCache`.

## Rules

- Jest and the existing Playwright gates pass on every PR. No behaviour or
UI change unless a step says so.
- Live Agility calls go only to `https://www14.v1host.com/v1sdktesting`
(`V1_URL`, token in `V1_ACCESS_TOKEN`; Node's fetch needs
`NODE_USE_ENV_PROXY=1`). Writes are allowed there and nowhere else: name
assets `sdk-integration …` and delete them by exact OID. Every query is
small and explicitly paged. Point Playwright at nothing else.
- An EmbeddedImage cannot be deleted; upload one only when a test needs it.
- If the SDK lacks something, don't work around it in rooms: tell the SDK
session (`session_016NSWj9gL1oCubj5e2anVkb`, `send_message`) with what
you need and why. Don't request reviewers; Jim picks.

## Done when

- Rooms reaches the data endpoints only through the SDK; no file outside
the transport adapter imports axios for them.
- No `"True"`/`"False"` comparisons or `NULL_OID` checks on SDK rows remain.
- Attachments and embedded images go through the SDK.
- Plan 001's checklist line `D1–D4 agility-rooms` is ticked, with PR links
(tell the SDK session as each merges).
Loading