Skip to content

feat(semaphore-sync): two-tier tag sync + scheduler mislog fix - #2480

Merged
jung-thomas merged 1 commit into
DEVfrom
worktree-semaphore-two-tier-sync
Sep 22, 2026
Merged

jung-thomas merged 1 commit into
DEVfrom
worktree-semaphore-two-tier-sync

Conversation

@jung-thomas

@jung-thomas jung-thomas commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

What

Two-tier rework of the semaphore-tag-sync cron (#2184) so the weekly run adopts the existing tag corpus without importing all ~20k SES terms, and picks up genuinely new tags only under an explicit class allowlist. Plus a scheduler mislog fix (#2478).

Tier 1 — adopt-only (existing rows)

  • Match each SES term by semaphoreId, then by name (adopts legacy rows lacking a semaphoreId).
  • Backfill taxonomy fields (label/name/titlePath/semaphoreId) in place when they differ.
  • Never overwrite editorial flags (isActualTag/isInterestItem).

Tier 2 — gated intake (unmatched rows)

  • INSERT an unmatched term only when its SES class is in semaphore.sync.intakeClasses (case-insensitive, URI-leaf tolerant).
  • New rows land inert — flags forced false, awaiting editor curation.
  • Empty allowlist ⇒ intake OFF (adopt-only), the safe default until FILTER/classes are chosen from data.

Dry-run histogram

Dry-run summary now carries a pre-formatted classHistogram string (e.g. SoftwareProduct=1, IndustryCluster=1). formatJobSummary only renders scalar fields, so it's a string on purpose. This is the point of the first in-app dry run: read the real SES class distribution and choose semaphore.sync.filter / intakeClasses from it. dryRun still defaults TRUE.

Scheduler mislog fix (#2478)

A job fn that returns { ok:false } (rather than throwing) was recorded as SUCCESS — the "no new tags, but green" symptom. The chassis now inspects the return value: logs a FAILED PipelineLog row, records JobLastRun.lastErrorAt + message, and raises an alert.

Config (all ImsConfig, DB-driven — no env vars)

semaphore.sync.intakeClasses (new), .dryRun, .filter, .model, .lang, .actualTagClasses, .interestItemClasses

Tests

48 passing across 3 suites (semaphore-sync-applier, semaphore-tag-sync-job, admin-job-controls), including new coverage for the mislog branch (ok:falselastErrorAt set / FAILED log; generic message fallback; ok:true → SUCCESS) and the dry-run histogram + gated intake.

Not in this PR (tracked in #2479, Tom to drive)

Run an in-app dry run against prod SES → read histogram → decide server FILTER vs intakeClasses + which class(es) → set config in prod DB → validate with a second dry run → flip dryRun=false. Rotate the compromised API key.

Refs #2184, #2478

…e) + fix mislog

Rework the semaphore-tag-sync applier so a weekly run adopts the existing
tag corpus without importing all ~20k SES terms, and picks up genuinely
new tags only under an explicit class allowlist.

Tier 1 (adopt-only): match each SES term by semaphoreId, then by name.
Backfill taxonomy fields (label/name/titlePath/semaphoreId) in place when
they differ; NEVER overwrite editorial flags (isActualTag/isInterestItem).

Tier 2 (gated intake): INSERT an unmatched term only when its SES class is
in semaphore.sync.intakeClasses (case-insensitive, URI-leaf tolerant).
New rows land inert (flags forced false), awaiting editor curation. Empty
allowlist = intake OFF (adopt-only), the safe default.

Dry-run summary now carries a pre-formatted classHistogram string so the
real SES class distribution can be read from an in-app dry run and used to
choose semaphore.sync.filter / intakeClasses from data. dryRun defaults TRUE.

Also fixes a scheduler mislog: a job fn RETURNING { ok:false } (rather than
throwing) was recorded as SUCCESS. The chassis now inspects the return value,
logs a FAILED PipelineLog row, records JobLastRun.lastErrorAt, and raises an
alert. Covered by new admin-job-controls tests.

Config keys (all ImsConfig, DB-driven -- no env vars):
  semaphore.sync.intakeClasses (new), .dryRun, .filter, .model, .lang,
  .actualTagClasses, .interestItemClasses

Refs #2184, #2478
@jung-thomas
jung-thomas merged commit 7ab30d5 into DEV Sep 22, 2026
4 of 5 checks passed
@jung-thomas
jung-thomas deleted the worktree-semaphore-two-tier-sync branch September 22, 2026 21:23
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