Skip to content

[cli] multi identifier preference record uploads#11

Open
bencmbrook wants to merge 16 commits intomainfrom
bencmbrook/migrate-cli-pr-444
Open

[cli] multi identifier preference record uploads#11
bencmbrook wants to merge 16 commits intomainfrom
bencmbrook/migrate-cli-pr-444

Conversation

@bencmbrook
Copy link
Copy Markdown
Member

@bencmbrook bencmbrook commented Mar 19, 2026

Migrated from @JonnavithulaGirish PR at transcend-io/cli#444

Summary

  • port the legacy CLI multi-identifier preference upload refactor into packages/cli, including consent configure-preference-upload, schema-backed uploads, worker orchestration, receipts state, and the upload transform pipeline
  • add the .cursor preference upload skill, move reconcile-preference-records into packages/cli/scripts, and regenerate the CLI README/schema artifacts in the monorepo layout
  • treat this as a major CLI change with a changeset because the upload-preferences workflow and flags now follow the new configuration-driven flow

Test plan

  • pnpm -F @transcend-io/cli genfiles
  • pnpm -F @transcend-io/cli typecheck
  • pnpm -F @transcend-io/cli build
  • pnpm -F @transcend-io/cli test
  • pnpm -F @transcend-io/cli check-exports
  • pnpm quality

Made with Cursor

Bring the legacy CLI preference-upload refactor into the monorepo, including the new configure flow, schema-backed parallel uploads, receipts state, the upload skill, and the reconcile helper script.

Made-with: Cursor
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 19, 2026

Open in StackBlitz

@transcend-io/cli

pnpm add https://pkg.pr.new/transcend-io/tools/@transcend-io/cli@11
yarn add https://pkg.pr.new/transcend-io/tools/@transcend-io/cli@11.tgz

@transcend-io/privacy-types

pnpm add https://pkg.pr.new/transcend-io/tools/@transcend-io/privacy-types@11
yarn add https://pkg.pr.new/transcend-io/tools/@transcend-io/privacy-types@11.tgz

@transcend-io/sdk

pnpm add https://pkg.pr.new/transcend-io/tools/@transcend-io/sdk@11
yarn add https://pkg.pr.new/transcend-io/tools/@transcend-io/sdk@11.tgz

@transcend-io/utils

pnpm add https://pkg.pr.new/transcend-io/tools/@transcend-io/utils@11
yarn add https://pkg.pr.new/transcend-io/tools/@transcend-io/utils@11.tgz

commit: 4e96a28

@bencmbrook bencmbrook changed the title Port multi-identifier preference uploads to monorepo CLI multi identifier preference record uploads Mar 19, 2026
@bencmbrook bencmbrook changed the title multi identifier preference record uploads [cli] multi identifier preference record uploads Mar 19, 2026
@bencmbrook
Copy link
Copy Markdown
Member Author

Relative to old transcend-io/cli PR #444, here’s the thorough migration summary.

Ported Or Adapted

Area Outcome In This PR Where It Landed Notes
Interactive schema/config command Added packages/cli/src/commands/consent/configure-preference-upload/command.ts, packages/cli/src/commands/consent/configure-preference-upload/impl.ts, packages/cli/src/commands/consent/routes.ts New consent configure-preference-upload command was ported and wired into the monorepo CLI. It scans all CSVs in a directory, discovers headers/unique values, and persists the mapping config.
upload-preferences CLI surface Major refactor ported packages/cli/src/commands/consent/upload-preferences/command.ts, packages/cli/src/commands/consent/upload-preferences/readme.ts The command now follows the new config-driven flow from the old PR. It picked up the expanded flag surface for schema/config, worker concurrency, chunking, retry behavior, and viewer mode.
Parent upload orchestration Rewritten to new worker model packages/cli/src/commands/consent/upload-preferences/impl.ts The old single-process upload path was replaced with the upstream parent/child worker orchestration. It now discovers files, auto-chunks oversized CSVs, ensures config exists, launches workers, aggregates receipts, and exports logs/artifacts.
Worker/task plumbing Added packages/cli/src/commands/consent/upload-preferences/buildTaskOptions.ts, packages/cli/src/commands/consent/upload-preferences/schemaState.ts, packages/cli/src/commands/consent/upload-preferences/worker.ts These files are the runtime glue for the new upload architecture: shared worker options, schema-state adapter, and the child worker loop.
Upload planning/execution split Added packages/cli/src/commands/consent/upload-preferences/upload/index.ts, packages/cli/src/commands/consent/upload-preferences/upload/buildInteractiveUploadPlan.ts, packages/cli/src/commands/consent/upload-preferences/upload/interactivePreferenceUploaderFromPlan.ts, packages/cli/src/commands/consent/upload-preferences/upload/types.ts The old PR split “figure out what to upload” from “actually upload it”; that split was preserved here.
CSV transform pipeline Added packages/cli/src/commands/consent/upload-preferences/upload/transform/buildPendingUpdates.ts, packages/cli/src/commands/consent/upload-preferences/upload/transform/transformCsv.ts, packages/cli/src/commands/consent/upload-preferences/upload/transform/index.ts This is the new transform layer that builds pending/safe/conflict/skipped updates from the configured schema and current store state.
Receipts state persistence Added packages/cli/src/commands/consent/upload-preferences/artifacts/receipts/receiptsState.ts, packages/cli/src/commands/consent/upload-preferences/artifacts/receipts/index.ts The new upload flow persists richer per-run state for pending, successful, failing, skipped, and conflicting records.
Receipts test coverage Added packages/cli/src/commands/consent/upload-preferences/artifacts/receipts/tests/receiptsState.test.ts The upstream file was effectively a placeholder; in the monorepo port I replaced it with a real test so Vitest would accept it and the behavior would be covered.
Preference-management state model Refactored packages/cli/src/lib/preference-management/codecs.ts The old single-column/inline-state model was replaced with the upstream schema model: FileFormatState plus RequestUploadReceipts. This supports multiple identifier columns, timestamp mapping, metadata mapping, ignored columns, and separated receipts state.
Identifier parsing Refactored packages/cli/src/lib/preference-management/parsePreferenceIdentifiersFromCsv.ts Ported to the new multi-identifier config flow instead of the older single identifierColumn model.
Timestamp/file-format parsing Renamed and expanded packages/cli/src/lib/preference-management/parsePreferenceFileFormatFromCsv.ts This replaces the old timestamp-only parser with the upstream broader file-format parser. It handles timestamp selection plus schema-backed non-interactive behavior.
Purpose/preference mapping Refactored packages/cli/src/lib/preference-management/parsePreferenceAndPurposeValuesFromCsv.ts Updated to work against the new persisted schema state instead of the older inline flow.
CSV-to-update parsing Refactored packages/cli/src/lib/preference-management/parsePreferenceManagementCsv.ts Ported to the new planning/receipts architecture.
Existing preference lookup Refactored packages/cli/src/lib/preference-management/getPreferencesForIdentifiers.ts Ported the newer batching/progress/error-splitting behavior needed by the refactored upload flow.
Preference-management exports Updated packages/cli/src/lib/preference-management/index.ts Exports now match the new architecture and drop the old interactive uploader export.
Supporting query/log tweaks Ported packages/cli/src/lib/graphql/gqls/RequestDataSilo.ts, packages/cli/src/lib/pooling/logRotation.ts, packages/cli/src/commands/consent/upload-preferences/upload/batchUploader.ts These were small supporting changes from the old PR that the new flow depended on or expected.
Reconcile helper Moved and adapted packages/cli/scripts/reconcile-preference-records.ts, packages/cli/package.json The old root script was moved into packages/cli/scripts and exposed as script:reconcile-preference-records. I also adapted imports and removed the hardcoded local CSV path so it runs from env vars instead.
Cursor skill Added .cursor/skills/preference-data-upload/SKILL.md Included per your request.
Generated docs/schema Regenerated instead of hand-editing packages/cli/README.md, packages/cli/schema/* I did not hand-port the old README diff. I regenerated monorepo-friendly docs and schema outputs via pnpm -F @transcend-io/cli genfiles.
Release semantics Marked as major .changeset/late-terms-apply.md Added a major changeset because this intentionally preserves the breaking behavior from the old PR.
Monorepo test/repo adaptation Added packages/cli/src/lib/tests/codebase.test.ts, packages/cli/src/lib/preference-management/tests/fetchConsentPreferencesChunked.test.ts, packages/cli/src/lib/preference-management/tests/getPreferencesForIdentifiers.test.ts I updated tests and repo-structure expectations so the migrated command layout and current Vitest behavior pass cleanly in this repo.

Replaced Or Dropped

Old Item / Behavior What Happened Replacement / Reason
packages/cli/src/lib/preference-management/uploadPreferenceManagementPreferencesInteractive.ts Dropped Replaced by the new upstream flow: configure-preference-upload + buildInteractiveUploadPlan + interactivePreferenceUploaderFromPlan + worker orchestration.
packages/cli/src/lib/preference-management/parsePreferenceTimestampsFromCsv.ts Dropped Replaced by packages/cli/src/lib/preference-management/parsePreferenceFileFormatFromCsv.ts, which handles timestamp choice as part of broader file-format/schema config.
Old inline single-file-style upload path Dropped The port preserves the upstream breaking change: upload-preferences is now directory/config driven rather than the older direct interactive uploader model.
Old single identifierColumn schema model Dropped Replaced by the new multi-identifier columnToIdentifier mapping in FileFormatState.
Old receipt/cache model embedded in preference metadata Dropped Replaced by standalone RequestUploadReceipts plus receiptsState.ts, which keeps schema/config state separate from upload receipts.
Upstream README.md patch Not ported verbatim Per your instruction, I regenerated packages/cli/README.md from monorepo sources instead of copying the old repo’s manual README diff.
Upstream transcend-yml-schema-v9.json file diff Not ported verbatim The monorepo stores generated schema artifacts under packages/cli/schema/, so I regenerated them instead of copying the old root-level schema file.
Upstream pnpm-lock.yaml diff Dropped Not needed as a direct port. This monorepo manages dependencies at the workspace level, and the migration didn’t require importing the old standalone lockfile changes.
Old root location src/reconcile-preference-records.ts Dropped from that location Moved to packages/cli/scripts/reconcile-preference-records.ts to match this repo’s package layout.
Hardcoded local path inside reconcile script Dropped Replaced with env-driven execution via INPUT_CSV, PARTITION, TRANSCEND_URL, TRANSCEND_API_KEY, and optional related vars.
Empty upstream receiptsState.test.ts placeholder Dropped as-is Replaced with a real test because empty Vitest files fail in this repo.

Net Effect

Summary Result
User-requested items omitted None
Standalone-repo artifacts copied verbatim Only where they fit monorepo patterns
Standalone-repo artifacts moved/regenerated/replaced README, schema JSON, reconcile script location, old interactive uploader, old timestamp parser
Breaking-change intent preserved Yes

bencmbrook and others added 11 commits March 20, 2026 16:55
Resolve conflicts from SDK extraction (PR #34) merging into
multi-identifier feature branch:
- Take HEAD's feature code for CLI preference-management files
- Restore HEAD's enhanced versions (FileFormatState, multi-identifier,
  split-on-validation in getPreferencesForIdentifiers)
- Fix imports: splitCsvToList from @transcend-io/utils, withPreferenceRetry
  and ConsentPreferenceResponse from @transcend-io/sdk
- Delete uploadPreferenceManagementPreferencesInteractive (replaced by pool)
- Take main's mise.lock and SDK getPreferencesForIdentifiers

Made-with: Cursor
Delete 6 CLI files that were duplicated in SDK after the merge:
- codecs.ts, getPreferenceMetadataFromRow.ts (identical)
- checkIfPendingPreferenceUpdatesAreNoOp.ts, checkIfPendingPreferenceUpdatesCauseConflict.ts,
  getPreferenceUpdatesFromRow.ts (only import path diffs)
- getPreferencesForIdentifiers.ts (ported enhanced split-on-validation
  logic into SDK version with Logger DI)

Move PreferenceUploadProgress type to SDK types.ts so SDK
getPreferencesForIdentifiers can use it.

Update all CLI consumers to import from @transcend-io/sdk directly.
SDK typecheck pass | CLI typecheck pass | 86 tests pass

Made-with: Cursor
UploadProgressSink interface:
- New packages/sdk/src/preference-upload/progress.ts with structured
  callbacks (onFileStart, onFileProgress, onFileComplete, onError,
  onJobComplete) for CLI receipts/dashboard, container progress.json,
  or agent events
- noopProgressSink for when reporting isn't needed

Upload core moved to SDK (packages/sdk/src/preference-upload/):
- batchUploader.ts — Logger DI, stripped colors
- loadReferenceData.ts — Logger DI, calls SDK fetchAll*
- buildPendingUpdates.ts — pure transforms using SDK codecs
- getPreferenceIdentifiersFromRow + NONE_PREFERENCE_MAP moved to
  SDK preference-management (pure functions, no CLI deps)

Pooling moved to SDK (packages/sdk/src/pooling/):
- runPool.ts — stripped colors, installInteractiveSwitcher now injectable
  callback (CLI passes it, container skips it)
- spawnWorkerProcess.ts — openLogWindows replaced with onLogFilesCreated
  callback
- types.ts, logRotation.ts, ensureLogFile.ts, safeGetLogPathsForSlot.ts

CLI rewired to import from @transcend-io/sdk for moved modules.

SDK typecheck ✓ | SDK build ✓ | CLI typecheck ✓ | 154 tests pass ✓
No colors in SDK ✓

Made-with: Cursor
Upload pipeline:
- Delete CLI batchUploader.ts, loadReferenceData.ts, buildPendingUpdates.ts,
  types.ts (all moved to SDK preference-upload/)
- Clean up upload/index.ts and transform/index.ts barrels
- Move loadReferenceData.test.ts to SDK package

Pooling:
- Delete CLI runPool.ts, types.ts, spawnWorkerProcess.ts, logRotation.ts,
  ensureLogFile.ts, safeGetLogPathsForSlot.ts (all moved to SDK pooling/)
- Update CLI pooling barrel to only export CLI-specific files
- Rewire 15+ consumer files to split imports: SDK items from @transcend-io/sdk,
  CLI items from CLI pooling barrel

Note: Some pooling tests need migration to SDK (mock targets reference
deleted local modules). This is a known follow-up.

SDK typecheck ✓ | CLI typecheck ✓

Made-with: Cursor
…ific

Move packages/sdk/src/pooling/ to packages/utils/src/pooling/ since
runPool, spawnWorkerProcess, logRotation, and types are generic
multi-process infrastructure (like chunkOneCsvFile, RateCounter) not
Transcend API-specific code.

- Fix RateCounter import to relative (now within same package)
- Add @transcend-io/type-utils dependency to utils package.json
- Update utils barrel, remove pooling from SDK barrel
- Update ~34 CLI consumer files: pooling imports from @transcend-io/utils

Utils typecheck ✓ | Utils build ✓ | SDK typecheck ✓ | CLI typecheck ✓

Made-with: Cursor
import {
CHILD_FLAG,
type PoolHooks,
runPool,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (err instanceof PoolCancelledError) {

Resolve conflicts by taking main's polished pooling versions.
Fix duplicate imports, add installInteractiveSwitcher + PoolCancelledError
to upload-preferences, add worker.ts as build entry point.

Made-with: Cursor
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