kylon-cli 0.7.0 → 0.7.1-next.886
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -0
- package/dist/kylon-bundle.manifest.json +3 -3
- package/dist/kylon-bundle.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -432,6 +432,154 @@ trigger, not a required extra step after a production deploy. Do not run
|
|
|
432
432
|
Development installs `@next` and production installs `@latest`, so each
|
|
433
433
|
environment tracks its own release train.
|
|
434
434
|
|
|
435
|
+
#### Auto-update policy: dev is automatic, production is manual
|
|
436
|
+
|
|
437
|
+
The two `cli_auto_update` keys are maintained by deliberately different
|
|
438
|
+
mechanisms.
|
|
439
|
+
|
|
440
|
+
**`cli_auto_update/next` (dev) is reconciled automatically.** After a `develop`
|
|
441
|
+
prerelease is published, the `sync-dev-auto-update` job in
|
|
442
|
+
`.github/workflows/cli-publish.yml` sets the dev entry to the exact version it
|
|
443
|
+
just released, with `enabled: true` and `rolloutPercentage: 100`. A staged
|
|
444
|
+
rollout on dev would serve no purpose: the prerelease it points at is the only
|
|
445
|
+
build `@next` resolves to, so anyone tracking `next` is getting it regardless.
|
|
446
|
+
|
|
447
|
+
**Any CLI publish workflow run on `develop` converges the dev policy with the
|
|
448
|
+
real `@next`** — not only a run that published something. The job runs in one
|
|
449
|
+
of three modes, reported by the classifier as `sync_reason`:
|
|
450
|
+
|
|
451
|
+
| `sync_reason` | What happened | What the sync does |
|
|
452
|
+
| --- | --- | --- |
|
|
453
|
+
| `published` | this run released a prerelease | point the entry at it |
|
|
454
|
+
| `this_run_already_published` | a full re-run whose own version is already on npm | re-run the outstanding reconciliation |
|
|
455
|
+
| `ordinary_dedup_reconcile_current_next` | the bundle is identical to what `@next` already carries, so nothing was published | reconcile the entry toward the version `@next` already serves |
|
|
456
|
+
|
|
457
|
+
The third mode is the one to understand: **when there is no new bundle, the run
|
|
458
|
+
only bootstraps or repairs the config.** It publishes nothing, mints no
|
|
459
|
+
version, never touches a dist-tag, and writes no revision at all when the entry
|
|
460
|
+
is already correct. The version it converges on is never hypothetical — it is
|
|
461
|
+
read from the registry, must be an exact `X.Y.Z-next.N`, and is the build every
|
|
462
|
+
`@next` install is already getting.
|
|
463
|
+
|
|
464
|
+
That mode exists because the previous behaviour had a bootstrap gap. The merge
|
|
465
|
+
that shipped this sync (#6692) changed no CLI bundle, so content dedup skipped,
|
|
466
|
+
the sync job's condition rejected an ordinary skip, and the dev
|
|
467
|
+
`cli_auto_update/next` entry — which did not exist yet — was never created. An
|
|
468
|
+
identical bundle is a reason not to publish; it is not a reason to leave the
|
|
469
|
+
dev policy unreconciled.
|
|
470
|
+
|
|
471
|
+
The job verifies that `kylon-cli@next` actually resolves to the published
|
|
472
|
+
version before writing (retrying for registry read lag), and writes through
|
|
473
|
+
`upsertRuntimeConfigEntry`, so the same schema validation and
|
|
474
|
+
`runtime_config_entry_revisions` audit row apply as for an admin edit. The
|
|
475
|
+
revision's change reason records the published version, commit and workflow run.
|
|
476
|
+
|
|
477
|
+
The write is fenced with the entry version the job read, so it is a
|
|
478
|
+
compare-and-swap rather than a blind overwrite. That matters because
|
|
479
|
+
`cli-publish.yml` deliberately gives every run its own concurrency group: two
|
|
480
|
+
`develop` prereleases can be in flight at once and both reach this reconciler.
|
|
481
|
+
The rule is **latest wins** — the highest `X.Y.Z-next.N` the job can observe,
|
|
482
|
+
whether on the dist-tag or already stored in the entry, owns the target. An
|
|
483
|
+
older run that sees a newer one records a `superseded` no-op and succeeds; if
|
|
484
|
+
its fenced write loses the race instead, it re-reads both the dist-tag and the
|
|
485
|
+
row and re-decides against the state that won. An older release can therefore
|
|
486
|
+
never overwrite a newer one, and the entry never flaps between two concurrent
|
|
487
|
+
runs.
|
|
488
|
+
|
|
489
|
+
**The dist-tag is part of the same convergence, not an input to trust.**
|
|
490
|
+
`npm publish --tag next` moves the tag by wall clock, not by version, so two
|
|
491
|
+
overlapping runs that finish in reverse order leave the registry serving the
|
|
492
|
+
*older* build: run 811 publishes, then run 810 publishes and takes `@next`.
|
|
493
|
+
That is user-visible — `automatic-cli-update.ts` refuses to upgrade a machine
|
|
494
|
+
whose configured target differs from the dist-tag, logging `release_mismatch` —
|
|
495
|
+
so the two surfaces have to agree on one canonical winner: the newest
|
|
496
|
+
`X.Y.Z-next.N` any run can observe on its own release, on the tag, or in the
|
|
497
|
+
row.
|
|
498
|
+
|
|
499
|
+
Two mechanisms keep them agreeing:
|
|
500
|
+
|
|
501
|
+
- **The publish never moves `@next` backwards.** Immediately before publishing,
|
|
502
|
+
the run re-reads the dist-tag; if it already serves a strictly newer
|
|
503
|
+
prerelease, this run is already superseded and publishes under the
|
|
504
|
+
non-promoting `next-superseded` tag instead. The version is still published
|
|
505
|
+
and still installable by exact version — it just does not take the channel
|
|
506
|
+
head. A lookup that cannot be answered stops the run *before* the
|
|
507
|
+
irreversible step rather than publishing blind.
|
|
508
|
+
- **The sync repairs what is left.** A check-then-publish window remains, so if
|
|
509
|
+
the sync job finds `@next` behind the canonical winner it moves the tag
|
|
510
|
+
first — under a re-read fence, so an older run can never pull it back — and
|
|
511
|
+
only then writes the row. The row is never pointed at a version the dist-tag
|
|
512
|
+
does not serve, because that state upgrades nobody.
|
|
513
|
+
|
|
514
|
+
Moving a dist-tag needs a credential: npm's OIDC trusted publishing
|
|
515
|
+
authenticates `npm publish` and nothing else ([npm/cli#8547](https://github.com/npm/cli/issues/8547)).
|
|
516
|
+
The sync job reads an optional `NPM_DIST_TAG_TOKEN` from its `dev`
|
|
517
|
+
environment; when it is absent, the run fails with an `::error::` naming the
|
|
518
|
+
exact `npm dist-tag add kylon-cli@<winner> next` to run, instead of reporting
|
|
519
|
+
a convergence that did not happen.
|
|
520
|
+
|
|
521
|
+
Propagation is not part of the write's success condition. Committing the entry
|
|
522
|
+
also bumps a per-namespace revision counter and publishes a cache-invalidation
|
|
523
|
+
message on Redis, but no runtime reader polls that counter: services drop their
|
|
524
|
+
in-process runtime-config snapshot when the pub/sub message arrives, and
|
|
525
|
+
otherwise when the snapshot ages past its five-minute TTL. The publish is
|
|
526
|
+
bounded inside `invalidateRuntimeConfig`, so an unreachable Redis (the CI job
|
|
527
|
+
tunnels Postgres only) costs at most that five minutes of staleness and cannot
|
|
528
|
+
stall or fail an already-committed, already-audited write.
|
|
529
|
+
|
|
530
|
+
**`cli_auto_update/latest` (production) is never touched by automation.** The
|
|
531
|
+
stable target version and its rollout percentage are set by a human in the
|
|
532
|
+
admin runtime config, and ramping 0 → 100% is an explicit blast-radius
|
|
533
|
+
decision. Publishing a stable build to `@latest` does not enrol any computer in
|
|
534
|
+
updating to it; that remains a separate, deliberate step.
|
|
535
|
+
|
|
536
|
+
Two consequences worth knowing:
|
|
537
|
+
|
|
538
|
+
- **A dedup-skipped prerelease publishes nothing, but still reconciles.** When
|
|
539
|
+
content dedup decides the bundle is identical to what `@next` already has, no
|
|
540
|
+
version is published — and the sync job runs anyway, against the version
|
|
541
|
+
`@next` currently serves. Usually that is a no-op that writes no revision;
|
|
542
|
+
when the entry is missing or stale it is repaired on the spot. The sync never
|
|
543
|
+
fabricates a version for a release that did not happen: the only version it
|
|
544
|
+
can write is one it read off the registry.
|
|
545
|
+
|
|
546
|
+
A run with no release of its own also never moves the dist-tag. If it finds
|
|
547
|
+
the row pointing at something newer than `@next`, that winner belongs to the
|
|
548
|
+
run that published it, and that run converges both surfaces itself — so this
|
|
549
|
+
one records a `superseded` no-op instead of racing it. For the same reason a
|
|
550
|
+
registry it cannot read — or one serving a version this workflow does not
|
|
551
|
+
own — is a `::warning::` and a green run here, not a red one, and that holds
|
|
552
|
+
for **every** registry read the job takes: the read that picks the target and
|
|
553
|
+
the read the reconciliation itself takes just before it writes. Nothing was
|
|
554
|
+
published, nothing was written, nothing is at risk, and the next push
|
|
555
|
+
reconciles again. The downgrade stops there: a schema rejection, a lost CAS
|
|
556
|
+
fence or a database error still fails the job on this trigger too.
|
|
557
|
+
- **A failed sync fails the run, loudly, and re-running repairs it.** The npm
|
|
558
|
+
publish is irreversible, so the sync cannot be retried by re-publishing. If
|
|
559
|
+
the config write fails (or `@next` does not converge on the published
|
|
560
|
+
version), the workflow fails with an `::error::` naming the manual fix — a red
|
|
561
|
+
run, never a silent partial release.
|
|
562
|
+
|
|
563
|
+
"Re-run all jobs" is the supported repair. A re-run keeps the same run number
|
|
564
|
+
and therefore mints the same `X.Y.Z-next.<run>` version, which is already on
|
|
565
|
+
npm; the publish job detects exactly that case and marks the run
|
|
566
|
+
`reconcile_only`, so it publishes nothing but still runs the sync job. The
|
|
567
|
+
reconciliation is idempotent and reads the live dist-tag, so it either repairs
|
|
568
|
+
the stale entry, finds it already correct, or finds that a newer prerelease
|
|
569
|
+
has superseded this one and leaves the newer target alone. That stays distinct
|
|
570
|
+
from an ordinary content-dedup skip: both start a sync, but only the re-run
|
|
571
|
+
has a release of its own to reconcile, so only it may claim one. If the re-run
|
|
572
|
+
also fails, set `cli_auto_update/next` in the dev admin runtime config by
|
|
573
|
+
hand.
|
|
574
|
+
|
|
575
|
+
The classifier that tells those two skips apart is
|
|
576
|
+
`scripts/ci/cli-prerelease-npm.sh` — it emits `sync_reason`, and keeps
|
|
577
|
+
`reconcile_only` reserved for the re-run case — and every registry lookup in
|
|
578
|
+
it retries and fails closed. A transient `npm view` error is not evidence that a version
|
|
579
|
+
is unpublished; treating it as such is what would let a failed reconciliation
|
|
580
|
+
hide behind a green re-run. The dist-tag's own version is used as a second,
|
|
581
|
+
independent confirmation of the same fact.
|
|
582
|
+
|
|
435
583
|
## Usage
|
|
436
584
|
|
|
437
585
|
### Sign in for workspace commands
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.7.
|
|
3
|
-
"fingerprint": "
|
|
4
|
-
"source_commit": "
|
|
2
|
+
"version": "0.7.1-next.886",
|
|
3
|
+
"fingerprint": "eb8ae32e3145ae3090c81c8a5c17f5776fe9445e6dd047815eb8610424c87ee7",
|
|
4
|
+
"source_commit": "d291002061d8a9ec2fb14765e14c786783d8aa9c"
|
|
5
5
|
}
|