kalup 0.5.0 → 0.6.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.
@@ -1,4 +1,4 @@
1
- import { n as Prompter, r as Result, t as Handler } from "./context-0mrva_6H.mjs";
1
+ import { n as Prompter, r as Result, t as Handler } from "./context-BgFzBPj9.mjs";
2
2
  import { Command } from "@oclif/core";
3
3
  //#region src/host/commands.d.ts
4
4
  /**
package/dist/commands.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as TargetRebindCommand, a as CompareCommand, c as InitCommand, d as PlanCommand, f as PullCommand, g as StatusCommand, h as StateRebuildCommand, i as COMMANDS, l as IrCommand, m as SnapshotCommand, n as ApplyCommand, o as DocsCommand, p as RmCommand, r as BlueprintUpgradeCommand, s as FmtCommand, t as AddCommand, u as KalupCommand, v as ValidateCommand } from "./commands-D_Q8-jc5.mjs";
1
+ import { _ as TargetRebindCommand, a as CompareCommand, c as InitCommand, d as PlanCommand, f as PullCommand, g as StatusCommand, h as StateRebuildCommand, i as COMMANDS, l as IrCommand, m as SnapshotCommand, n as ApplyCommand, o as DocsCommand, p as RmCommand, r as BlueprintUpgradeCommand, s as FmtCommand, t as AddCommand, u as KalupCommand, v as ValidateCommand } from "./commands-DdogKJKg.mjs";
2
2
  export { AddCommand, ApplyCommand, BlueprintUpgradeCommand, COMMANDS, CompareCommand, DocsCommand, FmtCommand, InitCommand, IrCommand, KalupCommand, PlanCommand, PullCommand, RmCommand, SnapshotCommand, StateRebuildCommand, StatusCommand, TargetRebindCommand, ValidateCommand };
@@ -1271,6 +1271,16 @@ declare const issues: {
1271
1271
  output: string[];
1272
1272
  };
1273
1273
  };
1274
+ W_SETTLING: {
1275
+ exit: string;
1276
+ title: string;
1277
+ summary: string;
1278
+ when: string[];
1279
+ fix: string[];
1280
+ example: {
1281
+ output: string[];
1282
+ };
1283
+ };
1274
1284
  W_UNADDRESSABLE_NAME: {
1275
1285
  exit: string;
1276
1286
  title: string;
@@ -1,4 +1,4 @@
1
- import { A as sanitize, C as usageError, D as disclaimer, E as bin, O as escapeJson, S as versionText, T as KalupError, b as formats, k as exitCodes, u as KalupCommand, w as IssueError, x as version, y as PATH_MAX } from "./commands-D_Q8-jc5.mjs";
1
+ import { A as sanitize, C as usageError, D as disclaimer, E as bin, O as escapeJson, S as versionText, T as KalupError, b as formats, k as exitCodes, u as KalupCommand, w as IssueError, x as version, y as PATH_MAX } from "./commands-DdogKJKg.mjs";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
package/dist/host.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as ExitCode, n as Prompter, r as Result } from "./context-0mrva_6H.mjs";
1
+ import { i as ExitCode, n as Prompter, r as Result } from "./context-BgFzBPj9.mjs";
2
2
  //#region src/host/host.d.ts
3
3
  interface Out {
4
4
  write: (text: string) => unknown;
package/dist/host.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as isInteractive, r as run, t as execute } from "./host-BkBYlh_7.mjs";
1
+ import { n as isInteractive, r as run, t as execute } from "./host-BSYg3I66.mjs";
2
2
  export { execute, isInteractive, run };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as isInteractive, r as run } from "./host-BkBYlh_7.mjs";
2
+ import { n as isInteractive, r as run } from "./host-BSYg3I66.mjs";
3
3
  //#region src/index.ts
4
4
  process.exitCode = await run(process.argv.slice(2), {
5
5
  cwd: process.cwd(),
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://kalup.dev/schemas/ir-1.schema.json",
4
4
  "title": "Kalup IR, version 1",
5
- "description": "What a Kalup project's config files mean, derived by `kalup ir`, or what a portal holds, captured by `kalup snapshot` with an observation block. Change inside a version is additive and readers keep unknown fields, so the document and each resource accept fields this schema does not list. Below a resource everything is closed except `x` and the definition of a resource type this schema does not describe, which stays open until a later ir/1 release describes that type.",
5
+ "description": "What a Kalup project's config files mean, derived by `kalup ir`, or what a portal holds, captured by `kalup snapshot` with an observation block. Open for additions within ir/1 (docs/compatibility.md): the document, each resource and everything below it accept fields this schema does not list, and readers keep or ignore them; a later 1.x may add a resource type, and a reader reports an address of a type it does not handle as unknown. Closed, because a new value changes what a reader may conclude: generator, a $ref, a tombstone, the read statuses in coverage, lifecycle.options, and a target's drift and adopt.",
6
6
  "type": "object",
7
7
  "required": ["irVersion", "project", "generator", "resources", "targets", "tombstones"],
8
8
  "properties": {
@@ -277,23 +277,12 @@
277
277
  "$ref": "#/$defs/ref"
278
278
  },
279
279
  "type": {
280
- "enum": ["string", "number", "bool", "date", "datetime", "enumeration", "phone_number"]
280
+ "type": "string",
281
+ "description": "A value HubSpot defines; known values: string, number, bool, date, datetime, enumeration, phone_number. A later version may record one HubSpot adds."
281
282
  },
282
283
  "fieldType": {
283
- "enum": [
284
- "text",
285
- "textarea",
286
- "file",
287
- "phonenumber",
288
- "number",
289
- "booleancheckbox",
290
- "select",
291
- "radio",
292
- "checkbox",
293
- "date",
294
- "html",
295
- "calculation_equation"
296
- ]
284
+ "type": "string",
285
+ "description": "A value HubSpot defines; known values: text, textarea, file, phonenumber, number, booleancheckbox, select, radio, checkbox, date, html, calculation_equation. A later version may record one HubSpot adds."
297
286
  },
298
287
  "description": {
299
288
  "type": "string"
@@ -318,7 +307,8 @@
318
307
  "minimum": -1
319
308
  },
320
309
  "numberDisplayHint": {
321
- "enum": ["currency", "duration", "formatted", "percentage", "probability", "unformatted"]
310
+ "type": "string",
311
+ "description": "A value HubSpot defines; known values: currency, duration, formatted, percentage, probability, unformatted. A later version may record one HubSpot adds."
322
312
  },
323
313
  "showCurrencySymbol": {
324
314
  "type": "boolean"
@@ -327,22 +317,15 @@
327
317
  "type": "string"
328
318
  },
329
319
  "textDisplayHint": {
330
- "enum": [
331
- "domain_name",
332
- "email",
333
- "ip_address",
334
- "multi_line",
335
- "phone_number",
336
- "physical_address",
337
- "postal_code",
338
- "unformatted_single_line"
339
- ]
320
+ "type": "string",
321
+ "description": "A value HubSpot defines; known values: domain_name, email, ip_address, multi_line, phone_number, physical_address, postal_code, unformatted_single_line. A later version may record one HubSpot adds."
340
322
  },
341
323
  "calculationFormula": {
342
324
  "type": "string"
343
325
  },
344
326
  "dataSensitivity": {
345
- "enum": ["non_sensitive", "sensitive", "highly_sensitive"]
327
+ "type": "string",
328
+ "description": "A value HubSpot defines; known values: non_sensitive, sensitive, highly_sensitive. A later version may record one HubSpot adds."
346
329
  },
347
330
  "externalOptions": {
348
331
  "const": true
@@ -351,7 +334,7 @@
351
334
  "const": "OWNER"
352
335
  }
353
336
  },
354
- "additionalProperties": false
337
+ "additionalProperties": true
355
338
  },
356
339
  "option": {
357
340
  "description": "One enumeration option. Array index is display order. The app alias lives in binding.aliases, never here.",
@@ -371,7 +354,10 @@
371
354
  "type": "string"
372
355
  }
373
356
  },
374
- "additionalProperties": false
357
+ "additionalProperties": true,
358
+ "patternProperties": {
359
+ "^as$": false
360
+ }
375
361
  },
376
362
  "groupDefinition": {
377
363
  "type": "object",
@@ -381,7 +367,7 @@
381
367
  "type": "string"
382
368
  }
383
369
  },
384
- "additionalProperties": false
370
+ "additionalProperties": true
385
371
  },
386
372
  "objectDefinition": {
387
373
  "description": "A custom object schema. Its properties and groups are resources of their own.",
@@ -399,7 +385,7 @@
399
385
  "type": "string"
400
386
  }
401
387
  },
402
- "additionalProperties": false
388
+ "additionalProperties": true
403
389
  },
404
390
  "description": {
405
391
  "type": "string"
@@ -426,7 +412,7 @@
426
412
  }
427
413
  }
428
414
  },
429
- "additionalProperties": false
415
+ "additionalProperties": true
430
416
  },
431
417
  "pipelineDefinition": {
432
418
  "description": "A pipeline. Its stages are resources of their own; stages lists their IDs in display order.",
@@ -447,7 +433,7 @@
447
433
  }
448
434
  }
449
435
  },
450
- "additionalProperties": false
436
+ "additionalProperties": true
451
437
  },
452
438
  "stageDefinition": {
453
439
  "description": "A pipeline stage. Its metadata field depends on the object: probability on deals, ticketState on tickets, state on custom objects.",
@@ -463,13 +449,15 @@
463
449
  "maximum": 1
464
450
  },
465
451
  "ticketState": {
466
- "enum": ["OPEN", "CLOSED"]
452
+ "type": "string",
453
+ "description": "A value HubSpot defines; known values: OPEN, CLOSED. A later version may record one HubSpot adds."
467
454
  },
468
455
  "state": {
469
- "enum": ["OPEN", "CLOSED"]
456
+ "type": "string",
457
+ "description": "A value HubSpot defines; known values: OPEN, CLOSED. A later version may record one HubSpot adds."
470
458
  }
471
459
  },
472
- "additionalProperties": false
460
+ "additionalProperties": true
473
461
  },
474
462
  "associationDefinition": {
475
463
  "description": "An association label between two objects: label as the from object shows it, inverseLabel as the to object does. With neither, the plain association of a pair that has no HubSpot-defined one.",
@@ -482,7 +470,7 @@
482
470
  "type": "string"
483
471
  }
484
472
  },
485
- "additionalProperties": false
473
+ "additionalProperties": true
486
474
  },
487
475
  "binding": {
488
476
  "description": "App terms, filled in by the loader. key and codec for properties, export for objects.",
@@ -492,19 +480,9 @@
492
480
  "type": "string"
493
481
  },
494
482
  "codec": {
495
- "enum": [
496
- "string",
497
- "number",
498
- "boolean",
499
- "date",
500
- "datetime",
501
- "enum",
502
- "multiEnum",
503
- "stringArray",
504
- "json",
505
- "phoneNumber",
506
- "owner"
507
- ]
483
+ "type": "string",
484
+ "pattern": "^[a-zA-Z]+$",
485
+ "description": "The builder. Known: string, number, boolean, date, datetime, enum, multiEnum, stringArray, json, phoneNumber, owner. A later version may add a builder."
508
486
  },
509
487
  "aliases": {
510
488
  "type": "object",
@@ -525,7 +503,7 @@
525
503
  "type": "string"
526
504
  }
527
505
  },
528
- "additionalProperties": false
506
+ "additionalProperties": true
529
507
  },
530
508
  "lifecycle": {
531
509
  "type": "object",
@@ -550,7 +528,7 @@
550
528
  "type": "boolean"
551
529
  }
552
530
  },
553
- "additionalProperties": false
531
+ "additionalProperties": true
554
532
  },
555
533
  "provenance": {
556
534
  "description": "Merged from blueprints.lock.json in the folder of object files by the loader. Absent means authored by hand.",
@@ -573,7 +551,7 @@
573
551
  "type": "string"
574
552
  }
575
553
  },
576
- "additionalProperties": false
554
+ "additionalProperties": true
577
555
  },
578
556
  "target": {
579
557
  "description": "One named portal. Credentials never enter the IR.",
@@ -614,7 +592,10 @@
614
592
  "additionalProperties": false
615
593
  }
616
594
  },
617
- "additionalProperties": false
595
+ "additionalProperties": true,
596
+ "patternProperties": {
597
+ "^credentials$": false
598
+ }
618
599
  },
619
600
  "override": {
620
601
  "type": "object",
@@ -635,7 +616,7 @@
635
616
  }
636
617
  }
637
618
  },
638
- "additionalProperties": false
619
+ "additionalProperties": true
639
620
  },
640
621
  "observation": {
641
622
  "description": "What a snapshot read: the target, when, and how completely. A portal-frontend document requires it. observedAt is the one timestamp an ir/1 document carries.",
@@ -665,7 +646,7 @@
665
646
  "$ref": "#/$defs/coverage"
666
647
  }
667
648
  },
668
- "additionalProperties": false
649
+ "additionalProperties": true
669
650
  },
670
651
  "coverage": {
671
652
  "description": "What the read covered. Only a complete read proves that a resource is absent.",
@@ -695,52 +676,40 @@
695
676
  "const": "unknown"
696
677
  }
697
678
  },
698
- "notCaptured": {
699
- "description": "Documented response fields Kalup does not capture, per resource type.",
679
+ "settling": {
680
+ "description": "Resources the read cannot be trusted on yet, by address: apply wrote them minutes ago and HubSpot still serves an older copy (stale), or does not list one Kalup created (missing). Unknown until the time given, never absent or drifted.",
700
681
  "type": "object",
701
- "required": ["property", "group", "object"],
702
- "properties": {
703
- "property": {
704
- "type": "array",
705
- "items": {
706
- "type": "string"
707
- }
708
- },
709
- "group": {
710
- "type": "array",
711
- "items": {
712
- "type": "string"
713
- }
714
- },
715
- "object": {
716
- "type": "array",
717
- "items": {
718
- "type": "string"
719
- }
720
- },
721
- "pipeline": {
722
- "type": "array",
723
- "items": {
724
- "type": "string"
725
- }
726
- },
727
- "stage": {
728
- "type": "array",
729
- "items": {
682
+ "additionalProperties": {
683
+ "type": "object",
684
+ "required": ["reason", "until"],
685
+ "properties": {
686
+ "reason": {
687
+ "type": "string",
688
+ "description": "Why it settles. Known: stale, missing. A later version may add a reason."
689
+ },
690
+ "until": {
730
691
  "type": "string"
731
692
  }
732
693
  },
733
- "association": {
694
+ "additionalProperties": true
695
+ }
696
+ },
697
+ "notCaptured": {
698
+ "description": "Documented response fields Kalup drops, by resource type. A later version may add a type.",
699
+ "type": "object",
700
+ "required": ["property", "group", "object"],
701
+ "additionalProperties": false,
702
+ "patternProperties": {
703
+ "^[a-z]+$": {
734
704
  "type": "array",
735
705
  "items": {
736
706
  "type": "string"
737
707
  }
738
708
  }
739
- },
740
- "additionalProperties": false
709
+ }
741
710
  }
742
711
  },
743
- "additionalProperties": false
712
+ "additionalProperties": true
744
713
  },
745
714
  "objectCoverage": {
746
715
  "type": "object",
@@ -830,7 +799,7 @@
830
799
  }
831
800
  }
832
801
  },
833
- "additionalProperties": false
802
+ "additionalProperties": true
834
803
  },
835
804
  "excluded": {
836
805
  "description": "Addresses a skip override leaves out.",
@@ -861,7 +830,7 @@
861
830
  "type": "string"
862
831
  }
863
832
  },
864
- "additionalProperties": false
833
+ "additionalProperties": true
865
834
  },
866
835
  "associations": {
867
836
  "description": "The associations of the pairs this object is in, pair by pair: per other object, whether the pair was read, and the user-defined types of this direction no name reached; and the HubSpot type IDs of each association addressed from this object. Absent when no pair with this object is in scope.",
@@ -884,10 +853,10 @@
884
853
  }
885
854
  }
886
855
  },
887
- "additionalProperties": false
856
+ "additionalProperties": true
888
857
  }
889
858
  },
890
- "additionalProperties": false
859
+ "additionalProperties": true
891
860
  },
892
861
  "unsupportedProperty": {
893
862
  "description": "A present property Kalup does not write: no builder carries its type or fieldType, or HubSpot fills its options (owner or externalOptions). It is compared like any property but is not a resource.",
@@ -928,7 +897,7 @@
928
897
  "type": "string"
929
898
  }
930
899
  },
931
- "additionalProperties": false
900
+ "additionalProperties": true
932
901
  },
933
902
  "tombstone": {
934
903
  "description": "Written by `kalup rm`. destroy archives or deletes in the portal; release stops managing and leaves it.",
@@ -975,7 +944,7 @@
975
944
  }
976
945
  }
977
946
  },
978
- "additionalProperties": false
947
+ "additionalProperties": true
979
948
  }
980
949
  }
981
950
  }
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://kalup.dev/schemas/plan-1.schema.json",
4
4
  "title": "Kalup plan, version 1",
5
- "description": "What `kalup plan` would do to one target, with the context an approval binds to. Closed at every level, so a saved plan carries nothing this schema does not name, and a new field is a new format version.",
5
+ "description": "What `kalup plan` would do to one target, with the context an approval binds to. Closed at every level, apart from the free-form values in a step's desired and expect.values, so a saved plan carries nothing this schema does not name. A later 1.x may add fields, values and step types; an earlier 1.x refuses a plan that uses one, before any request (docs/compatibility.md).",
6
6
  "type": "object",
7
7
  "required": [
8
8
  "format",
@@ -97,7 +97,9 @@
97
97
  "description": "The objects whose mode on this target is takeover, sorted.",
98
98
  "type": "array",
99
99
  "uniqueItems": true,
100
- "items": { "type": "string" }
100
+ "items": {
101
+ "type": "string"
102
+ }
101
103
  }
102
104
  },
103
105
  "additionalProperties": false
@@ -476,8 +478,12 @@
476
478
  "type": "object",
477
479
  "required": ["address", "desired"],
478
480
  "properties": {
479
- "address": { "$ref": "#/$defs/address" },
480
- "desired": { "type": "object" }
481
+ "address": {
482
+ "$ref": "#/$defs/address"
483
+ },
484
+ "desired": {
485
+ "type": "object"
486
+ }
481
487
  },
482
488
  "additionalProperties": false
483
489
  }
@@ -485,7 +491,9 @@
485
491
  "stageLabels": {
486
492
  "description": "Display only, never approved: the label of each stage a pipeline step's stage order names, config's else the portal's, so the plan text shows labels and not IDs.",
487
493
  "type": "object",
488
- "additionalProperties": { "type": "string" }
494
+ "additionalProperties": {
495
+ "type": "string"
496
+ }
489
497
  },
490
498
  "ignoreChanges": {
491
499
  "description": "Create only: set on create, released after.",
@@ -783,7 +791,8 @@
783
791
  "override",
784
792
  "unsupported",
785
793
  "not-owned",
786
- "policy"
794
+ "policy",
795
+ "settling"
787
796
  ]
788
797
  },
789
798
  "detail": {
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://kalup.dev/schemas/state-1.schema.json",
4
4
  "title": "Kalup portal state, version 1",
5
- "description": ".kalup/state/portal-<portalId>.json. Describes one verified portal, not the code, and holds no target name. Covered by the compatibility policy (docs/compatibility.md): closed at every level apart from the free-form values in an entry's base and rewrites, so a new field is a new format version. No tokens, record data, unowned fields or unmanaged resources.",
5
+ "description": ".kalup/state/portal-<portalId>.json. Describes one verified portal, not the code, and holds no target name. Covered by the compatibility policy (docs/compatibility.md). Open for additions within kalup.state/1: a later 1.x may add top-level fields, resource entries of types this version does not plan, and fields on an entry. A reader keeps what it does not know: it never drops an entry of a type it does not handle or a top-level field it does not know, and it drops an entry's unknown fields only when it rewrites that entry. lastApply, an entry's attested and rewrites, and the base's option members stay closed. Kalup never writes a key, record data, unowned fields or unmanaged resources: its state writer refuses a file holding anything shaped like a key.",
6
6
  "type": "object",
7
7
  "required": ["format", "lineage", "serial", "portalId", "resources"],
8
8
  "properties": {
@@ -58,15 +58,16 @@
58
58
  "additionalProperties": false
59
59
  }
60
60
  },
61
- "additionalProperties": false,
61
+ "additionalProperties": true,
62
62
  "$defs": {
63
63
  "resourceState": {
64
64
  "type": "object",
65
65
  "required": ["origin", "id"],
66
66
  "properties": {
67
67
  "origin": {
68
- "description": "created and adopted are owned. pulled owns nothing: pull recorded the base of a resource no entry owned, and a plan still adopts it.",
69
- "enum": ["created", "adopted", "reference", "pulled"]
68
+ "description": "created and adopted are owned. pulled owns nothing: pull recorded the base of a resource no entry owned, and a plan still adopts it. reference owns nothing. Another value, from a later 1.x, owns nothing here.",
69
+ "type": "string",
70
+ "pattern": "^[a-z]+$"
70
71
  },
71
72
  "id": {
72
73
  "description": "The portal name the entry owns. It owns the resource only while this equals the name the address resolves to. null for runbook-only types.",
@@ -119,9 +120,20 @@
119
120
  "items": {
120
121
  "type": "integer"
121
122
  }
123
+ },
124
+ "written": {
125
+ "description": "The units apply wrote within the settling window before its last write, each with when it verified the write. For a few minutes HubSpot may serve an older copy, so a read that disagrees on such a unit is settling: unknown, never drift.",
126
+ "type": "object",
127
+ "additionalProperties": {
128
+ "type": "string"
129
+ }
130
+ },
131
+ "writtenAt": {
132
+ "description": "When apply last verified a write to the resource, whatever units it named. A read that does not show the resource within the settling window after it is settling: unknown, never absence.",
133
+ "type": "string"
122
134
  }
123
135
  },
124
- "additionalProperties": false
136
+ "additionalProperties": true
125
137
  },
126
138
  "base": {
127
139
  "description": "Per owned unit, the value config and portal last agreed on; possibly partial. Scalar units by field name. options: a map keyed by option value whose members hold the agreed label, hidden and description; a member with no fields means only its membership is agreed. optionsOrder: the agreed order of the members both sides held.",
package/docs/compare.md CHANGED
@@ -30,7 +30,7 @@ Every address present on either side, including properties Kalup does not write,
30
30
  - `differs`: `changes[]` lists options to add or remove; `held[]` lists units that differ, `diverged` since there is no base; `notes[]` lists options only `b` holds, kept because options are additive. When `b` is a portal side, the note names the pull command that brings the option into config. `pull` does not write a resource that names a portal name a `name` override shadows (`shadowed:<name>`), so on such a resource the note says to correct or remove that override instead. Nor does it bring in a property the files lack that is outside its object's pull scope, so there the note says to add the name to `objects.<object>.include`; a property the files define is always in scope. A snapshot does not record whether HubSpot defines a property, so on a reference `include` does not name, a snapshot's note says it may be outside the scope and gives the same advice.
31
31
  - `only-a` or `only-b`: on one side only.
32
32
  - `unmanaged`: only a portal side holds it and the other side is config. Listed and counted, never a difference: absence never deletes.
33
- - `unknown`: a side could not read its object, never read it, left out a property config names because its group's name holds whitespace (`W_UNADDRESSABLE_NAME`), or a target side has a `lookup` override, since this version manages no lookup resources. `reason` says which side and why.
33
+ - `unknown`: a side could not read its object, never read it, left out a property config names because its group's name holds whitespace (`W_UNADDRESSABLE_NAME`), is settling after an apply (plan.md, `W_SETTLING`; the fix says when to compare again, or for a snapshot side when to take a new one), may be a type HubSpot's schema read does not name yet, or a target side has a `lookup` override, since this version manages no lookup resources. A snapshot a later version of Kalup took may hold a type this version does not handle: against config its addresses are `unmanaged`, since config never names them; against a target or another snapshot they are `unknown`, and the fix says to compare with a later version. When such a snapshot's read was incomplete and its coverage records parts this version does not know, what it lacks is `unknown` too, never absent. `reason` says which side and why.
34
34
  - `excluded`: a `skip` override, or outside a side's read scope. Listed, not a difference.
35
35
 
36
36
  Config owns the fields it states, less `ignoreChanges`; a reference owns nothing, so only its presence compares. A portal side owns every field it captured; a field HubSpot left out takes its default, or `null` when it has none. With config as `b`, only the fields config states are compared. Options are compared when the config side states them, and always between two portal sides. Config managing what the portal holds as HubSpot-defined or calculated differs in the unit `managed`.
@@ -6,6 +6,8 @@
6
6
 
7
7
  The file named on the command line is missing, is not JSON, or does not match the `plan/1` schema. The message names the first place that fails. Apply also refuses a file whose steps contradict themselves: a change that writes a value the step's `desired` values do not hold, or a custom object archive whose `expect` does not count the properties, groups and pipelines it takes along. `kalup plan` never writes such a file.
8
8
 
9
+ A step of a resource type this version does not handle: a later version of Kalup made the plan. The message names the step and that version. Apply the plan with it, or a later one.
10
+
9
11
  ## Fix
10
12
 
11
13
  Save the plan again with `kalup plan --target <name> --out <file>`, review it, and apply that file. Never edit a plan file by hand.
@@ -0,0 +1,19 @@
1
+ # W_SETTLING
2
+
3
+ A warning from every command that reads a target: for some minutes after a write HubSpot may serve an older copy of what was written, so the read cannot be trusted on those resources yet. Exit stays 0, except as below.
4
+
5
+ ## When
6
+
7
+ After `apply` verifies a write, state records when it did and the units it wrote. For 5 minutes after that, a read that shows another value than apply verified on one of those units, or does not show the resource, is settling: HubSpot has been seen to serve a custom object schema's fields from before a PATCH, to leave a new custom object out of the schemas list, and to leave a new association's name out of its schema read for about 5 minutes. A label HubSpot lists that its schema read does not name yet settles the same way.
8
+
9
+ A settling resource is unknown, never absent, drifted or held: `plan` blocks its step with reason `settling` and never creates, deletes or writes it, a destroy tombstone on it included, `pull` keeps the file as it is, `compare` reports it `unknown` (`E_INCOMPLETE`, exit 1), and the read is incomplete. Takeover waits only while something on the object it removes from settles; `state rebuild --write` and `target rebind` only while something config names does. Its base in state never moves on such a read. A difference on a unit apply did not write is drift as ever.
10
+
11
+ ## Fix
12
+
13
+ Run the command again after the time the warning names. Nothing to change.
14
+
15
+ ## Example
16
+
17
+ ```
18
+ W_SETTLING: HubSpot still serves an older copy of 1 resource apply wrote minutes ago, so this read is not trusted on it until 2026-10-06T09:05:00.000Z: property:companies/billing_status (fix: run the command again after 2026-10-06T09:05:00.000Z) (docs: errors/W_SETTLING.md)
19
+ ```
package/docs/plan.md CHANGED
@@ -39,12 +39,14 @@ With `drift: 'overwrite'`, drift and conflicts are written labelled `reverts-ui-
39
39
 
40
40
  ## What blocks
41
41
 
42
- The first rule that matches: a `skip` override (no step, `coverage.excluded`); a `lookup` override; an unread object (`scope`, action `unknown`); a blocked parent or missing group (`dependency-blocked`); a property Kalup does not write (pull.md), whose fix makes it a `p.string` reference; for a create, a missing `name` override target, an archived property name (a create restores it; an archived group's name is created anew), or no limit room; HubSpot-defined or calculated, a `type` or `hasUniqueValue` difference, or read-only definition or options.
42
+ The first rule that matches: a `skip` override (no step, `coverage.excluded`); a `lookup` override; a resource settling after an apply (`settling`, action `unknown`, below); an unread object (`scope`, action `unknown`); a blocked parent or missing group (`dependency-blocked`); a property Kalup does not write (pull.md), whose fix makes it a `p.string` reference; for a create, a missing `name` override target, an archived property name (a create restores it; an archived group's name is created anew), or no limit room; HubSpot-defined or calculated, a `type` or `hasUniqueValue` difference, or read-only definition or options.
43
+
44
+ For 5 minutes after apply wrote a unit and read it back, HubSpot can still serve the copy from before the write. So within that window a read that shows another value than the base on a unit apply wrote, or leaves out a resource apply wrote, makes the resource settling, with what lies under a custom object left out that way (what is under a resource HubSpot serves an older copy of plans as ever): its step is `unknown`, blocked `settling`, its fix says when to plan again, and `W_SETTLING` warns. Nothing is held, created, deleted or written for it, a destroy tombstone's release or delete included, and the read is incomplete. A release tombstone still releases. A difference on a unit apply did not write is drift as ever, and after the window the read is believed again. State records what apply wrote and when in each entry's `written` and `writtenAt`. Takeover waits only while a property or group of the object it removes from settles.
43
45
 
44
46
  ## Custom objects
45
47
 
46
48
  - A new custom object is one `create` step. Apply creates it with its name, labels and description, then its groups and properties, then sets the display, required and searchable properties, since HubSpot refuses those fields until the properties they name exist. The step's notes say what HubSpot adds to a new object (its own properties, the group `<name>_information` and associations with activities) and which fields wait for the properties. When the object file lists `<name>_information`, as a pull writes it once a property sits in it, that group's create step notes that apply gives HubSpot's group config's label instead.
47
- - HubSpot's schemas list can show a custom object's values from before a write for some seconds after apply verified it, so a plan made right after such an apply can show the write as held drift. Plan again a minute later, and do not pull in that window: the pull would take the old values into config.
49
+ - HubSpot's schemas list can show a custom object's values from before a write for some seconds after apply verified it, and can leave out an object just created. A plan made then blocks the object `settling` (above), never holds the write as drift.
48
50
  - An update writes the whole schema in one request. A create and every update are `safe`: the display fields change forms and record views, not record values. A delete is `destructive`.
49
51
  - Blocked `unsupported`: a create whose name HubSpot holds archived, since the create would purge the archived object with its records and association labels (restore it in HubSpot and pull, purge it in HubSpot, or choose another name); a create whose name differs only in case from a custom object HubSpot holds, since HubSpot keeps names unique ignoring case; and a create or update whose display, required or searchable field names a property the portal does not hold and the plan does not create. When the plan blocks that property's create (a limit, for example), the object's step is blocked `dependency-blocked`, naming the property.
50
52
  - `kalup rm object:<name>` writes one tombstone that covers everything on the object: the plan has one delete step, which archives the object. Its title says how many of the object's properties, groups and pipelines go with it, and that HubSpot keeps no properties on an archived custom object; apply stops before any write when its own read finds more than the plan did. When the key cannot read the object's pipelines, the step is blocked `scope`, since the plan cannot count them. HubSpot refuses the archive while the object holds records. A tombstone on something under the object that asks otherwise than the object's is blocked with the reason. Takeover never archives a custom object.
@@ -69,7 +71,7 @@ The first rule that matches: a `skip` override (no step, `coverage.excluded`); a
69
71
  - An update sends both labels. Risk: a create and an update are `safe`; a delete is `destructive`, since records lose the association.
70
72
  - A plain association delete is blocked `unsupported` while a label of its pair remains, one HubSpot does not name yet included, unless the plan deletes that label first: HubSpot refuses it.
71
73
  - Blocked `unsupported` too: a plain association config gives a label, or a label config holds as a plain association (add an entry under another name instead); a create whose label the pair shows already from the same object, a plain create on a pair that holds a plain association, and a label create that fits HubSpot's cap only once a delete in this plan has run (deletes run last: apply the delete, then plan again).
72
- - An association the read did not find, on a pair whose lists hold a type HubSpot's schema read does not name yet, is blocked: it may be that type. Plan again in a few minutes.
74
+ - An association the read did not find, on a pair whose lists hold a type HubSpot's schema read does not name yet, is blocked `settling`: it may be that type. `W_SETTLING` warns, and the read is incomplete. Plan again in a few minutes.
73
75
  - HubSpot holds at most 50 labels per pair. Plan warns `W_LIMIT_HEADROOM` when its creates would pass the count Limits Tracking reports, and never blocks on it; HubSpot refuses the 51st with HTTP 437, which apply reports.
74
76
  - Blocked `scope`: an association of a pair whose labels were not read or answered 403.
75
77
  - Takeover never deletes an association. `notCovered` names association limits, which Kalup does not manage yet.
package/docs/pull.md CHANGED
@@ -64,6 +64,8 @@ Where state holds agreed values for a resource (its base), each unit is compared
64
64
 
65
65
  `--accept <address[#unit]>` (repeatable, `*` as in `--only`) takes the portal side of those units, as each kept line prints; one matching nothing is `E_ACCEPT_UNMATCHED`.
66
66
 
67
+ A resource settling after an apply (plan.md) is left as the file has it and gets no base, as for an address `--only` leaves out, with `W_SETTLING`: for minutes after a write HubSpot can serve the copy from before it, and pulling that copy would undo the change in config. `--check --exit-code` counts it as pending, exit 2.
68
+
67
69
  After the files are written, and only after a complete read, pull records in state the base of every unit the files and the portal agree on, for the addresses `--only` selects: under the portal lock (`E_LOCKED`) with the serial check, as apply saves. An owned entry keeps its origin; an address no entry owns gets origin `pulled`, which owns nothing: the next plan still adopts it, but compares against that base, so a later file edit is a `config-change`, not `diverged`. A field the files leave out because HubSpot holds its default (an empty description, `formField` off, an option with no description) is recorded at that default, so adding it to the file later is a `config-change` too. A unit that still differs keeps its base. `--check` and `--discover` record nothing and take no lock. A plan saved before the pull no longer applies (`E_STATE_CHANGED`). The pull that creates the state file prints its path. A new object file that gets more than 200 properties warns `W_LARGE_SCOPE`: the scope `init` writes takes every custom property.
68
70
 
69
71
  ## Target overrides
package/docs/snapshot.md CHANGED
@@ -31,7 +31,7 @@ A snapshot holds the scope and the captured fields, and is no backup of the port
31
31
 
32
32
  ## Incomplete reads
33
33
 
34
- The file is still written, with `complete: false`, the objects not read marked `unreadable` and `unaddressable` properties listed, and `W_INCOMPLETE` names the fix. The exit stays 0.
34
+ The file is still written, with `complete: false`, the objects not read marked `unreadable` and `unaddressable` properties listed, and `W_INCOMPLETE` names the fix. The exit stays 0. A resource settling after an apply (plan.md) is listed under `coverage.settling` with when its window ends, compare reports it unknown, and `W_INCOMPLETE` says to take a new snapshot after that time.
35
35
 
36
36
  ## Output
37
37