@qmilab/lodestar-core 0.1.5 → 0.2.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.
Files changed (56) hide show
  1. package/dist/index.d.ts +6 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +12 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/schemas/action.d.ts +31 -13
  6. package/dist/schemas/action.d.ts.map +1 -1
  7. package/dist/schemas/action.js +20 -1
  8. package/dist/schemas/action.js.map +1 -1
  9. package/dist/schemas/approval.d.ts +271 -0
  10. package/dist/schemas/approval.d.ts.map +1 -0
  11. package/dist/schemas/approval.js +119 -0
  12. package/dist/schemas/approval.js.map +1 -0
  13. package/dist/schemas/belief.d.ts.map +1 -1
  14. package/dist/schemas/belief.js +7 -1
  15. package/dist/schemas/belief.js.map +1 -1
  16. package/dist/schemas/calibration.d.ts +977 -0
  17. package/dist/schemas/calibration.d.ts.map +1 -0
  18. package/dist/schemas/calibration.js +187 -0
  19. package/dist/schemas/calibration.js.map +1 -0
  20. package/dist/schemas/claim.d.ts.map +1 -1
  21. package/dist/schemas/claim.js +4 -2
  22. package/dist/schemas/claim.js.map +1 -1
  23. package/dist/schemas/common.d.ts.map +1 -1
  24. package/dist/schemas/common.js +11 -5
  25. package/dist/schemas/common.js.map +1 -1
  26. package/dist/schemas/policy.d.ts +768 -0
  27. package/dist/schemas/policy.d.ts.map +1 -0
  28. package/dist/schemas/policy.js +200 -0
  29. package/dist/schemas/policy.js.map +1 -0
  30. package/dist/schemas/probe-pack.d.ts +152 -0
  31. package/dist/schemas/probe-pack.d.ts.map +1 -0
  32. package/dist/schemas/probe-pack.js +140 -0
  33. package/dist/schemas/probe-pack.js.map +1 -0
  34. package/dist/schemas/reflection.d.ts +405 -0
  35. package/dist/schemas/reflection.d.ts.map +1 -0
  36. package/dist/schemas/reflection.js +154 -0
  37. package/dist/schemas/reflection.js.map +1 -0
  38. package/dist/schemas/revision.d.ts.map +1 -1
  39. package/dist/schemas/revision.js.map +1 -1
  40. package/dist/schemas/sentinel.d.ts +134 -0
  41. package/dist/schemas/sentinel.d.ts.map +1 -0
  42. package/dist/schemas/sentinel.js +97 -0
  43. package/dist/schemas/sentinel.js.map +1 -0
  44. package/package.json +2 -7
  45. package/src/index.ts +18 -0
  46. package/src/schemas/action.ts +20 -1
  47. package/src/schemas/approval.ts +136 -0
  48. package/src/schemas/belief.ts +7 -1
  49. package/src/schemas/calibration.ts +212 -0
  50. package/src/schemas/claim.ts +15 -8
  51. package/src/schemas/common.ts +16 -10
  52. package/src/schemas/policy.ts +231 -0
  53. package/src/schemas/probe-pack.ts +169 -0
  54. package/src/schemas/reflection.ts +166 -0
  55. package/src/schemas/revision.ts +7 -5
  56. package/src/schemas/sentinel.ts +104 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/schemas/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAUvB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,kDAAgD,CAAA;AAC/E,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAE7D;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB5B,CAAA;AACF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAE3D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWlC,CAAA;AACF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAA;AAEvE;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIpC,CAAA;AACF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAE3E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoBzB,CAAA;AACJ,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAEzD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2CrB,CAAA;AACJ,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA"}
@@ -0,0 +1,200 @@
1
+ import { z } from "zod";
2
+ import { BlastRadiusSchema, DataSensitivityForActionSchema, ReversibilitySchema, TrustLevelSchema, } from "./action.js";
3
+ import { SignatureSchema } from "./actor.js";
4
+ import { ResourceScopeSchema, SensitivitySchema } from "./common.js";
5
+ /**
6
+ * Action policy — the wire format for what actions may touch the world.
7
+ *
8
+ * Design lock: `docs/architecture/policy-kernel.md`. The short version:
9
+ *
10
+ * - Policy is a *declarative document*, not a function. Today's enforcement
11
+ * is an opaque `PolicyGate` closure (the `autoApprovePolicy` preset). The
12
+ * Policy Kernel compiles a `Policy` document into that gate, so the verdict
13
+ * becomes data — addressable, hashable, signable, and citable by
14
+ * `Decision.policy_dependencies`.
15
+ * - Rules are evaluated *in order*; the first decisive rule wins, over a
16
+ * *structural* deny default. There is deliberately no `default` field and
17
+ * no expressible `default: allow` — the safe outcome is structural, not a
18
+ * rule someone can forget to add ("no silent defaults for security-relevant
19
+ * settings", root CLAUDE.md).
20
+ * - The *trust-ladder floor* (L5 deny, L4 always require_approval) is a
21
+ * non-overridable pre-check applied *before* the rule list, in the engine —
22
+ * it is NOT expressed as a rule, so no broad earlier `allow` can lift it.
23
+ *
24
+ * Not to be confused with `ContextPolicy` (`belief.ts`), which governs what
25
+ * beliefs may enter model context. This `Policy` governs what actions may
26
+ * touch the world — a different gate on a different chain link.
27
+ *
28
+ * Core owns the wire format only. The engine — `compile(policy) → PolicyGate`,
29
+ * the three-valued gate, signature verification, the arbitrate hook — lives in
30
+ * `@qmilab/lodestar-policy-kernel`.
31
+ */
32
+ /**
33
+ * The declarative effect of a matched rule.
34
+ *
35
+ * `require_approval` is the *declarative* counterpart of the gate's runtime
36
+ * `hold` verdict: a matched `require_approval` rule causes the engine to park
37
+ * the action at `pending_approval` and open an `ApprovalRequest`. (The runtime
38
+ * three-valued verdict `allow | deny | hold` is an engine type and lives in
39
+ * `@qmilab/lodestar-policy-kernel`, not in the wire format.)
40
+ */
41
+ export const PolicyEffectSchema = z.enum(["allow", "deny", "require_approval"]);
42
+ /**
43
+ * The match clause of a rule. All present fields must hold (AND); an absent
44
+ * field is a wildcard. A rule with an empty `match` matches every action.
45
+ *
46
+ * The fields constrain an `ActionContract` (`action.ts`):
47
+ * - `tool` is a glob over the tool registry key (e.g. `"git.*"`).
48
+ * - `max_blast_radius` matches contracts at or below this radius on the
49
+ * ordering self < session < project < external (the comparison is engine
50
+ * logic; the schema stores the ceiling).
51
+ * - `reversibility` is the set the contract's reversibility must be a member
52
+ * of (e.g. `["reversible", "compensable"]` excludes `irreversible`).
53
+ * - `scope` constrains the contract's `ResourceScope`.
54
+ * - `data_sensitivity` matches the contract's 3-value action sensitivity.
55
+ * - `required_level_lte` matches contracts whose `required_level` is at or
56
+ * below this trust level.
57
+ */
58
+ export const PolicyMatchSchema = z.object({
59
+ tool: z.string().min(1).optional().describe("glob over the tool registry key, e.g. 'git.*'"),
60
+ max_blast_radius: BlastRadiusSchema.optional().describe("matches contracts at or below this blast radius (self < session < project < external)"),
61
+ reversibility: z
62
+ .array(ReversibilitySchema)
63
+ .min(1)
64
+ .optional()
65
+ .describe("the set the contract's reversibility must be a member of"),
66
+ scope: ResourceScopeSchema.optional().describe("constrains the contract's ResourceScope"),
67
+ data_sensitivity: DataSensitivityForActionSchema.optional().describe("matches the contract's 3-value action sensitivity"),
68
+ required_level_lte: TrustLevelSchema.optional().describe("matches contracts whose required_level is at or below this"),
69
+ });
70
+ /**
71
+ * Constraints an approver must satisfy to resolve a held action. *Data, not a
72
+ * callback* — it says *what* an approver must be, checked against the
73
+ * resolver's `Actor`. This is what lets a team approval surface route a
74
+ * request to the right person without the Policy Kernel knowing anything
75
+ * about people. All fields optional; an empty object means "any actor the
76
+ * host has configured as a resolver may approve".
77
+ *
78
+ * The clearance check spans two alphabets: an action's `data_sensitivity` is
79
+ * the 3-value `public | private | secret`, an `Actor.sensitivity_clearance`
80
+ * is the 4-value `Sensitivity`. `sensitivity_clearance` here is the *4-value*
81
+ * `Sensitivity` — the action's sensitivity *mapped* via the Action Kernel's
82
+ * `sensitivityForContract` (`public→public`, `private→internal`,
83
+ * `secret→secret`) — so the approver-side comparison happens in one alphabet.
84
+ */
85
+ export const RequiredAuthoritySchema = z.object({
86
+ min_trust_baseline: z
87
+ .number()
88
+ .min(0)
89
+ .max(1)
90
+ .optional()
91
+ .describe("floor on an approver's Actor.trust_baseline"),
92
+ sensitivity_clearance: SensitivitySchema.optional().describe("4-value clearance the approver must hold; the action's data_sensitivity mapped via sensitivityForContract"),
93
+ scope: ResourceScopeSchema.optional().describe("ResourceScope the approver must hold"),
94
+ });
95
+ /**
96
+ * The approval requirement carried by a `require_approval` rule. When the rule
97
+ * fires, its `required_authority` becomes the opened `ApprovalRequest`'s
98
+ * `required_authority`. Omitting `required_authority` (or the whole
99
+ * `approval` object) means any configured resolver may approve.
100
+ *
101
+ * A thin wrapper today; it is the seam where multi-approver / N-of-M
102
+ * constraints attach when the team approval surface is built (deferred —
103
+ * `policy-kernel.md`, "a separate team surface").
104
+ */
105
+ export const ApprovalRequirementSchema = z.object({
106
+ required_authority: RequiredAuthoritySchema.optional().describe("constraints an approver must satisfy; omitted means any configured resolver may approve"),
107
+ });
108
+ /**
109
+ * One match → effect rule. Evaluated in document order; the first rule whose
110
+ * `match` holds is decisive. `reason` is surfaced verbatim in the
111
+ * `PolicyDecision` (and, for a held action, in the `ApprovalRequest`).
112
+ *
113
+ * `approval` may be present only on a `require_approval` rule (enforced
114
+ * below). It is not *required* there — an absent `approval` means the hold has
115
+ * no authority constraints (any configured resolver may approve), which is a
116
+ * meaningful default, so it is left optional rather than forced to an empty
117
+ * object.
118
+ */
119
+ export const PolicyRuleSchema = z
120
+ .object({
121
+ match: PolicyMatchSchema,
122
+ effect: PolicyEffectSchema,
123
+ approval: ApprovalRequirementSchema.optional().describe("present only on a require_approval rule; carries the authority an approver must hold"),
124
+ reason: z
125
+ .string()
126
+ .min(1)
127
+ .describe("surfaced verbatim in the PolicyDecision and ApprovalRequest"),
128
+ })
129
+ .superRefine((rule, ctx) => {
130
+ if (rule.approval !== undefined && rule.effect !== "require_approval") {
131
+ ctx.addIssue({
132
+ code: z.ZodIssueCode.custom,
133
+ path: ["approval"],
134
+ message: "approval may only be set on a rule whose effect is 'require_approval'",
135
+ });
136
+ }
137
+ });
138
+ /**
139
+ * A signed, packageable action-policy document.
140
+ *
141
+ * `version` is the monotonic string that `Decision.policy_dependencies` cites,
142
+ * so an audit can resolve exactly which policy version arbitrated an action.
143
+ *
144
+ * `signature` / `signed_by` are *optional at the schema level* so that
145
+ * unsigned **drafts** parse, but `v02-delta.md` §5 lists policy versions among
146
+ * the artifacts that *require* Ed25519 signatures: the Policy Kernel rejects an
147
+ * unsigned (or invalid-signature) policy at the gate, except under an explicit,
148
+ * logged `allow_unsigned: true` development opt-in. The signer is
149
+ * `signature.signer_id`; `signed_by` is a top-level convenience that must
150
+ * equal it when a signature is present (enforced below) — never a second,
151
+ * divergeable source of truth.
152
+ *
153
+ * The signature is computed over the *canonical document without the
154
+ * signature* — `{ id, version, rules }` — since a document cannot sign over
155
+ * its own signature. That canonical hash is what `signature.payload_hash`
156
+ * carries and what `Decision.policy_dependencies` ultimately pins.
157
+ */
158
+ export const PolicySchema = z
159
+ .object({
160
+ id: z.string().min(1).describe("stable policy id"),
161
+ version: z
162
+ .string()
163
+ .min(1)
164
+ .describe("monotonic version; this is the string Decision.policy_dependencies cites"),
165
+ rules: z
166
+ .array(PolicyRuleSchema)
167
+ .describe("evaluated in order; first decisive rule wins, over a structural deny default"),
168
+ signature: SignatureSchema.optional().describe("Ed25519 over the canonical document { id, version, rules }; required at the gate for an active policy"),
169
+ signed_by: z
170
+ .string()
171
+ .min(1)
172
+ .optional()
173
+ .describe("actor_id of the signer; present iff signature is present, and equals signature.signer_id"),
174
+ })
175
+ .superRefine((policy, ctx) => {
176
+ if (policy.signature !== undefined) {
177
+ if (policy.signed_by === undefined) {
178
+ ctx.addIssue({
179
+ code: z.ZodIssueCode.custom,
180
+ path: ["signed_by"],
181
+ message: "signed_by must be present when signature is present",
182
+ });
183
+ }
184
+ else if (policy.signed_by !== policy.signature.signer_id) {
185
+ ctx.addIssue({
186
+ code: z.ZodIssueCode.custom,
187
+ path: ["signed_by"],
188
+ message: "signed_by must equal signature.signer_id",
189
+ });
190
+ }
191
+ }
192
+ else if (policy.signed_by !== undefined) {
193
+ ctx.addIssue({
194
+ code: z.ZodIssueCode.custom,
195
+ path: ["signed_by"],
196
+ message: "signed_by must be omitted when signature is absent (unsigned draft)",
197
+ });
198
+ }
199
+ });
200
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/schemas/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,152 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The probe-pack format spec version. This is the version of the
4
+ * *manifest schema itself*, not of any given pack. A loader declares
5
+ * which spec versions it understands; a manifest declares which one it
6
+ * was written against. v0 of the harness understands spec "1" only.
7
+ *
8
+ * Bump this when the manifest shape changes in a way older loaders
9
+ * cannot read. Adding an optional field is not a bump; removing or
10
+ * re-typing a field is.
11
+ */
12
+ export declare const PROBE_PACK_SPEC_VERSION: "1";
13
+ /**
14
+ * Where a pack's probe files come from.
15
+ *
16
+ * `local` — the pack lives on the filesystem; probe `file` paths are
17
+ * resolved relative to the directory containing the manifest.
18
+ * `npm` — the pack ships as a published package; the loader reads the
19
+ * manifest from the package's `./lodestar.probe-pack.json` export and
20
+ * resolves probe files relative to the package root.
21
+ *
22
+ * Both source types are part of the spec from day one so external
23
+ * authors can target a stable schema. The v0 loader resolves `local`
24
+ * only; `npm` resolution follows the first external pack that needs it
25
+ * (see docs/architecture/reflection-pass.md Q6).
26
+ */
27
+ export declare const ProbePackSourceTypeSchema: z.ZodEnum<["local", "npm"]>;
28
+ export type ProbePackSourceType = z.infer<typeof ProbePackSourceTypeSchema>;
29
+ /**
30
+ * One probe entry in a pack manifest.
31
+ *
32
+ * `name` is the probe's stable identifier, unique within the pack — the
33
+ * harness runner reports results under it and external references
34
+ * address probes by `<pack>/<name>`. `file` is the probe source,
35
+ * relative to the pack root.
36
+ */
37
+ export declare const ProbeEntrySchema: z.ZodObject<{
38
+ name: z.ZodString;
39
+ file: z.ZodEffects<z.ZodString, string, string>;
40
+ }, "strip", z.ZodTypeAny, {
41
+ name: string;
42
+ file: string;
43
+ }, {
44
+ name: string;
45
+ file: string;
46
+ }>;
47
+ export type ProbeEntry = z.infer<typeof ProbeEntrySchema>;
48
+ /**
49
+ * One sentinel entry in a pack manifest.
50
+ *
51
+ * Unlike a probe — a `bun run`-able script the pack carries as a `file` —
52
+ * a sentinel is a stateful in-process class the harness instantiates and
53
+ * feeds the event stream. There is no subprocess contract for it, so the
54
+ * manifest references a sentinel by a stable `id` and the harness resolves
55
+ * that id against its built-in registry of first-party sentinels
56
+ * (`FIRST_PARTY_SENTINELS` in `@qmilab/lodestar-harness`). A pack thus
57
+ * *declares* which built-in sentinels it ships rather than carrying their
58
+ * source.
59
+ *
60
+ * Per-pack construction-option overrides and third-party (file-referenced)
61
+ * sentinels are a deliberate later refinement — see the harness loader and
62
+ * `docs/architecture/sentinels.md`. v0 resolves first-party ids only.
63
+ */
64
+ export declare const SentinelEntrySchema: z.ZodObject<{
65
+ id: z.ZodString;
66
+ }, "strip", z.ZodTypeAny, {
67
+ id: string;
68
+ }, {
69
+ id: string;
70
+ }>;
71
+ export type SentinelEntry = z.infer<typeof SentinelEntrySchema>;
72
+ /**
73
+ * A `lodestar.probe-pack.json` manifest.
74
+ *
75
+ * This is the on-disk / on-wire contract every probe pack — first-party
76
+ * and external — is written against. It is deliberately declarative:
77
+ * the manifest names probes and their files but contains no executable
78
+ * logic. The harness loader (in `@qmilab/lodestar-harness`) reads it,
79
+ * validates it against this schema, and resolves the probe files; the
80
+ * runner (Batch 4 step 5) executes them.
81
+ *
82
+ * `coverage_areas` and `invariants` are free-form taxonomy tags the
83
+ * pack author declares. They are not validated against a closed list —
84
+ * the harness uses them for `lodestar harness list` grouping and for
85
+ * answering "which pack exercises invariant X?", not for gating. Keeping
86
+ * them open lets external packs name coverage the core taxonomy has not
87
+ * yet enumerated.
88
+ */
89
+ export declare const ProbePackManifestSchema: z.ZodObject<{
90
+ name: z.ZodString;
91
+ version: z.ZodString;
92
+ spec_version: z.ZodLiteral<"1">;
93
+ source_type: z.ZodEnum<["local", "npm"]>;
94
+ description: z.ZodOptional<z.ZodString>;
95
+ coverage_areas: z.ZodArray<z.ZodString, "many">;
96
+ invariants: z.ZodArray<z.ZodString, "many">;
97
+ probes: z.ZodArray<z.ZodObject<{
98
+ name: z.ZodString;
99
+ file: z.ZodEffects<z.ZodString, string, string>;
100
+ }, "strip", z.ZodTypeAny, {
101
+ name: string;
102
+ file: string;
103
+ }, {
104
+ name: string;
105
+ file: string;
106
+ }>, "many">;
107
+ sentinels: z.ZodOptional<z.ZodArray<z.ZodObject<{
108
+ id: z.ZodString;
109
+ }, "strip", z.ZodTypeAny, {
110
+ id: string;
111
+ }, {
112
+ id: string;
113
+ }>, "many">>;
114
+ }, "strip", z.ZodTypeAny, {
115
+ name: string;
116
+ version: string;
117
+ spec_version: "1";
118
+ source_type: "local" | "npm";
119
+ coverage_areas: string[];
120
+ invariants: string[];
121
+ probes: {
122
+ name: string;
123
+ file: string;
124
+ }[];
125
+ description?: string | undefined;
126
+ sentinels?: {
127
+ id: string;
128
+ }[] | undefined;
129
+ }, {
130
+ name: string;
131
+ version: string;
132
+ spec_version: "1";
133
+ source_type: "local" | "npm";
134
+ coverage_areas: string[];
135
+ invariants: string[];
136
+ probes: {
137
+ name: string;
138
+ file: string;
139
+ }[];
140
+ description?: string | undefined;
141
+ sentinels?: {
142
+ id: string;
143
+ }[] | undefined;
144
+ }>;
145
+ export type ProbePackManifest = z.infer<typeof ProbePackManifestSchema>;
146
+ /**
147
+ * The manifest filename a `local` pack carries at its root, and the
148
+ * export key an `npm` pack exposes it under. Defined as a constant so
149
+ * loaders and pack authors agree on the spelling.
150
+ */
151
+ export declare const PROBE_PACK_MANIFEST_FILENAME: "lodestar.probe-pack.json";
152
+ //# sourceMappingURL=probe-pack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe-pack.d.ts","sourceRoot":"","sources":["../../src/schemas/probe-pack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,KAAe,CAAA;AAEnD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,6BAA2B,CAAA;AACjE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAE3E;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;EAuB3B,CAAA;AACF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAEzD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,mBAAmB;;;;;;EAW9B,CAAA;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAE/D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgDlC,CAAA;AACF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAA;AAEvE;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,4BAAsC,CAAA"}
@@ -0,0 +1,140 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The probe-pack format spec version. This is the version of the
4
+ * *manifest schema itself*, not of any given pack. A loader declares
5
+ * which spec versions it understands; a manifest declares which one it
6
+ * was written against. v0 of the harness understands spec "1" only.
7
+ *
8
+ * Bump this when the manifest shape changes in a way older loaders
9
+ * cannot read. Adding an optional field is not a bump; removing or
10
+ * re-typing a field is.
11
+ */
12
+ export const PROBE_PACK_SPEC_VERSION = "1";
13
+ /**
14
+ * Where a pack's probe files come from.
15
+ *
16
+ * `local` — the pack lives on the filesystem; probe `file` paths are
17
+ * resolved relative to the directory containing the manifest.
18
+ * `npm` — the pack ships as a published package; the loader reads the
19
+ * manifest from the package's `./lodestar.probe-pack.json` export and
20
+ * resolves probe files relative to the package root.
21
+ *
22
+ * Both source types are part of the spec from day one so external
23
+ * authors can target a stable schema. The v0 loader resolves `local`
24
+ * only; `npm` resolution follows the first external pack that needs it
25
+ * (see docs/architecture/reflection-pass.md Q6).
26
+ */
27
+ export const ProbePackSourceTypeSchema = z.enum(["local", "npm"]);
28
+ /**
29
+ * One probe entry in a pack manifest.
30
+ *
31
+ * `name` is the probe's stable identifier, unique within the pack — the
32
+ * harness runner reports results under it and external references
33
+ * address probes by `<pack>/<name>`. `file` is the probe source,
34
+ * relative to the pack root.
35
+ */
36
+ export const ProbeEntrySchema = z.object({
37
+ name: z
38
+ .string()
39
+ .min(1)
40
+ .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "probe name must be kebab-case (lowercase alphanumerics separated by single hyphens)")
41
+ .describe("Stable probe identifier, unique within the pack."),
42
+ file: z
43
+ .string()
44
+ .min(1)
45
+ // Must be relative to the pack root: a pack that names an absolute
46
+ // path loads on its author's machine but breaks once moved or
47
+ // published. Reject POSIX (`/`), UNC/Windows-root (`\`), and
48
+ // drive-letter (`C:`) prefixes so the contract holds cross-platform.
49
+ .refine((f) => !/^([/\\]|[A-Za-z]:)/.test(f), {
50
+ message: "probe file must be a relative path inside the pack (absolute paths are not allowed)",
51
+ })
52
+ .describe("Probe source file, relative to the pack root (the directory containing the manifest)."),
53
+ });
54
+ /**
55
+ * One sentinel entry in a pack manifest.
56
+ *
57
+ * Unlike a probe — a `bun run`-able script the pack carries as a `file` —
58
+ * a sentinel is a stateful in-process class the harness instantiates and
59
+ * feeds the event stream. There is no subprocess contract for it, so the
60
+ * manifest references a sentinel by a stable `id` and the harness resolves
61
+ * that id against its built-in registry of first-party sentinels
62
+ * (`FIRST_PARTY_SENTINELS` in `@qmilab/lodestar-harness`). A pack thus
63
+ * *declares* which built-in sentinels it ships rather than carrying their
64
+ * source.
65
+ *
66
+ * Per-pack construction-option overrides and third-party (file-referenced)
67
+ * sentinels are a deliberate later refinement — see the harness loader and
68
+ * `docs/architecture/sentinels.md`. v0 resolves first-party ids only.
69
+ */
70
+ export const SentinelEntrySchema = z.object({
71
+ id: z
72
+ .string()
73
+ .min(1)
74
+ .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "sentinel id must be kebab-case (lowercase alphanumerics separated by single hyphens)")
75
+ .describe("Stable id of a first-party sentinel, resolved by the harness against its built-in registry. Matches the sentinel's own `name`."),
76
+ });
77
+ /**
78
+ * A `lodestar.probe-pack.json` manifest.
79
+ *
80
+ * This is the on-disk / on-wire contract every probe pack — first-party
81
+ * and external — is written against. It is deliberately declarative:
82
+ * the manifest names probes and their files but contains no executable
83
+ * logic. The harness loader (in `@qmilab/lodestar-harness`) reads it,
84
+ * validates it against this schema, and resolves the probe files; the
85
+ * runner (Batch 4 step 5) executes them.
86
+ *
87
+ * `coverage_areas` and `invariants` are free-form taxonomy tags the
88
+ * pack author declares. They are not validated against a closed list —
89
+ * the harness uses them for `lodestar harness list` grouping and for
90
+ * answering "which pack exercises invariant X?", not for gating. Keeping
91
+ * them open lets external packs name coverage the core taxonomy has not
92
+ * yet enumerated.
93
+ */
94
+ export const ProbePackManifestSchema = z.object({
95
+ name: z
96
+ .string()
97
+ .min(1)
98
+ .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "pack name must be kebab-case (lowercase alphanumerics separated by single hyphens)")
99
+ .describe("Pack identifier, e.g. 'lodestar-core'."),
100
+ version: z
101
+ .string()
102
+ .min(1)
103
+ .describe("Pack version (the author's, not the spec version). Conventionally semver."),
104
+ spec_version: z
105
+ .literal(PROBE_PACK_SPEC_VERSION)
106
+ .describe("Manifest-schema spec version. v0 loaders accept only '1' and reject unknown versions with a clear error rather than guessing."),
107
+ source_type: ProbePackSourceTypeSchema.describe("How the loader resolves probe files. The v0 loader resolves 'local' only."),
108
+ description: z
109
+ .string()
110
+ .min(1)
111
+ .optional()
112
+ .describe("Human-readable one-liner shown by `lodestar harness list`."),
113
+ coverage_areas: z
114
+ .array(z.string().min(1))
115
+ .describe("Free-form tags naming the threat-model / subsystem areas this pack covers."),
116
+ invariants: z
117
+ .array(z.string().min(1))
118
+ .describe("Free-form tags naming the Lodestar invariants this pack's probes exercise."),
119
+ probes: z
120
+ .array(ProbeEntrySchema)
121
+ .min(1, "a pack must declare at least one probe")
122
+ .describe("The probes this pack ships."),
123
+ // `.optional()` rather than `.default([])` on purpose: a default makes the
124
+ // field REQUIRED in the `z.infer` *output* type, so external TS code that
125
+ // constructs a manifest without `sentinels` would fail to compile — breaking
126
+ // the "additive optional field is free" promise. Keeping it optional leaves
127
+ // the public type backward-compatible; the loader treats an absent value as
128
+ // "no sentinels". Do not reintroduce `.default([])`.
129
+ sentinels: z
130
+ .array(SentinelEntrySchema)
131
+ .optional()
132
+ .describe("The sentinels this pack ships, referenced by stable id and resolved by the harness against its built-in registry. Optional; an absent field means the pack ships no sentinels. Additive since spec '1' — a manifest without it still loads."),
133
+ });
134
+ /**
135
+ * The manifest filename a `local` pack carries at its root, and the
136
+ * export key an `npm` pack exposes it under. Defined as a constant so
137
+ * loaders and pack authors agree on the spelling.
138
+ */
139
+ export const PROBE_PACK_MANIFEST_FILENAME = "lodestar.probe-pack.json";
140
+ //# sourceMappingURL=probe-pack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe-pack.js","sourceRoot":"","sources":["../../src/schemas/probe-pack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAY,CAAA;AAEnD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAA;AAGjE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,KAAK,CACJ,4BAA4B,EAC5B,qFAAqF,CACtF;SACA,QAAQ,CAAC,kDAAkD,CAAC;IAC/D,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;QACP,mEAAmE;QACnE,8DAA8D;QAC9D,6DAA6D;QAC7D,qEAAqE;SACpE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;QAC5C,OAAO,EACL,qFAAqF;KACxF,CAAC;SACD,QAAQ,CACP,uFAAuF,CACxF;CACJ,CAAC,CAAA;AAGF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,EAAE,EAAE,CAAC;SACF,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,KAAK,CACJ,4BAA4B,EAC5B,sFAAsF,CACvF;SACA,QAAQ,CACP,gIAAgI,CACjI;CACJ,CAAC,CAAA;AAGF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,KAAK,CACJ,4BAA4B,EAC5B,oFAAoF,CACrF;SACA,QAAQ,CAAC,wCAAwC,CAAC;IACrD,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,2EAA2E,CAAC;IACxF,YAAY,EAAE,CAAC;SACZ,OAAO,CAAC,uBAAuB,CAAC;SAChC,QAAQ,CACP,+HAA+H,CAChI;IACH,WAAW,EAAE,yBAAyB,CAAC,QAAQ,CAC7C,2EAA2E,CAC5E;IACD,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,QAAQ,CAAC,4DAA4D,CAAC;IACzE,cAAc,EAAE,CAAC;SACd,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;SACxB,QAAQ,CAAC,4EAA4E,CAAC;IACzF,UAAU,EAAE,CAAC;SACV,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;SACxB,QAAQ,CAAC,4EAA4E,CAAC;IACzF,MAAM,EAAE,CAAC;SACN,KAAK,CAAC,gBAAgB,CAAC;SACvB,GAAG,CAAC,CAAC,EAAE,wCAAwC,CAAC;SAChD,QAAQ,CAAC,6BAA6B,CAAC;IAC1C,2EAA2E;IAC3E,0EAA0E;IAC1E,6EAA6E;IAC7E,4EAA4E;IAC5E,4EAA4E;IAC5E,qDAAqD;IACrD,SAAS,EAAE,CAAC;SACT,KAAK,CAAC,mBAAmB,CAAC;SAC1B,QAAQ,EAAE;SACV,QAAQ,CACP,6OAA6O,CAC9O;CACJ,CAAC,CAAA;AAGF;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,0BAAmC,CAAA"}