Skip to content

feat(tags): automate Semaphore taxonomy sync (#2184) - #2197

Merged
jung-thomas merged 1 commit into
DEVfrom
feat/2184-semaphore-auto-sync
Sep 8, 2026
Merged

feat(tags): automate Semaphore taxonomy sync (#2184)#2197
jung-thomas merged 1 commit into
DEVfrom
feat/2184-semaphore-auto-sync

Conversation

@jung-thomas

Copy link
Copy Markdown
Contributor

Closes #2184 (automation) — ships dark behind a default-OFF DB flag; awaits the Semaphore Service Account + semaphore-destination before it can be enabled. Service Account requested by email in parallel (draft in the issue comment).

What

Replaces the manual one-off Semaphore batch load with a weekly, flag-gated cron that pulls the SAPCore model from the Semaphore SES allterms REST API and upserts Tags keyed on semaphoreId (a renamed term updates in place instead of duplicating).

client.fetchAllTerms → mapper.mapAllTerms → applier.applyTerms
File Role
srv/lib/semaphore-sync/client.js SES REST client; resolves semaphore-destination; fails shut on any HTTP/parse/shape error
srv/lib/semaphore-sync/mapper.js pure SES term → tag row; titlePath + normalized name; config-driven class→flag mapping
srv/lib/semaphore-sync/applier.js upsert keyed on semaphoreId (distinct from the CSV importer); adopts legacy name matches; idempotent; dryRun
srv/jobs/semaphore-tag-sync-job.js orchestrator — flag-gated, config-driven, fail-shut; Sunday 04:47 UTC

Config (all DB-driven, no env vars)

  • SEMAPHORE_SYNC_ENABLED — DB feature flag (ImsConfig flag.semaphore.sync), default OFF, dev-only. Off → no-op.
  • ImsConfig semaphore.sync.{model,lang,filter,actualTagClasses,interestItemClasses,dryRun} tune a run without redeploy. dryRun defaults ON — first enabled runs only report the plan.
  • cds.requires.semaphore REST destination (semaphore-destination); .cdsrc.json mock for dev/unit. Token lives in the destination / Credential Store — never in source.

Safety

  • No schema changeTags already carries semaphoreId/isActualTag/isInterestItem (Tutorial and Tag API enhancements to eliminate SAGE sqlite caching dependencies #385 PR-1).
  • DEV-first (not prod-only): validate the mapping on DEV in dryRun before flipping dryRun off, then enable on PROD.
  • Fail-shut fetch — a transient SES outage/garbled payload throws before the applier runs, so the taxonomy is never wiped by an empty response.
  • Idempotent upsert; weekly cadence off the existing cron minute grid.

Open items (need the Service Account)

Confirm the live paths shape + the class URIs for actual-tag vs interest-item, and the destination auth flavour, then tune the class lists in dryRun on DEV. Mapper is deliberately conservative until then (every term an actual tag, none an interest item).

Tests

37 new unit tests (mapper / client / applier / job), all green. npx cds compile srv clean. CSV tag-import path untouched (existing applier tests still pass).

Design: docs/superpowers/specs/2026-09-08-2184-semaphore-auto-sync-design.md

Replaces the manual, one-off Semaphore batch load with a weekly,
DB-flag-gated cron that pulls the SAPCore model from the Semaphore SES
allterms REST API and upserts Tags keyed on semaphoreId.

Pipeline (all pure/injectable for test):
  client.fetchAllTerms -> mapper.mapAllTerms -> applier.applyTerms

- srv/lib/semaphore-sync/client.js  SES REST client; resolves
  semaphore-destination, fails shut on any HTTP/parse/shape error.
- srv/lib/semaphore-sync/mapper.js  pure SES term -> tag row; titlePath +
  normalized name; config-driven class->flag mapping.
- srv/lib/semaphore-sync/applier.js upsert keyed on semaphoreId (distinct
  from the CSV importer's name-keyed path); adopts legacy name matches;
  idempotent; dryRun.
- srv/jobs/semaphore-tag-sync-job.js orchestrator; flag-gated, config-driven,
  fail-shut. Registered Sunday 04:47 UTC.
- SEMAPHORE_SYNC_ENABLED DB feature flag (default OFF, dev-only); ImsConfig
  semaphore.sync.* tuning keys (dryRun defaults ON).
- cds.requires.semaphore REST destination + .cdsrc.json mock for dev/unit.

No schema change: Tags already carries semaphoreId/isActualTag/isInterestItem.
Ships dark; validate on DEV in dryRun before enabling. 37 new unit tests.

Design: docs/superpowers/specs/2026-09-08-2184-semaphore-auto-sync-design.md
@jung-thomas
jung-thomas marked this pull request as ready for review September 8, 2026 13:56
@jung-thomas
jung-thomas merged commit 44457b2 into DEV Sep 8, 2026
5 of 6 checks passed
@jung-thomas
jung-thomas deleted the feat/2184-semaphore-auto-sync branch September 8, 2026 13:56
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