@lmzhen/dsh-evolution-core 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.
package/lib/index.js CHANGED
@@ -483,6 +483,12 @@ const DEFAULT_REVIEW_CONTEXT_MESSAGES = 60;
483
483
  const DEFAULT_REVIEW_MESSAGE_CHARS = 2e3;
484
484
  const DEFAULT_CURATOR_BOOT_GRACE_SECONDS = 10;
485
485
  const DEFAULT_CURATOR_REVIEW_MAX_TOKENS = 2048;
486
+ /** Threat-scan WINDOW SIZE (not a total cap — E-12: the whole text is scanned in
487
+ * overlapping windows, so content beyond this stays in scope). The coverage
488
+ * floor is `PATTERN_OVERLAP + 1` (V6-05). Single home for the core scanners'
489
+ * default parameter and clamp fallback, plus evolution-threat's Config default
490
+ * — the two packages previously wrote 65_536 independently (G0/S0.1). */
491
+ const DEFAULT_THREAT_MAX_SCAN_CHARS = 65536;
486
492
  /** 0.3.17 (S3.10, T-1): control-plane fields a model-facing write call may
487
493
  * never carry — single source for plan-validator, evolution-policy and the
488
494
  * threat scanner (they used to each hardcode the list).
@@ -3360,8 +3366,8 @@ const PATTERN_OVERLAP = 4096;
3360
3366
  * text is always scanned in overlapping windows, so content beyond 65,536
3361
3367
  * characters (skill files may run to 100,000) is no longer a blind zone.
3362
3368
  */
3363
- function scanThreats(text, scope = "strict", maxScanChars = 65536, options = NO_SCAN_OPTIONS) {
3364
- const windowSize = clampedNumber(maxScanChars, 65536, { min: 4097 });
3369
+ function scanThreats(text, scope = "strict", maxScanChars = DEFAULT_THREAT_MAX_SCAN_CHARS, options = NO_SCAN_OPTIONS) {
3370
+ const windowSize = clampedNumber(maxScanChars, DEFAULT_THREAT_MAX_SCAN_CHARS, { min: 4097 });
3365
3371
  const findings = [];
3366
3372
  const excluded = new Set(options.excludeLabels ?? []);
3367
3373
  if ((ZERO_WIDTH_CHARS.test(text) || ZWJ_OUTSIDE_EMOJI.test(text)) && !excluded.has("unicode_zero_width")) findings.push({
@@ -3415,7 +3421,7 @@ function scanThreats(text, scope = "strict", maxScanChars = 65536, options = NO_
3415
3421
  /** Blocking policy (P1-1, v19): a finding blocks unless it is explicitly
3416
3422
  * `report`-only. Pattern findings carry no severity and therefore block as
3417
3423
  * before. */
3418
- function evaluateThreat(text, scope = "strict", maxScanChars = 65536, options = NO_SCAN_OPTIONS) {
3424
+ function evaluateThreat(text, scope = "strict", maxScanChars = DEFAULT_THREAT_MAX_SCAN_CHARS, options = NO_SCAN_OPTIONS) {
3419
3425
  const findings = scanThreats(text, scope, maxScanChars, options);
3420
3426
  return {
3421
3427
  blocked: findings.some((finding) => finding.severity !== "report"),
@@ -3423,7 +3429,7 @@ function evaluateThreat(text, scope = "strict", maxScanChars = 65536, options =
3423
3429
  };
3424
3430
  }
3425
3431
  /** User-facing block message for memory writes. */
3426
- function scanMemoryThreats(text, maxScanChars = 65536, options = NO_SCAN_OPTIONS) {
3432
+ function scanMemoryThreats(text, maxScanChars = DEFAULT_THREAT_MAX_SCAN_CHARS, options = NO_SCAN_OPTIONS) {
3427
3433
  const { blocked, findings } = evaluateThreat(text, "strict", maxScanChars, options);
3428
3434
  if (!blocked) return null;
3429
3435
  const pattern = findings.find((f) => f.category !== "unicode_obfuscation");
@@ -3431,7 +3437,7 @@ function scanMemoryThreats(text, maxScanChars = 65536, options = NO_SCAN_OPTIONS
3431
3437
  return `Blocked by security scan: invisible or potentially malicious Unicode detected.${THREAT_EXEMPTION_HINT}`;
3432
3438
  }
3433
3439
  /** User-facing block message for skill content writes. */
3434
- function scanContentThreats(text, maxScanChars = 65536, options = NO_SCAN_OPTIONS) {
3440
+ function scanContentThreats(text, maxScanChars = DEFAULT_THREAT_MAX_SCAN_CHARS, options = NO_SCAN_OPTIONS) {
3435
3441
  const { blocked, findings } = evaluateThreat(text, "strict", maxScanChars, options);
3436
3442
  if (!blocked) return null;
3437
3443
  const pattern = findings.find((f) => f.category !== "unicode_obfuscation");
@@ -8832,6 +8838,1151 @@ function newSkillLibrary(options) {
8832
8838
  } : void 0, transact, [...threatExemptLabels ?? []]);
8833
8839
  }
8834
8840
  //#endregion
8841
+ //#region lib/types/params.js
8842
+ /**
8843
+ * Parameter id consolidation (G0/S0.2): one semantic gets ONE id.
8844
+ *
8845
+ * Nine places in this family carry the same value under two carriers: three use
8846
+ * the SAME name in two carriers (reviewMode, staleAfterDays, archiveAfterDays —
8847
+ * resolved by the existing policy-shadows-row rule) and six use DIFFERENT names.
8848
+ * This module owns the six: the policy/snapshot name is the canonical id, the
8849
+ * plugin-row name is a deprecated alias kept readable for one minor version
8850
+ * (0.6.x) and removable in 0.7.0.
8851
+ *
8852
+ * Reading stays compatible (a carrier still spelling the legacy name resolves),
8853
+ * writing is strict (the write path accepts canonical ids only, so no new
8854
+ * document is created under a deprecated name).
8855
+ * @module
8856
+ */
8857
+ /** Deprecated alias (plugin-row name) -> canonical id (policy/snapshot name). */
8858
+ const PARAM_ALIASES = Object.freeze({
8859
+ memoryInterval: "reviewMemoryInterval",
8860
+ skillInterval: "reviewSkillInterval",
8861
+ intervalHours: "curatorIntervalHours",
8862
+ maxSkillContentChars: "skillContentChars",
8863
+ memoryCharLimit: "memoryChars",
8864
+ userCharLimit: "userChars"
8865
+ });
8866
+ /** Canonical ids that have at least one deprecated alias, for read fallback. */
8867
+ const ALIASES_BY_CANONICAL = (() => {
8868
+ const index = {};
8869
+ for (const [alias, canonical] of Object.entries(PARAM_ALIASES)) (index[canonical] ??= []).push(alias);
8870
+ return index;
8871
+ })();
8872
+ /**
8873
+ * Resolve any parameter id to its canonical form.
8874
+ * @param id - canonical id or deprecated alias.
8875
+ * @returns the canonical id; ids without an alias pass through unchanged.
8876
+ */
8877
+ function resolveParamId(id) {
8878
+ return PARAM_ALIASES[id] ?? id;
8879
+ }
8880
+ /**
8881
+ * Whether an id is a deprecated alias.
8882
+ * @param id - parameter id to test.
8883
+ * @returns true when the id must be migrated to its canonical form.
8884
+ */
8885
+ function isDeprecatedParamId(id) {
8886
+ return PARAM_ALIASES[id] !== void 0;
8887
+ }
8888
+ /**
8889
+ * Guard for the write path: only canonical ids may be written.
8890
+ * @param id - parameter id a caller intends to write.
8891
+ * @returns the canonical id.
8892
+ * @throws {Error} when the id is a deprecated alias; the message names both ids.
8893
+ */
8894
+ function canonicalWriteId(id) {
8895
+ const canonical = PARAM_ALIASES[id];
8896
+ if (canonical === void 0) return id;
8897
+ throw new Error(`parameter id \`${id}\` is deprecated; write \`${canonical}\` instead`);
8898
+ }
8899
+ /**
8900
+ * Read a parameter from a carrier that may still spell the legacy name.
8901
+ * @param carrier - config/snapshot object to read from, or undefined.
8902
+ * @param id - canonical id (a deprecated alias is accepted and resolved first).
8903
+ * @returns the canonical value when present, else the alias value, else undefined.
8904
+ */
8905
+ function readParam(carrier, id) {
8906
+ if (carrier === void 0) return void 0;
8907
+ const record = carrier;
8908
+ const canonical = resolveParamId(id);
8909
+ if (record[canonical] !== void 0) return record[canonical];
8910
+ for (const alias of ALIASES_BY_CANONICAL[canonical] ?? []) if (record[alias] !== void 0) return record[alias];
8911
+ }
8912
+ /**
8913
+ * The parameter registry. G1/S1.1 seeds it with the review group (G-C); the
8914
+ * remaining groups land in S2.1. E3 = behaviour preference the user may change
8915
+ * (live); E2 = resource or identity knob that stays with the deployment.
8916
+ */
8917
+ const PARAM_EXPOSURE = Object.freeze([
8918
+ {
8919
+ id: "reviewSkillInterval",
8920
+ group: "review",
8921
+ tier: "E3",
8922
+ authority: "cordis",
8923
+ owner: "evolution-review",
8924
+ applies: "live",
8925
+ docAnchor: "PARAMETERS.md#review",
8926
+ summary: "Activity units between skill-review injections."
8927
+ },
8928
+ {
8929
+ id: "reviewMemoryInterval",
8930
+ group: "review",
8931
+ tier: "E3",
8932
+ authority: "cordis",
8933
+ owner: "evolution-review",
8934
+ applies: "live",
8935
+ docAnchor: "PARAMETERS.md#review",
8936
+ summary: "Activity units between memory-review injections."
8937
+ },
8938
+ {
8939
+ id: "skillReviewTrigger",
8940
+ group: "review",
8941
+ tier: "E3",
8942
+ authority: "cordis",
8943
+ owner: "evolution-review",
8944
+ applies: "live",
8945
+ docAnchor: "PARAMETERS.md#review",
8946
+ summary: "Which channel may inject a skill review (cadence, completion, both)."
8947
+ },
8948
+ {
8949
+ id: "skillReviewCompletionMinToolCalls",
8950
+ group: "review",
8951
+ tier: "E3",
8952
+ authority: "cordis",
8953
+ owner: "evolution-review",
8954
+ applies: "live",
8955
+ docAnchor: "PARAMETERS.md#review",
8956
+ summary: "Tool calls a task needs before the completion channel injects."
8957
+ },
8958
+ {
8959
+ id: "reviewEnabled",
8960
+ group: "review",
8961
+ tier: "E3",
8962
+ authority: "cordis",
8963
+ owner: "evolution-review",
8964
+ applies: "live",
8965
+ docAnchor: "PARAMETERS.md#review",
8966
+ summary: "Master switch for the review plugin."
8967
+ },
8968
+ {
8969
+ id: "reviewMode",
8970
+ group: "review",
8971
+ tier: "E3",
8972
+ authority: "cordis",
8973
+ owner: "evolution-review",
8974
+ applies: "live",
8975
+ docAnchor: "PARAMETERS.md#review",
8976
+ summary: "Run the review in the parent session (inject) or on a subagent."
8977
+ },
8978
+ {
8979
+ id: "reviewWakeInject",
8980
+ group: "review",
8981
+ tier: "E3",
8982
+ authority: "cordis",
8983
+ owner: "evolution-review",
8984
+ applies: "live",
8985
+ docAnchor: "PARAMETERS.md#review",
8986
+ summary: "Deliver the deferred review as a waking follow-up message."
8987
+ },
8988
+ {
8989
+ id: "reviewProvider",
8990
+ group: "review",
8991
+ tier: "E2",
8992
+ authority: "cordis",
8993
+ owner: "evolution-review",
8994
+ applies: "none",
8995
+ docAnchor: "PARAMETERS.md#review",
8996
+ summary: "LLM provider for review subagents (deployment identity)."
8997
+ },
8998
+ {
8999
+ id: "reviewTimeoutMs",
9000
+ group: "review",
9001
+ tier: "E2",
9002
+ authority: "cordis",
9003
+ owner: "evolution-review",
9004
+ applies: "none",
9005
+ docAnchor: "PARAMETERS.md#review",
9006
+ summary: "Bound on one review subagent run and its write leg."
9007
+ },
9008
+ {
9009
+ id: "reviewContextMessages",
9010
+ group: "review",
9011
+ tier: "E2",
9012
+ authority: "cordis",
9013
+ owner: "evolution-review",
9014
+ applies: "none",
9015
+ docAnchor: "PARAMETERS.md#review",
9016
+ summary: "Messages of context handed to a review subagent."
9017
+ },
9018
+ {
9019
+ id: "reviewMessageChars",
9020
+ group: "review",
9021
+ tier: "E2",
9022
+ authority: "cordis",
9023
+ owner: "evolution-review",
9024
+ applies: "none",
9025
+ docAnchor: "PARAMETERS.md#review",
9026
+ summary: "Per-message character budget of the review context."
9027
+ },
9028
+ {
9029
+ id: "reviewMaxDepth",
9030
+ group: "review",
9031
+ tier: "E2",
9032
+ authority: "cordis",
9033
+ owner: "evolution-review",
9034
+ applies: "none",
9035
+ docAnchor: "PARAMETERS.md#review",
9036
+ summary: "Absolute delegation-depth cap of the review subagent."
9037
+ },
9038
+ {
9039
+ id: "reviewToolAllow",
9040
+ group: "review",
9041
+ tier: "E2",
9042
+ authority: "cordis",
9043
+ owner: "evolution-review",
9044
+ applies: "none",
9045
+ docAnchor: "PARAMETERS.md#review",
9046
+ summary: "Tools the review subagent may use (safety surface)."
9047
+ },
9048
+ {
9049
+ id: "skillContentChars",
9050
+ group: "write-caps",
9051
+ tier: "E3",
9052
+ authority: "cordis",
9053
+ owner: "tool-skill-manage",
9054
+ applies: "live",
9055
+ docAnchor: "PARAMETERS.md#write-caps",
9056
+ summary: "Character cap on a SKILL.md body (tighten-only)."
9057
+ },
9058
+ {
9059
+ id: "maxSkillFileBytes",
9060
+ group: "write-caps",
9061
+ tier: "E3",
9062
+ authority: "cordis",
9063
+ owner: "tool-skill-manage",
9064
+ applies: "live",
9065
+ docAnchor: "PARAMETERS.md#write-caps",
9066
+ summary: "Byte cap on one support file (tighten-only)."
9067
+ },
9068
+ {
9069
+ id: "maxSkillNameLength",
9070
+ group: "write-caps",
9071
+ tier: "E3",
9072
+ authority: "cordis",
9073
+ owner: "tool-skill-manage",
9074
+ applies: "live",
9075
+ docAnchor: "PARAMETERS.md#write-caps",
9076
+ summary: "Character cap on a skill name (tighten-only)."
9077
+ },
9078
+ {
9079
+ id: "maxDescriptionLength",
9080
+ group: "write-caps",
9081
+ tier: "E3",
9082
+ authority: "cordis",
9083
+ owner: "tool-skill-manage",
9084
+ applies: "live",
9085
+ docAnchor: "PARAMETERS.md#write-caps",
9086
+ summary: "Character cap on a skill description (tighten-only)."
9087
+ },
9088
+ {
9089
+ id: "descriptionStrict",
9090
+ group: "write-caps",
9091
+ tier: "E3",
9092
+ authority: "cordis",
9093
+ owner: "tool-skill-manage",
9094
+ applies: "live",
9095
+ docAnchor: "PARAMETERS.md#write-caps",
9096
+ summary: "Refuse a description over the authoring bar instead of advising."
9097
+ },
9098
+ {
9099
+ id: "strictCrossSource",
9100
+ group: "write-caps",
9101
+ tier: "E3",
9102
+ authority: "cordis",
9103
+ owner: "tool-skill-manage",
9104
+ applies: "live",
9105
+ docAnchor: "PARAMETERS.md#write-caps",
9106
+ summary: "Refuse writes whose catalog entry resolves outside the family."
9107
+ },
9108
+ {
9109
+ id: "citationPolicy",
9110
+ group: "write-caps",
9111
+ tier: "E3",
9112
+ authority: "cordis",
9113
+ owner: "tool-skill-manage",
9114
+ applies: "live",
9115
+ docAnchor: "PARAMETERS.md#write-caps",
9116
+ summary: "Refuse a move that would leave a dangling reference, or verify it."
9117
+ },
9118
+ {
9119
+ id: "referenceRewrite",
9120
+ group: "write-caps",
9121
+ tier: "E2",
9122
+ authority: "cordis",
9123
+ owner: "tool-skill-manage",
9124
+ applies: "none",
9125
+ docAnchor: "PARAMETERS.md#write-caps",
9126
+ summary: "Re-home support files and rewrite references during a merge (plan or apply)."
9127
+ },
9128
+ {
9129
+ id: "archiveRetention",
9130
+ group: "write-caps",
9131
+ tier: "E2",
9132
+ authority: "cordis",
9133
+ owner: "tool-skill-manage",
9134
+ applies: "none",
9135
+ docAnchor: "PARAMETERS.md#write-caps",
9136
+ summary: "Report expired archives, or prune them."
9137
+ },
9138
+ {
9139
+ id: "supportFileCharPolicy",
9140
+ group: "write-caps",
9141
+ tier: "E3",
9142
+ authority: "cordis",
9143
+ owner: "tool-skill-manage",
9144
+ applies: "live",
9145
+ docAnchor: "PARAMETERS.md#write-caps",
9146
+ summary: "Warn about an oversize support file, or refuse the write."
9147
+ },
9148
+ {
9149
+ id: "memoryChars",
9150
+ group: "memory",
9151
+ tier: "E3",
9152
+ authority: "cordis",
9153
+ owner: "memory-files",
9154
+ applies: "live",
9155
+ docAnchor: "PARAMETERS.md#memory",
9156
+ summary: "Character budget the memory store enforces for MEMORY.md."
9157
+ },
9158
+ {
9159
+ id: "userChars",
9160
+ group: "memory",
9161
+ tier: "E3",
9162
+ authority: "cordis",
9163
+ owner: "memory-files",
9164
+ applies: "live",
9165
+ docAnchor: "PARAMETERS.md#memory",
9166
+ summary: "Character budget the memory store enforces for USER.md."
9167
+ },
9168
+ {
9169
+ id: "memoryEnabled",
9170
+ group: "memory",
9171
+ tier: "E2",
9172
+ authority: "cordis",
9173
+ owner: "tool-memory",
9174
+ applies: "none",
9175
+ docAnchor: "PARAMETERS.md#memory",
9176
+ summary: "Register the memory tool and its prompt section at all (deployment switch)."
9177
+ },
9178
+ {
9179
+ id: "entryPreviewChars",
9180
+ group: "memory",
9181
+ tier: "E3",
9182
+ authority: "cordis",
9183
+ owner: "tool-memory",
9184
+ applies: "live",
9185
+ docAnchor: "PARAMETERS.md#memory",
9186
+ summary: "Characters of one memory entry shown in a tool result preview."
9187
+ },
9188
+ {
9189
+ id: "addDatePrefix",
9190
+ group: "memory",
9191
+ tier: "E3",
9192
+ authority: "cordis",
9193
+ owner: "memory-files",
9194
+ applies: "live",
9195
+ docAnchor: "PARAMETERS.md#memory",
9196
+ summary: "Prefix stored memory entries with their date heading."
9197
+ },
9198
+ {
9199
+ id: "maxConsolidationFailures",
9200
+ group: "memory",
9201
+ tier: "E3",
9202
+ authority: "cordis",
9203
+ owner: "memory-files",
9204
+ applies: "live",
9205
+ docAnchor: "PARAMETERS.md#memory",
9206
+ summary: "Consolidation failures one turn tolerates before the tool gives up."
9207
+ },
9208
+ {
9209
+ id: "curatorIntervalHours",
9210
+ group: "curator",
9211
+ tier: "E3",
9212
+ authority: "cordis",
9213
+ owner: "evolution-curator",
9214
+ applies: "live",
9215
+ docAnchor: "PARAMETERS.md#curator",
9216
+ summary: "Minimum hours between deterministic curation passes."
9217
+ },
9218
+ {
9219
+ id: "staleAfterDays",
9220
+ group: "curator",
9221
+ tier: "E3",
9222
+ authority: "cordis",
9223
+ owner: "evolution-curator",
9224
+ applies: "live",
9225
+ docAnchor: "PARAMETERS.md#curator",
9226
+ summary: "Inactive days before a skill counts as stale."
9227
+ },
9228
+ {
9229
+ id: "archiveAfterDays",
9230
+ group: "curator",
9231
+ tier: "E3",
9232
+ authority: "cordis",
9233
+ owner: "evolution-curator",
9234
+ applies: "live",
9235
+ docAnchor: "PARAMETERS.md#curator",
9236
+ summary: "Inactive days before a stale skill is archived (must be >= staleAfterDays)."
9237
+ },
9238
+ {
9239
+ id: "qualityWarnStaleAfterDays",
9240
+ group: "curator",
9241
+ tier: "E3",
9242
+ authority: "cordis",
9243
+ owner: "evolution-curator",
9244
+ applies: "live",
9245
+ docAnchor: "PARAMETERS.md#curator",
9246
+ summary: "Age at which a low quality score starts warning."
9247
+ },
9248
+ {
9249
+ id: "minIdleHours",
9250
+ group: "curator",
9251
+ tier: "E3",
9252
+ authority: "cordis",
9253
+ owner: "evolution-curator",
9254
+ applies: "live",
9255
+ docAnchor: "PARAMETERS.md#curator",
9256
+ summary: "Idle hours required before an automatic curation pass runs."
9257
+ },
9258
+ {
9259
+ id: "minIdleFailOpen",
9260
+ group: "curator",
9261
+ tier: "E3",
9262
+ authority: "cordis",
9263
+ owner: "evolution-curator",
9264
+ applies: "live",
9265
+ docAnchor: "PARAMETERS.md#curator",
9266
+ summary: "Let the idle gate open when the activity probe is unavailable."
9267
+ },
9268
+ {
9269
+ id: "llmReview",
9270
+ group: "curator",
9271
+ tier: "E3",
9272
+ authority: "cordis",
9273
+ owner: "evolution-curator",
9274
+ applies: "live",
9275
+ docAnchor: "PARAMETERS.md#curator",
9276
+ summary: "Enable the LLM nomination pass on top of the deterministic lifecycle."
9277
+ },
9278
+ {
9279
+ id: "curatorReviewMaxTokens",
9280
+ group: "curator",
9281
+ tier: "E3",
9282
+ authority: "cordis",
9283
+ owner: "evolution-curator",
9284
+ applies: "live",
9285
+ docAnchor: "PARAMETERS.md#curator",
9286
+ summary: "Token budget of the curator LLM review."
9287
+ },
9288
+ {
9289
+ id: "curatorReviewTimeoutMs",
9290
+ group: "curator",
9291
+ tier: "E3",
9292
+ authority: "cordis",
9293
+ owner: "evolution-curator",
9294
+ applies: "live",
9295
+ docAnchor: "PARAMETERS.md#curator",
9296
+ summary: "Wall-clock bound of the curator LLM review."
9297
+ },
9298
+ {
9299
+ id: "healthSoftBodyChars",
9300
+ group: "curator",
9301
+ tier: "E3",
9302
+ authority: "cordis",
9303
+ owner: "evolution-curator",
9304
+ applies: "live",
9305
+ docAnchor: "PARAMETERS.md#curator",
9306
+ summary: "Body character line the health view judges against."
9307
+ },
9308
+ {
9309
+ id: "healthStampDensityPerKb",
9310
+ group: "curator",
9311
+ tier: "E3",
9312
+ authority: "cordis",
9313
+ owner: "evolution-curator",
9314
+ applies: "live",
9315
+ docAnchor: "PARAMETERS.md#curator",
9316
+ summary: "Stamp density per KB that flags log-like content in a body."
9317
+ },
9318
+ {
9319
+ id: "healthChurnMinPatches",
9320
+ group: "curator",
9321
+ tier: "E3",
9322
+ authority: "cordis",
9323
+ owner: "evolution-curator",
9324
+ applies: "live",
9325
+ docAnchor: "PARAMETERS.md#curator",
9326
+ summary: "Patches without a read that flag a write-ghost skill."
9327
+ },
9328
+ {
9329
+ id: "evolution-curator.enabled",
9330
+ group: "curator",
9331
+ tier: "E2",
9332
+ authority: "cordis",
9333
+ owner: "evolution-curator",
9334
+ applies: "none",
9335
+ docAnchor: "PARAMETERS.md#curator",
9336
+ summary: "Mount the curator plugin at all."
9337
+ },
9338
+ {
9339
+ id: "autoStart",
9340
+ group: "curator",
9341
+ tier: "E2",
9342
+ authority: "cordis",
9343
+ owner: "evolution-curator",
9344
+ applies: "none",
9345
+ docAnchor: "PARAMETERS.md#curator",
9346
+ summary: "Arm the hourly due-ness tick with the plugin."
9347
+ },
9348
+ {
9349
+ id: "bootGraceSeconds",
9350
+ group: "curator",
9351
+ tier: "E2",
9352
+ authority: "cordis",
9353
+ owner: "evolution-curator",
9354
+ applies: "none",
9355
+ docAnchor: "PARAMETERS.md#curator",
9356
+ summary: "Grace period before the first automatic pass after a restart."
9357
+ },
9358
+ {
9359
+ id: "curatorProvider",
9360
+ group: "curator",
9361
+ tier: "E2",
9362
+ authority: "cordis",
9363
+ owner: "evolution-curator",
9364
+ applies: "none",
9365
+ docAnchor: "PARAMETERS.md#curator",
9366
+ summary: "LLM provider for curator reviews (deployment identity)."
9367
+ },
9368
+ {
9369
+ id: "curatorModel",
9370
+ group: "curator",
9371
+ tier: "E2",
9372
+ authority: "cordis",
9373
+ owner: "evolution-curator",
9374
+ applies: "none",
9375
+ docAnchor: "PARAMETERS.md#curator",
9376
+ summary: "Model for curator reviews (deployment identity)."
9377
+ },
9378
+ {
9379
+ id: "protectedSkillNames",
9380
+ group: "library",
9381
+ tier: "E2",
9382
+ authority: "cordis",
9383
+ owner: "evolution-curator",
9384
+ applies: "none",
9385
+ docAnchor: "PARAMETERS.md#library",
9386
+ summary: "Skills the lifecycle never archives or rewrites."
9387
+ },
9388
+ {
9389
+ id: "manageUnmanaged",
9390
+ group: "library",
9391
+ tier: "E2",
9392
+ authority: "cordis",
9393
+ owner: "evolution-curator",
9394
+ applies: "none",
9395
+ docAnchor: "PARAMETERS.md#library",
9396
+ summary: "Let curation touch skills with no family metadata."
9397
+ },
9398
+ {
9399
+ id: "pruneBuiltins",
9400
+ group: "library",
9401
+ tier: "E2",
9402
+ authority: "cordis",
9403
+ owner: "evolution-curator",
9404
+ applies: "none",
9405
+ docAnchor: "PARAMETERS.md#library",
9406
+ summary: "Let curation nominate bundled skills for pruning."
9407
+ },
9408
+ {
9409
+ id: "referencedSkillNames",
9410
+ group: "library",
9411
+ tier: "E2",
9412
+ authority: "cordis",
9413
+ owner: "evolution-curator",
9414
+ applies: "none",
9415
+ docAnchor: "PARAMETERS.md#library",
9416
+ summary: "Names treated as referenced by external docs (never retired)."
9417
+ },
9418
+ {
9419
+ id: "includeSkillNames",
9420
+ group: "library",
9421
+ tier: "E2",
9422
+ authority: "cordis",
9423
+ owner: "evolution-skill-catalog",
9424
+ applies: "none",
9425
+ docAnchor: "PARAMETERS.md#library",
9426
+ summary: "Allow-list of skills the catalog exposes."
9427
+ },
9428
+ {
9429
+ id: "skill-catalog.excludeSkillNames",
9430
+ group: "library",
9431
+ tier: "E2",
9432
+ authority: "cordis",
9433
+ owner: "evolution-skill-catalog",
9434
+ applies: "none",
9435
+ docAnchor: "PARAMETERS.md#library",
9436
+ summary: "Deny-list of skills the catalog hides (row-local name; see the collision note)."
9437
+ },
9438
+ {
9439
+ id: "modelInvocable",
9440
+ group: "library",
9441
+ tier: "E2",
9442
+ authority: "cordis",
9443
+ owner: "evolution-skill-catalog",
9444
+ applies: "none",
9445
+ docAnchor: "PARAMETERS.md#library",
9446
+ summary: "Default for whether the model may invoke a catalog skill."
9447
+ },
9448
+ {
9449
+ id: "userInvocable",
9450
+ group: "library",
9451
+ tier: "E2",
9452
+ authority: "cordis",
9453
+ owner: "evolution-skill-catalog",
9454
+ applies: "none",
9455
+ docAnchor: "PARAMETERS.md#library",
9456
+ summary: "Default for whether the user may invoke a catalog skill."
9457
+ },
9458
+ {
9459
+ id: "maxItems",
9460
+ group: "library",
9461
+ tier: "E2",
9462
+ authority: "cordis",
9463
+ owner: "evolution-activity",
9464
+ applies: "none",
9465
+ docAnchor: "PARAMETERS.md#library",
9466
+ summary: "Entries kept in the activity sidecar window."
9467
+ },
9468
+ {
9469
+ id: "sessionScoped",
9470
+ group: "library",
9471
+ tier: "E2",
9472
+ authority: "cordis",
9473
+ owner: "evolution-review",
9474
+ applies: "none",
9475
+ docAnchor: "PARAMETERS.md#library",
9476
+ summary: "Act only on sessions carrying the family model tools."
9477
+ },
9478
+ {
9479
+ id: "skill-usage.sessionScoped",
9480
+ group: "library",
9481
+ tier: "E2",
9482
+ authority: "cordis",
9483
+ owner: "skill-usage",
9484
+ applies: "none",
9485
+ docAnchor: "PARAMETERS.md#library",
9486
+ summary: "Keep the usage sidecar scoped per session (row-local name)."
9487
+ },
9488
+ {
9489
+ id: "evolution-review.root",
9490
+ group: "deployment",
9491
+ tier: "E1",
9492
+ authority: "cordis",
9493
+ owner: "evolution-review",
9494
+ applies: "none",
9495
+ docAnchor: "PARAMETERS.md#deployment",
9496
+ summary: "Skill-tree root for review-created skills (empty = shared default)."
9497
+ },
9498
+ {
9499
+ id: "evolution-review.skillsRoot",
9500
+ group: "deployment",
9501
+ tier: "E1",
9502
+ authority: "cordis",
9503
+ owner: "evolution-review",
9504
+ applies: "none",
9505
+ docAnchor: "PARAMETERS.md#deployment",
9506
+ summary: "Retired alias of root; a value here fails the load (V27 G2.4)."
9507
+ },
9508
+ {
9509
+ id: "evolution-curator.root",
9510
+ group: "deployment",
9511
+ tier: "E1",
9512
+ authority: "cordis",
9513
+ owner: "evolution-curator",
9514
+ applies: "none",
9515
+ docAnchor: "PARAMETERS.md#deployment",
9516
+ summary: "Skill-tree root for curator scope, snapshot and archive."
9517
+ },
9518
+ {
9519
+ id: "evolution-commands.root",
9520
+ group: "deployment",
9521
+ tier: "E1",
9522
+ authority: "cordis",
9523
+ owner: "evolution-commands",
9524
+ applies: "none",
9525
+ docAnchor: "PARAMETERS.md#deployment",
9526
+ summary: "Skill-tree root the command surface writes through."
9527
+ },
9528
+ {
9529
+ id: "evolution-commands.skillsRoot",
9530
+ group: "deployment",
9531
+ tier: "E1",
9532
+ authority: "cordis",
9533
+ owner: "evolution-commands",
9534
+ applies: "none",
9535
+ docAnchor: "PARAMETERS.md#deployment",
9536
+ summary: "Retired alias of the commands root; a value here fails the load."
9537
+ },
9538
+ {
9539
+ id: "evolution-maintenance.root",
9540
+ group: "deployment",
9541
+ tier: "E1",
9542
+ authority: "cordis",
9543
+ owner: "evolution-maintenance",
9544
+ applies: "none",
9545
+ docAnchor: "PARAMETERS.md#deployment",
9546
+ summary: "Skill-tree root the maintenance probe scans."
9547
+ },
9548
+ {
9549
+ id: "evolution-maintenance.skillsRoot",
9550
+ group: "deployment",
9551
+ tier: "E1",
9552
+ authority: "cordis",
9553
+ owner: "evolution-maintenance",
9554
+ applies: "none",
9555
+ docAnchor: "PARAMETERS.md#deployment",
9556
+ summary: "Accepted skill-root spelling for the maintenance row."
9557
+ },
9558
+ {
9559
+ id: "evolution-skill-catalog.root",
9560
+ group: "deployment",
9561
+ tier: "E1",
9562
+ authority: "cordis",
9563
+ owner: "evolution-skill-catalog",
9564
+ applies: "none",
9565
+ docAnchor: "PARAMETERS.md#deployment",
9566
+ summary: "Skill-tree root the catalog lists."
9567
+ },
9568
+ {
9569
+ id: "evolution-learning-graph.root",
9570
+ group: "deployment",
9571
+ tier: "E1",
9572
+ authority: "cordis",
9573
+ owner: "evolution-learning-graph",
9574
+ applies: "none",
9575
+ docAnchor: "PARAMETERS.md#deployment",
9576
+ summary: "Skill-tree root the learning graph reads."
9577
+ },
9578
+ {
9579
+ id: "skill-usage.root",
9580
+ group: "deployment",
9581
+ tier: "E1",
9582
+ authority: "cordis",
9583
+ owner: "skill-usage",
9584
+ applies: "none",
9585
+ docAnchor: "PARAMETERS.md#deployment",
9586
+ summary: "Skill-tree root the usage store observes."
9587
+ },
9588
+ {
9589
+ id: "skill-usage.eventsHome",
9590
+ group: "deployment",
9591
+ tier: "E1",
9592
+ authority: "cordis",
9593
+ owner: "skill-usage",
9594
+ applies: "none",
9595
+ docAnchor: "PARAMETERS.md#deployment",
9596
+ summary: "Directory holding the family event log the usage store reads."
9597
+ },
9598
+ {
9599
+ id: "evolution-state-json.root",
9600
+ group: "deployment",
9601
+ tier: "E1",
9602
+ authority: "cordis",
9603
+ owner: "evolution-state-json",
9604
+ applies: "none",
9605
+ docAnchor: "PARAMETERS.md#deployment",
9606
+ summary: "Directory holding the JSON state store."
9607
+ },
9608
+ {
9609
+ id: "memory-files.root",
9610
+ group: "deployment",
9611
+ tier: "E1",
9612
+ authority: "cordis",
9613
+ owner: "memory-files",
9614
+ applies: "none",
9615
+ docAnchor: "PARAMETERS.md#deployment",
9616
+ summary: "Directory holding MEMORY.md and USER.md (empty = $DSH_HOME/memories)."
9617
+ },
9618
+ {
9619
+ id: "evolution-feedback.path",
9620
+ group: "deployment",
9621
+ tier: "E1",
9622
+ authority: "cordis",
9623
+ owner: "evolution-feedback",
9624
+ applies: "none",
9625
+ docAnchor: "PARAMETERS.md#deployment",
9626
+ summary: "Event log the feedback scorer reads (empty = family events file)."
9627
+ },
9628
+ {
9629
+ id: "evolution-state.provider",
9630
+ group: "deployment",
9631
+ tier: "E2",
9632
+ authority: "cordis",
9633
+ owner: "evolution-state",
9634
+ applies: "none",
9635
+ docAnchor: "PARAMETERS.md#deployment",
9636
+ summary: "Registered state-store provider name."
9637
+ },
9638
+ {
9639
+ id: "memory.provider",
9640
+ group: "deployment",
9641
+ tier: "E2",
9642
+ authority: "cordis",
9643
+ owner: "memory",
9644
+ applies: "none",
9645
+ docAnchor: "PARAMETERS.md#deployment",
9646
+ summary: "Registered memory provider name."
9647
+ },
9648
+ {
9649
+ id: "memory-files.providerName",
9650
+ group: "deployment",
9651
+ tier: "E2",
9652
+ authority: "cordis",
9653
+ owner: "memory-files",
9654
+ applies: "none",
9655
+ docAnchor: "PARAMETERS.md#deployment",
9656
+ summary: "Name this package registers as the memory provider."
9657
+ },
9658
+ {
9659
+ id: "memoryReviewModel",
9660
+ group: "deployment",
9661
+ tier: "E2",
9662
+ authority: "cordis",
9663
+ owner: "evolution-review",
9664
+ applies: "none",
9665
+ docAnchor: "PARAMETERS.md#deployment",
9666
+ summary: "Model for the memory review channel (deployment identity)."
9667
+ },
9668
+ {
9669
+ id: "skillReviewModel",
9670
+ group: "deployment",
9671
+ tier: "E2",
9672
+ authority: "cordis",
9673
+ owner: "evolution-review",
9674
+ applies: "none",
9675
+ docAnchor: "PARAMETERS.md#deployment",
9676
+ summary: "Model for the skill review channel (deployment identity)."
9677
+ },
9678
+ {
9679
+ id: "maxOpsPerPlan",
9680
+ group: "deployment",
9681
+ tier: "E2",
9682
+ authority: "cordis",
9683
+ owner: "evolution-plan-validator",
9684
+ applies: "none",
9685
+ docAnchor: "PARAMETERS.md#deployment",
9686
+ summary: "Operation cap one staged plan may carry."
9687
+ },
9688
+ {
9689
+ id: "substantiveMinToolCalls",
9690
+ group: "deployment",
9691
+ tier: "E2",
9692
+ authority: "cordis",
9693
+ owner: "evolution-review",
9694
+ applies: "none",
9695
+ docAnchor: "PARAMETERS.md#deployment",
9696
+ summary: "Tool calls that make a turn count as substantive."
9697
+ },
9698
+ {
9699
+ id: "substantiveMinUserChars",
9700
+ group: "deployment",
9701
+ tier: "E2",
9702
+ authority: "cordis",
9703
+ owner: "evolution-review",
9704
+ applies: "none",
9705
+ docAnchor: "PARAMETERS.md#deployment",
9706
+ summary: "User characters that make a turn count as substantive."
9707
+ },
9708
+ {
9709
+ id: "substantiveMinAgentChars",
9710
+ group: "deployment",
9711
+ tier: "E2",
9712
+ authority: "cordis",
9713
+ owner: "evolution-review",
9714
+ applies: "none",
9715
+ docAnchor: "PARAMETERS.md#deployment",
9716
+ summary: "Assistant characters that make a turn count as substantive."
9717
+ },
9718
+ {
9719
+ id: "threatExemptLabels",
9720
+ group: "deployment",
9721
+ tier: "E1",
9722
+ authority: "cordis",
9723
+ owner: "evolution-threat",
9724
+ applies: "none",
9725
+ docAnchor: "PARAMETERS.md#deployment",
9726
+ summary: "Threat labels the deployment declares benign (safety surface, never user-writable)."
9727
+ },
9728
+ {
9729
+ id: "evolution-threat.enabled",
9730
+ group: "deployment",
9731
+ tier: "E2",
9732
+ authority: "cordis",
9733
+ owner: "evolution-threat",
9734
+ applies: "none",
9735
+ docAnchor: "PARAMETERS.md#deployment",
9736
+ summary: "Mount the write-time threat guard at all."
9737
+ },
9738
+ {
9739
+ id: "evolution-threat.maxScanChars",
9740
+ group: "deployment",
9741
+ tier: "E2",
9742
+ authority: "cordis",
9743
+ owner: "evolution-threat",
9744
+ applies: "none",
9745
+ docAnchor: "PARAMETERS.md#deployment",
9746
+ summary: "Scan window size of the threat guard."
9747
+ },
9748
+ {
9749
+ id: "evolution-approval.enabled",
9750
+ group: "deployment",
9751
+ tier: "E2",
9752
+ authority: "cordis",
9753
+ owner: "evolution-approval",
9754
+ applies: "none",
9755
+ docAnchor: "PARAMETERS.md#deployment",
9756
+ summary: "Require approval before a staged write executes."
9757
+ },
9758
+ {
9759
+ id: "evolution-approval.stageForeground",
9760
+ group: "deployment",
9761
+ tier: "E2",
9762
+ authority: "cordis",
9763
+ owner: "evolution-approval",
9764
+ applies: "none",
9765
+ docAnchor: "PARAMETERS.md#deployment",
9766
+ summary: "Stage foreground agent writes for approval too."
9767
+ },
9768
+ {
9769
+ id: "qualityWarnThreshold",
9770
+ group: "deployment",
9771
+ tier: "E2",
9772
+ authority: "cordis",
9773
+ owner: "evolution-feedback",
9774
+ applies: "none",
9775
+ docAnchor: "PARAMETERS.md#deployment",
9776
+ summary: "Feedback score below which a skill carries a warning."
9777
+ },
9778
+ {
9779
+ id: "replay.maxPlans",
9780
+ group: "deployment",
9781
+ tier: "E2",
9782
+ authority: "cordis",
9783
+ owner: "evolution-replay",
9784
+ applies: "none",
9785
+ docAnchor: "PARAMETERS.md#deployment",
9786
+ summary: "Plans compared in one replay report."
9787
+ },
9788
+ {
9789
+ id: "replay.weights",
9790
+ group: "deployment",
9791
+ tier: "E2",
9792
+ authority: "cordis",
9793
+ owner: "evolution-replay",
9794
+ applies: "none",
9795
+ docAnchor: "PARAMETERS.md#deployment",
9796
+ summary: "Scoring weights of the replay comparison."
9797
+ },
9798
+ {
9799
+ id: "evolution-commands.maintainCooldownMs",
9800
+ group: "deployment",
9801
+ tier: "E2",
9802
+ authority: "cordis",
9803
+ owner: "evolution-commands",
9804
+ applies: "none",
9805
+ docAnchor: "PARAMETERS.md#deployment",
9806
+ summary: "Cooldown between maintenance runs from the command surface."
9807
+ },
9808
+ {
9809
+ id: "evolution-commands.maintainTimeoutMs",
9810
+ group: "deployment",
9811
+ tier: "E2",
9812
+ authority: "cordis",
9813
+ owner: "evolution-commands",
9814
+ applies: "none",
9815
+ docAnchor: "PARAMETERS.md#deployment",
9816
+ summary: "Timeout of one maintenance run started from the command surface."
9817
+ },
9818
+ {
9819
+ id: "skill-usage.supportReadToolNames",
9820
+ group: "deployment",
9821
+ tier: "E2",
9822
+ authority: "cordis",
9823
+ owner: "skill-usage",
9824
+ applies: "none",
9825
+ docAnchor: "PARAMETERS.md#deployment",
9826
+ summary: "Tool names whose file reads are attributed to support files."
9827
+ },
9828
+ {
9829
+ id: "install.mode",
9830
+ group: "deployment",
9831
+ tier: "E4",
9832
+ authority: "install",
9833
+ owner: "scripts",
9834
+ applies: "restart",
9835
+ docAnchor: "PARAMETERS.md#deployment",
9836
+ summary: "Install target plane (layered preset vs profile-root bundle)."
9837
+ },
9838
+ {
9839
+ id: "install.basePreset",
9840
+ group: "deployment",
9841
+ tier: "E4",
9842
+ authority: "install",
9843
+ owner: "scripts",
9844
+ applies: "restart",
9845
+ docAnchor: "PARAMETERS.md#deployment",
9846
+ summary: "Agent-preset base the layered install composes from (--base)."
9847
+ },
9848
+ {
9849
+ id: "install.home",
9850
+ group: "deployment",
9851
+ tier: "E4",
9852
+ authority: "install",
9853
+ owner: "scripts",
9854
+ applies: "restart",
9855
+ docAnchor: "PARAMETERS.md#deployment",
9856
+ summary: "Harness home the installer writes into (--home)."
9857
+ },
9858
+ {
9859
+ id: "install.presetRowOverrides",
9860
+ group: "deployment",
9861
+ tier: "E4",
9862
+ authority: "install",
9863
+ owner: "scripts",
9864
+ applies: "restart",
9865
+ docAnchor: "PARAMETERS.md#deployment",
9866
+ summary: "Preset row overrides the installer injects (row-overrides.json)."
9867
+ }
9868
+ ]);
9869
+ /** The settings namespace each OWNER PACKAGE registers (design §7.2).
9870
+ *
9871
+ * Keyed by owner rather than by group because a namespace has exactly one
9872
+ * registrant (the platform refuses a second registration of the same name),
9873
+ * while a group may span packages — group 'memory' is served by memory-files and
9874
+ * tool-memory, each owning its own section. A package without an entry has no
9875
+ * user layer (its knobs stay deployment-only). */
9876
+ const PARAM_NAMESPACES = Object.freeze({
9877
+ "evolution-review": "evolution-review",
9878
+ "memory-files": "evolution-memory",
9879
+ "tool-memory": "evolution-tool-memory",
9880
+ "evolution-curator": "evolution-curator",
9881
+ "tool-skill-manage": "evolution-skills"
9882
+ });
9883
+ /**
9884
+ * G3: expose one parameter section to the user layer.
9885
+ *
9886
+ * Precedence stays 'user > deployment > default': the caller keeps reading its
9887
+ * deployment carriers (policy snapshot, then the plugin row) and consults
9888
+ * {@link ParamOverrides.get} FIRST — an unset key returns undefined, so the
9889
+ * deployment value keeps winning and the family's shadowing rules survive.
9890
+ *
9891
+ * Failure posture: a provider without `describe` (or one whose describe throws)
9892
+ * leaves the user layer UNAVAILABLE and warns once — deployment values then
9893
+ * apply. Treating an unreadable user layer as 'no overrides' would silently
9894
+ * ignore a setting the user did write, so the warning names it.
9895
+ * @typeParam T - the section's value type.
9896
+ * @param provider - the platform settings provider, or undefined when absent.
9897
+ * @param namespace - namespace to register.
9898
+ * @param schema - schemastery schema the platform validates against.
9899
+ * @param base - composition base layer (the plugin row's values).
9900
+ * @param options - warning sink and the change hook.
9901
+ * @returns a reader bound to the namespace.
9902
+ */
9903
+ function paramSectionOverrides(provider, namespace, schema, base, options = {}) {
9904
+ if (provider === void 0) return unavailableOverrides(namespace, base);
9905
+ const scope = options.validate === void 0 ? provider.register(namespace, schema, {
9906
+ base,
9907
+ applies: "live"
9908
+ }) : provider.register(namespace, schema, {
9909
+ base,
9910
+ applies: "live",
9911
+ validate: options.validate
9912
+ });
9913
+ const warn = options.warn ?? (() => {});
9914
+ let user = readUserLayer(provider, namespace);
9915
+ if (user === void 0) warn("settings provider for " + namespace + " exposes no readable user layer; deployment values apply");
9916
+ scope.watch(() => {
9917
+ const next = readUserLayer(provider, namespace);
9918
+ if (next === void 0) {
9919
+ warn("settings provider for " + namespace + " stopped exposing its user layer; deployment values apply");
9920
+ user = void 0;
9921
+ options.onChange?.();
9922
+ return;
9923
+ }
9924
+ user = next;
9925
+ options.onChange?.();
9926
+ });
9927
+ return {
9928
+ namespace,
9929
+ get: (key) => user === void 0 ? void 0 : user[key],
9930
+ resolved: () => scope.get() ?? base
9931
+ };
9932
+ }
9933
+ /** The pre-provider reader: no user layer, deployment values only. */
9934
+ function unavailableOverrides(namespace, base) {
9935
+ return {
9936
+ namespace,
9937
+ get: () => void 0,
9938
+ resolved: () => base
9939
+ };
9940
+ }
9941
+ /** Read the raw user section, or undefined when the provider cannot report it. */
9942
+ function readUserLayer(provider, namespace) {
9943
+ if (provider.describe === void 0) return void 0;
9944
+ try {
9945
+ return provider.describe({ redactSecrets: false }).find((entry) => entry.ns === namespace)?.user ?? {};
9946
+ } catch {
9947
+ return;
9948
+ }
9949
+ }
9950
+ /**
9951
+ * Attach a parameter section through the optional settings service.
9952
+ * @typeParam T - the section's value type.
9953
+ * @param host - the plugin context (structurally typed).
9954
+ * @param namespace - namespace to register.
9955
+ * @param schema - schemastery schema the platform validates against.
9956
+ * @param base - composition base layer (the plugin row's values).
9957
+ * @param options - warning sink and the change hook.
9958
+ * @returns a reader that follows the provider when it appears.
9959
+ */
9960
+ function installParamSection(host, namespace, schema, base, options = {}) {
9961
+ let current = unavailableOverrides(namespace, base);
9962
+ host.inject(["settings"], (injected) => {
9963
+ const settings = injected.settings;
9964
+ current = paramSectionOverrides(settings, namespace, schema, base, options);
9965
+ options.onChange?.();
9966
+ });
9967
+ return {
9968
+ namespace,
9969
+ get: (key) => current.get(key),
9970
+ resolved: () => current.resolved()
9971
+ };
9972
+ }
9973
+ /**
9974
+ * Number-typed read over {@link readParam}: the family's tunables are numbers,
9975
+ * and a value of another type reads as absent so the caller's default applies
9976
+ * (the same outcome the numeric clamps produce for a malformed value).
9977
+ * @param carrier - config/snapshot object to read from, or undefined.
9978
+ * @param id - canonical id (a deprecated alias is accepted and resolved first).
9979
+ * @returns the resolved number, or undefined when absent or not a number.
9980
+ */
9981
+ function readNumberParam(carrier, id) {
9982
+ const value = readParam(carrier, id);
9983
+ return typeof value === "number" ? value : void 0;
9984
+ }
9985
+ //#endregion
8835
9986
  //#region lib/types/opt-in.js
8836
9987
  /**
8837
9988
  * Tool names only a session that mounted the family's MODEL rows can see.
@@ -8928,4 +10079,4 @@ function sessionAudited(ctx, sessionId, sessionScoped) {
8928
10079
  return false;
8929
10080
  }
8930
10081
  //#endregion
8931
- export { ALIVE_LOCK_TAKEOVER_MS, AUTHORING_DESCRIPTION_BAR, AUTHORING_SPLIT_LINE_CHARS, CITATION_SUPPORT_DIRS, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CONTENT_SPLIT_HINT, COST_ASCII_TOKEN_HIGH, COST_ASCII_TOKEN_LOW, COST_CJK_TOKEN_HIGH, COST_CJK_TOKEN_LOW, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEAD_LOCK_TAKEOVER_MS, DEDUP_MAX_PAIR_COMPARISONS, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_CITATION_POLICY, DEFAULT_CITATION_REF_BUDGET, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_SUPPORT_FILE_CHAR_POLICY, DEFAULT_SUPPORT_READ_TOOL_NAMES, DEFAULT_USER_CHAR_LIMIT, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, EMPTY_LOCK_TAKEOVER_MS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, HEALTH_STAMP_RE, HOOK_LINE_RE, INSTANCE_KEYS, KEEP_LINE_RE, LOCK_BODY_RE, LOCK_SUFFIX, LOCK_TEAR_TAKEOVER_MS, LOW_QUALITY_THRESHOLD, LostWriteLock, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MAX_SUPPORT_READ_PATHS, MAX_TIMER_DELAY_MS, MEMORY_GUIDANCE_SECTION_ORDER, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MUTATIONS_FILE_VERSION, MemoryStore, NATIVE_CALL_EVENT, NATIVE_RESULT_EVENT, PATTERN_OVERLAP, PLATFORM_ESTIMATE_CHARS_PER_TOKEN, POLICY_STAGE_DEFAULTS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, PTC_DISPATCH_EVENT, PTC_DISPATCH_START_EVENT, QUALITY_WEIGHTS, RESTRUCTURE_TARGET_RE, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UPSTREAM_LIMIT_CHARS_PER_TOKEN, advanceReview, allowRowCollisions, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyReferenceRewrite, assertDispatchPayload, assertSkillsRootAliasRetired, assessStructureHealth, authoringFeedback, bodyCost, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, claimInstance, clampedNumber, clearReviewChannel, collectReadSkillNames, composePresetComposition, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, countDispatches, createGateSet, daysSinceIso, decideTakeover, describeReferenceRewrite, duplicateHeadings, emptyRecord, evaluateThreat, eventsFile, evolutionEventPayloadIssue, evolutionHome, evolutionIoAdapter, evolutionRoot, findDriftSignal, foldCuratorFields, foldToolDispatches, foldTurn, frontmatterBlock, frontmatterCatalogInvalid, getRecord, idleDays, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isCommittedWarning, isFileShapedPath, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, latestActivityAt, lifecycleCandidate, listEventArchives, loadMutations, loadRowOverrides, loadSuppressedNames, loadUsage, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, neutralizePromptVariables, newSkillLibrary, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, observeEvent, overlongLines, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseLockBody, pendingSelfCleanup, persistedWriteSite, persistedWriteSites, planReferenceRewrite, planRehoming, policyStageLimits, probeAbsent, probeList, probeMtime, probePresent, probeReason, probeUnknown, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, recordMutation, redactSecrets, relatedSkillNames, releaseInstance, renameWithRetry, renderCuratorReportMarkdown, resolveCitations, resolveExecOrigins, resolveOrigins, resolveRootConfig, resolveSkillsRoot, retainEventArchives, retirementReport, reviewPrompt, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopedProbeReport, sessionAudited, sessionSeesFamilyTools, skillReadNameOf, skillsRoot, supportFileReadOf, suppressedFile, sweepReviewChannelSessions, tokenLineFor, transactIo, transactTaskGuard, unhookedSupportPointers, updateSuppressedNames, usageFile, usageObserved, validateFrontmatter, validateRestructureTarget, valueOr, verifyPromptBundle, writeDurableTmp, yamlPlainScalarNeedsQuotes };
10082
+ export { ALIVE_LOCK_TAKEOVER_MS, AUTHORING_DESCRIPTION_BAR, AUTHORING_SPLIT_LINE_CHARS, CITATION_SUPPORT_DIRS, COMBINED_REVIEW_PLAN_PROMPT, COMBINED_REVIEW_PROMPT, COMPLETION_SKILL_REVIEW_PROMPT, CONTENT_SPLIT_HINT, COST_ASCII_TOKEN_HIGH, COST_ASCII_TOKEN_LOW, COST_CJK_TOKEN_HIGH, COST_CJK_TOKEN_LOW, CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEAD_LOCK_TAKEOVER_MS, DEDUP_MAX_PAIR_COMPARISONS, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_ARCHIVE_RETENTION_POLICY, DEFAULT_CITATION_POLICY, DEFAULT_CITATION_REF_BUDGET, DEFAULT_CONSOLIDATION_FAILURES, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, DEFAULT_MIN_IDLE_HOURS, DEFAULT_MUTATION_CAP, DEFAULT_REFERENCE_REWRITE_POLICY, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_STALE_AFTER_DAYS, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_SUPPORT_FILE_CHAR_POLICY, DEFAULT_SUPPORT_READ_TOOL_NAMES, DEFAULT_THREAT_MAX_SCAN_CHARS, DEFAULT_USER_CHAR_LIMIT, DISPATCH_EVENT_TYPES, DRIFT_MAX_LINE_CHARS, DRIFT_SIGNALS_VERSION, DRIFT_SIGNAL_NOUNS, DSH_AUTHORING_STANDARDS, EMPTY_LOCK_TAKEOVER_MS, ENTRY_DELIMITER, EVENT_ARCHIVE_PREFIX, EVENT_LOG_RETAIN_ARCHIVES, EVENT_LOG_ROTATE_AT, EVENT_LOG_VERSION, EVOLUTION_WRITE_TOOLS, EvolutionGateSet, FAMILY_SESSION_TOOL_NAMES, FORBIDDEN_CONTROL_KEYS, HEALTH_STAMP_RE, HOOK_LINE_RE, INSTANCE_KEYS, KEEP_LINE_RE, LOCK_BODY_RE, LOCK_SUFFIX, LOCK_TEAR_TAKEOVER_MS, LOW_QUALITY_THRESHOLD, LostWriteLock, MAINTAIN_OUTPUT_INSTRUCTION, MAINTAIN_PROMPT, MAX_DESCRIPTION_LENGTH, MAX_RESTRUCTURE_MOVES, MAX_SKILL_CONTENT_CHARS, MAX_SKILL_FILE_BYTES, MAX_SKILL_NAME_LENGTH, MAX_SUPPORT_READ_PATHS, MAX_TIMER_DELAY_MS, MEMORY_GUIDANCE_SECTION_ORDER, MEMORY_REVIEW_PROMPT, MIN_STAMP_BODY_CHARS, MUTATIONS_FILE_VERSION, MemoryStore, NATIVE_CALL_EVENT, NATIVE_RESULT_EVENT, PARAM_ALIASES, PARAM_EXPOSURE, PARAM_NAMESPACES, PATTERN_OVERLAP, PLATFORM_ESTIMATE_CHARS_PER_TOKEN, POLICY_STAGE_DEFAULTS, PROMPT_BUNDLE, PROMPT_BUNDLE_ID, PROMPT_BUNDLE_VERSION, PROTECTED_BUILTIN_SKILLS, PTC_DISPATCH_EVENT, PTC_DISPATCH_START_EVENT, QUALITY_WEIGHTS, RESTRUCTURE_TARGET_RE, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SKILL_ACTION_REQUIRED_FIELDS, SKILL_NAME_RE, SKILL_REVIEW_PLAN_PROMPT, SKILL_REVIEW_PROMPT, SNAPSHOT_EXTRA_NAME_RE, SUPPORT_DIRS, SUPPRESSED_FILE_VERSION, SkillLibrary, THREAT_EXEMPTION_HINT, TOKEN_ASCII_WEIGHT, TOKEN_CJK_WEIGHT, ToolDispatchNormalizer, ToolDispatchPayloadError, UPSTREAM_LIMIT_CHARS_PER_TOKEN, advanceReview, allowRowCollisions, appendEvolutionEvent, applyCuratorLifecycleFields, applyCuratorMetaFields, applyReferenceRewrite, assertDispatchPayload, assertSkillsRootAliasRetired, assessStructureHealth, authoringFeedback, bodyCost, buildCuratorRunReport, buildLearnPrompt, bumpPatch, bumpSupportRead, bumpUse, bumpView, callingScope, canonicalWriteId, claimInstance, clampedNumber, clearReviewChannel, collectReadSkillNames, composePresetComposition, computeDedupGroups, computeDriftSignals, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, countDispatches, createGateSet, daysSinceIso, decideTakeover, describeReferenceRewrite, duplicateHeadings, emptyRecord, evaluateThreat, eventsFile, evolutionEventPayloadIssue, evolutionHome, evolutionIoAdapter, evolutionRoot, findDriftSignal, foldCuratorFields, foldToolDispatches, foldTurn, frontmatterBlock, frontmatterCatalogInvalid, getRecord, idleDays, installParamSection, instanceClaimKey, instanceClaimedWriteSites, instanceHolder, isAbsent, isCommittedWarning, isDeprecatedParamId, isFileShapedPath, isMissingPath, isPresent, isProcessAlive, isProgramToolName, isReviewChannelSession, isSkillReadToolName, isSkillToolName, isUnknown, latestActivityAt, lifecycleCandidate, listEventArchives, loadMutations, loadRowOverrides, loadSuppressedNames, loadUsage, makeSerialQueue, mapProbe, markAgentCreated, markReviewChannel, markerEntryName, memoryRoot, missingSupportPointers, mutateUsage, mutationsFile, narrowNameMatches, neutralizePromptVariables, newSkillLibrary, nodeEvolutionIo, normalizeFrontmatter, normalizeUsageRecord, observeEvent, overlongLines, paramSectionOverrides, parseCuratorNominations, parseEvolutionEvents, parseFrontmatter, parseLockBody, pendingSelfCleanup, persistedWriteSite, persistedWriteSites, planReferenceRewrite, planRehoming, policyStageLimits, probeAbsent, probeList, probeMtime, probePresent, probeReason, probeUnknown, readDispatchSignal, readEvolutionEvents, readEvolutionTimeline, readNumberParam, readParam, recordMutation, redactSecrets, relatedSkillNames, releaseInstance, renameWithRetry, renderCuratorReportMarkdown, resolveCitations, resolveExecOrigins, resolveOrigins, resolveParamId, resolveRootConfig, resolveSkillsRoot, retainEventArchives, retirementReport, reviewPrompt, saveSuppressedNames, saveUsage, scanBodyHooks, scanContentThreats, scanMemoryThreats, scanThreats, scopedProbeReport, sessionAudited, sessionSeesFamilyTools, skillReadNameOf, skillsRoot, supportFileReadOf, suppressedFile, sweepReviewChannelSessions, tokenLineFor, transactIo, transactTaskGuard, unhookedSupportPointers, updateSuppressedNames, usageFile, usageObserved, validateFrontmatter, validateRestructureTarget, valueOr, verifyPromptBundle, writeDurableTmp, yamlPlainScalarNeedsQuotes };