@gallopsystems/agent-skills 1.12.0 → 1.13.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gallopsystems/agent-skills",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Gallop Systems agent skills, symlinked into .claude/skills (Claude Code) and .agents/skills (Codex) on install.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -10,7 +10,9 @@ doctl databases ca <db-id> # cluster CA certi
10
10
 
11
11
  - **The connection URI contains live credentials** — treat command output as a secret. Don't echo it into logs; pipe it directly to where it's needed.
12
12
  - **Check `Version`** and keep CI/local database versions in sync with production — a test suite running `postgres:15` against a pg-18 production cluster hides version-specific behavior.
13
- - Connections use port 25060 with `sslmode=require`. **TLS trap**: some clients (e.g. newer `pg-connection-string`) silently upgrade `require` to `verify-full`, which rejects DO's CA under the default trust store. Fix: supply the CA from `doctl databases ca <db-id>` explicitly, or configure ssl options in code rather than relying on the URI.
13
+ - Connections use port 25060 with `sslmode=require`. **TLS trap**: some clients (e.g. `pg-connection-string` as bundled with `pg` >= 8.16) silently treat `require` as `verify-full`, which rejects DO's self-signed CA under the default trust store (`SELF_SIGNED_CERT_IN_CHAIN`). Two non-obvious parts:
14
+ - **An ssl option set in code does NOT override an `sslmode` already in the URI.** Passing `ssl: { rejectUnauthorized: false }` while the connection string still ends in `?sslmode=require` keeps failing — the URI's `sslmode` wins. The fix has to land in the URI itself: drop/replace `sslmode`, append `uselibpqcompat=true` (restores libpq semantics: encrypt but don't verify), or supply the CA from `doctl databases ca <db-id>` explicitly.
15
+ - **When you can't edit the URI** — specifically, when you bind App Platform's generated `${db.DATABASE_URL}` straight into an env var in the app spec, it always carries `?sslmode=require` and you don't author the string — append the param to the bound value: `value: ${db.DATABASE_URL}&uselibpqcompat=true`. This only applies to that bound-pipethrough case; if you declare the connection-string env var yourself, just put the right params (or none) in from the start and an in-code ssl option is enough.
14
16
 
15
17
  ## Spaces
16
18
 
@@ -964,6 +964,53 @@ await db.schema.createIndex("idx_order_user_id").on("order").column("user_id").e
964
964
  .addColumn("price", sql`numeric(10, 2)`)
965
965
  ```
966
966
 
967
+ ### Migration Ordering Is Append-Only — Out-of-Order Timestamps Break Prod Deploys
968
+
969
+ Kysely's migrator enforces a **strict append-only ledger**: it refuses to run any
970
+ unexecuted migration whose timestamp sorts *before* the last-executed one
971
+ (throwing `Corrupted migrations: previously executed migration ... is missing`).
972
+ This bites when two branches each add a migration, and the one that merges *second*
973
+ carries the *earlier* timestamp:
974
+
975
+ ```
976
+ branch A merges first → 1700000200000_drop_thing (runs in prod)
977
+ branch B merges second → 1700000100000_add_table (timestamp is EARLIER)
978
+ → 1700000100001_add_column
979
+ ```
980
+
981
+ Prod has already recorded `...200000_drop_thing` as executed. On the next deploy
982
+ the `migrate` job sees two pending migrations that sort *before* it, throws
983
+ "Corrupted migrations", and **exits non-zero**. If migrations run as a pre-deploy
984
+ job (common on PaaS like DigitalOcean App Platform), the failed job fails the whole
985
+ deploy and the platform **auto-rolls-back to the previous image** — so prod silently
986
+ stays on stale code and every subsequent deploy fails the same way. A self-reinforcing
987
+ loop that looks like a deploy/token problem but is really a migration-ledger problem.
988
+
989
+ **Prevent it:** before merging a long-lived branch, check whether `main` has merged
990
+ any migration with a *later* timestamp than yours. If so, regenerate your migration's
991
+ timestamp so it sorts last (`migrate:make` again, or rename the file) **before it
992
+ merges** — only safe while the migration has not yet run in any shared DB. Never
993
+ re-stamp a migration that prod has already executed; that forces it to re-run.
994
+
995
+ **Fix it once prod is wedged:** reconcile the ledger so the executed set is a clean
996
+ *prefix* again, then let the normal strict migrate job run. Do **not** reach for
997
+ `allowUnorderedMigrations: true` — it works (kysely-ctl spreads the `migrations`
998
+ config into the `Migrator`), but it permanently weakens the ordering guard to paper
999
+ over one bad state. Instead, surgically remove the prematurely-recorded row from the
1000
+ migration ledger table (default `kysely_migration`):
1001
+
1002
+ ```sql
1003
+ -- prod ledger has the later-timestamp migration recorded, blocking the two earlier ones
1004
+ DELETE FROM kysely_migration WHERE name = '1700000200000_drop_thing';
1005
+ ```
1006
+
1007
+ Now `add_table → add_column → drop_thing` are all pending in true timestamp order, and
1008
+ the next deploy's strict migrate job applies them cleanly. This only works when the
1009
+ removed migration is **idempotent to re-run** (e.g. a `dropTable`/`dropColumn` written
1010
+ with `ifExists`, so re-applying it after the others is a safe no-op). Verify the
1011
+ ledger is a contiguous prefix after the DELETE, and prefer letting the deploy's own
1012
+ migrate job re-apply rather than running migrations from a laptop against prod.
1013
+
967
1014
  ## Type Generation
968
1015
 
969
1016
  Use `kysely-codegen` to generate types from your database: