@codyswann/lisa 2.345.1 → 2.348.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/all/copy-overwrite/scripts/check-state-classification.mjs +609 -0
- package/all/copy-overwrite/scripts/lisa-command-envelope.mjs +194 -0
- package/all/copy-overwrite/scripts/lisa-schema-validate.mjs +208 -0
- package/all/copy-overwrite/scripts/schemas/lisa-command-envelope.v1.schema.json +119 -0
- package/all/copy-overwrite/scripts/schemas/lisa-state-contract.v1.schema.json +191 -0
- package/all/create-only/state/README.md +41 -0
- package/all/create-only/state/state-contract.example.json +46 -0
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +92 -10
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/expo/copy-overwrite/scripts/bdd/baseline.mjs +224 -0
- package/expo/copy-overwrite/scripts/bdd/contract.mjs +121 -0
- package/expo/copy-overwrite/scripts/bdd/envelope.mjs +231 -0
- package/expo/copy-overwrite/scripts/bdd/parse.mjs +220 -0
- package/expo/copy-overwrite/scripts/bdd/render.mjs +170 -0
- package/expo/copy-overwrite/scripts/bdd/report.mjs +361 -0
- package/expo/copy-overwrite/scripts/bdd/validate.mjs +282 -0
- package/expo/copy-overwrite/scripts/bdd/waivers.mjs +210 -0
- package/expo/copy-overwrite/scripts/bdd-matrix.mjs +278 -0
- package/expo/copy-overwrite/scripts/check-bdd-coverage.mjs +657 -0
- package/expo/create-only/bdd/coverage-map.json +38 -0
- package/expo/create-only/bdd/features/.keep +5 -0
- package/expo/github-rulesets/bdd-coverage.json +33 -0
- package/expo/package-lisa/package.lisa.json +3 -0
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-acceptance-criteria/SKILL.md +1 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-codify-verification/SKILL.md +4 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-research/SKILL.md +7 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-task-decomposition/SKILL.md +2 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-test-strategy/SKILL.md +1 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-verification-lifecycle/SKILL.md +1 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-verify/SKILL.md +1 -1
- package/plugins/lisa/rules/eager/reset-seed-coverage.md +48 -0
- package/plugins/lisa/rules/reference/reset-seed-coverage.md +231 -0
- package/plugins/lisa/skills/lisa-acceptance-criteria/SKILL.md +1 -0
- package/plugins/lisa/skills/lisa-codify-verification/SKILL.md +4 -0
- package/plugins/lisa/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/lisa/skills/lisa-research/SKILL.md +7 -1
- package/plugins/lisa/skills/lisa-task-decomposition/SKILL.md +2 -0
- package/plugins/lisa/skills/lisa-test-strategy/SKILL.md +1 -0
- package/plugins/lisa/skills/lisa-verification-lifecycle/SKILL.md +1 -0
- package/plugins/lisa/skills/lisa-verify/SKILL.md +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-acceptance-criteria/SKILL.md +1 -0
- package/plugins/lisa-agy/skills/lisa-codify-verification/SKILL.md +4 -0
- package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/lisa-agy/skills/lisa-research/SKILL.md +7 -1
- package/plugins/lisa-agy/skills/lisa-task-decomposition/SKILL.md +2 -0
- package/plugins/lisa-agy/skills/lisa-test-strategy/SKILL.md +1 -0
- package/plugins/lisa-agy/skills/lisa-verification-lifecycle/SKILL.md +1 -0
- package/plugins/lisa-agy/skills/lisa-verify/SKILL.md +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/rules/eager/reset-seed-coverage.md +48 -0
- package/plugins/lisa-copilot/rules/reference/reset-seed-coverage.md +231 -0
- package/plugins/lisa-copilot/skills/lisa-acceptance-criteria/SKILL.md +1 -0
- package/plugins/lisa-copilot/skills/lisa-codify-verification/SKILL.md +4 -0
- package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/lisa-copilot/skills/lisa-research/SKILL.md +7 -1
- package/plugins/lisa-copilot/skills/lisa-task-decomposition/SKILL.md +2 -0
- package/plugins/lisa-copilot/skills/lisa-test-strategy/SKILL.md +1 -0
- package/plugins/lisa-copilot/skills/lisa-verification-lifecycle/SKILL.md +1 -0
- package/plugins/lisa-copilot/skills/lisa-verify/SKILL.md +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/rules/reset-seed-coverage-reference.mdc +236 -0
- package/plugins/lisa-cursor/rules/reset-seed-coverage.mdc +53 -0
- package/plugins/lisa-cursor/skills/lisa-acceptance-criteria/SKILL.md +1 -0
- package/plugins/lisa-cursor/skills/lisa-codify-verification/SKILL.md +4 -0
- package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/lisa-cursor/skills/lisa-research/SKILL.md +7 -1
- package/plugins/lisa-cursor/skills/lisa-task-decomposition/SKILL.md +2 -0
- package/plugins/lisa-cursor/skills/lisa-test-strategy/SKILL.md +1 -0
- package/plugins/lisa-cursor/skills/lisa-verification-lifecycle/SKILL.md +1 -0
- package/plugins/lisa-cursor/skills/lisa-verify/SKILL.md +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/skills/ops-db-ops/SKILL.md +93 -2
- package/plugins/lisa-expo/skills/ops-db-ops/SKILL.md +94 -3
- package/plugins/lisa-expo/skills/ops-db-ops/agents/openai.yaml +2 -2
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-agy/skills/ops-db-ops/SKILL.md +94 -3
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/skills/ops-db-ops/SKILL.md +94 -3
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/skills/ops-db-ops/SKILL.md +94 -3
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/rules/eager/reset-seed-coverage.md +48 -0
- package/plugins/src/base/rules/reference/reset-seed-coverage.md +231 -0
- package/plugins/src/base/skills/lisa-acceptance-criteria/SKILL.md +1 -0
- package/plugins/src/base/skills/lisa-codify-verification/SKILL.md +4 -0
- package/plugins/src/base/skills/lisa-implement/SKILL.md +2 -0
- package/plugins/src/base/skills/lisa-research/SKILL.md +7 -1
- package/plugins/src/base/skills/lisa-task-decomposition/SKILL.md +2 -0
- package/plugins/src/base/skills/lisa-test-strategy/SKILL.md +1 -0
- package/plugins/src/base/skills/lisa-verification-lifecycle/SKILL.md +1 -0
- package/plugins/src/base/skills/lisa-verify/SKILL.md +1 -1
- package/plugins/src/expo/skills/ops-db-ops/SKILL.md +94 -3
- package/scripts/check-state-classification.mjs +27 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://lisa.codyswann.dev/schemas/lisa-state-contract.v1.schema.json",
|
|
4
|
+
"title": "Lisa state contract (v1)",
|
|
5
|
+
"description": "Per-project declaration of every persistent entity and the reset policy that governs it. Governed by the reset-seed-coverage rule. The check compares a runtime inventory against this document and fails closed on any entity the document does not classify.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["schemaVersion", "contractVersion", "mode", "owner"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": {
|
|
11
|
+
"const": "lisa-state-contract-v1",
|
|
12
|
+
"description": "Pinned schema version. A bump is a deliberate migration."
|
|
13
|
+
},
|
|
14
|
+
"contractVersion": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"minLength": 1,
|
|
17
|
+
"description": "The project's own version for its declared state. Bump whenever a policy or ownership predicate changes, so evidence from one run cannot be read as evidence for a different contract."
|
|
18
|
+
},
|
|
19
|
+
"mode": {
|
|
20
|
+
"enum": ["contract", "declared-noop"],
|
|
21
|
+
"description": "contract = this project holds persistent state and classifies it below. declared-noop = this project holds no persistent state; the check verifies that claim against the repository rather than trusting it."
|
|
22
|
+
},
|
|
23
|
+
"owner": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"minLength": 1,
|
|
26
|
+
"description": "Team or role that answers questions about this file. Not an individual's personal account."
|
|
27
|
+
},
|
|
28
|
+
"noop": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"additionalProperties": false,
|
|
31
|
+
"required": ["reason", "owner", "capabilityManifest"],
|
|
32
|
+
"description": "Required when mode is declared-noop. A bare exit 0 is indistinguishable from a successful destructive run and never satisfies the contract.",
|
|
33
|
+
"properties": {
|
|
34
|
+
"reason": { "type": "string", "minLength": 1 },
|
|
35
|
+
"owner": { "type": "string", "minLength": 1 },
|
|
36
|
+
"capabilityManifest": { "type": "string", "minLength": 1 }
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"environments": {
|
|
40
|
+
"type": "array",
|
|
41
|
+
"description": "Environments a reset may target. Each names how the environment identity is resolved server-side; a caller-supplied stage is only a request checked against it.",
|
|
42
|
+
"items": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"additionalProperties": true,
|
|
45
|
+
"required": ["name", "identitySource"],
|
|
46
|
+
"properties": {
|
|
47
|
+
"name": { "type": "string", "minLength": 1 },
|
|
48
|
+
"identitySource": { "type": "string", "minLength": 1 },
|
|
49
|
+
"resetAllowed": { "type": "boolean" }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"fixtureIdentity": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"additionalProperties": true,
|
|
56
|
+
"required": ["description"],
|
|
57
|
+
"description": "How fixture-owned records are recognized. The ownership predicate the entire safety model rests on: a reserved id shape, a reserved account or namespace, or a marker attribute.",
|
|
58
|
+
"properties": {
|
|
59
|
+
"description": { "type": "string", "minLength": 1 },
|
|
60
|
+
"idPattern": { "type": "string", "minLength": 1 },
|
|
61
|
+
"reservedPrincipals": { "type": "array", "items": { "type": "string" } }
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"detection": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"additionalProperties": false,
|
|
67
|
+
"description": "Tuning for the subtraction detectors. Detectors are a staleness signal, never the safety boundary.",
|
|
68
|
+
"properties": {
|
|
69
|
+
"sources": {
|
|
70
|
+
"type": "array",
|
|
71
|
+
"items": { "type": "string", "minLength": 1 },
|
|
72
|
+
"description": "Extra repository paths to scan for declared entities (migrations, schema files, model definitions)."
|
|
73
|
+
},
|
|
74
|
+
"ignore": {
|
|
75
|
+
"type": "array",
|
|
76
|
+
"items": { "type": "string", "minLength": 1 },
|
|
77
|
+
"description": "Entity names the detectors may find but that are not real persistent entities (framework bookkeeping, examples in docs)."
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"entities": {
|
|
82
|
+
"type": "array",
|
|
83
|
+
"description": "One entry per persistent entity. Rows are only one kind of state: identity-provider objects, object-storage prefixes, search indexes, queues, caches, derived views, scheduled jobs and outbound side effects all belong here too.",
|
|
84
|
+
"items": {
|
|
85
|
+
"type": "object",
|
|
86
|
+
"additionalProperties": true,
|
|
87
|
+
"required": ["id", "kind", "policy", "reason", "owner"],
|
|
88
|
+
"properties": {
|
|
89
|
+
"id": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"minLength": 1,
|
|
92
|
+
"description": "Stable, fully qualified identifier: namespace/schema plus name."
|
|
93
|
+
},
|
|
94
|
+
"kind": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"minLength": 1,
|
|
97
|
+
"description": "The project's own vocabulary for what sort of state this is (table, view, materialized-view, identity-group, object-prefix, search-index, queue, cache-namespace, scheduled-job, external-record, ...)."
|
|
98
|
+
},
|
|
99
|
+
"policy": {
|
|
100
|
+
"enum": [
|
|
101
|
+
"fixture-owned",
|
|
102
|
+
"preserve",
|
|
103
|
+
"derived-rebuild",
|
|
104
|
+
"forbidden"
|
|
105
|
+
],
|
|
106
|
+
"description": "fixture-owned = the reset may delete records it owns. preserve = untouched. derived-rebuild = recomputed from sources. forbidden = the reset must be structurally unable to touch it."
|
|
107
|
+
},
|
|
108
|
+
"reason": {
|
|
109
|
+
"type": "string",
|
|
110
|
+
"minLength": 1,
|
|
111
|
+
"description": "Why this policy, in one sentence a reviewer can check. Classify by provenance (who writes it, can anything put it back), never by an emptiness observation."
|
|
112
|
+
},
|
|
113
|
+
"owner": { "type": "string", "minLength": 1 },
|
|
114
|
+
"ownership": {
|
|
115
|
+
"type": "string",
|
|
116
|
+
"minLength": 1,
|
|
117
|
+
"description": "Required for fixture-owned: the predicate identifying which records the reset may delete. Never 'everything in this entity'."
|
|
118
|
+
},
|
|
119
|
+
"sweptBy": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"minLength": 1,
|
|
122
|
+
"description": "Required for fixture-owned: the routine that actually removes them. A fixture-owned entity nothing sweeps is the leak this contract exists to catch."
|
|
123
|
+
},
|
|
124
|
+
"rebuiltFrom": { "type": "string", "minLength": 1 },
|
|
125
|
+
"rebuiltBy": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"minLength": 1,
|
|
128
|
+
"description": "Required for derived-rebuild: the routine that recomputes it, and proves convergence."
|
|
129
|
+
},
|
|
130
|
+
"enforcedBy": {
|
|
131
|
+
"type": "string",
|
|
132
|
+
"minLength": 1,
|
|
133
|
+
"description": "Required for forbidden: a control OUTSIDE the reset process — a least-privilege role, a revoked grant, a separate credential boundary, a constraint. 'The script does not touch it' is not an enforcement."
|
|
134
|
+
},
|
|
135
|
+
"retiredAt": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"minLength": 1,
|
|
138
|
+
"description": "Set when the entity no longer exists. A classified entity absent from the inventory is stale and fails unless retired with a date."
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"assurances": {
|
|
144
|
+
"type": "object",
|
|
145
|
+
"additionalProperties": false,
|
|
146
|
+
"description": "The required properties of the reset, each pointing at the evidence that proves it. A declaration with no evidence pointer fails the check.",
|
|
147
|
+
"properties": {
|
|
148
|
+
"preserves-non-fixture-data": { "$ref": "#/$defs/assurance" },
|
|
149
|
+
"rejects-reserved-id-collision": { "$ref": "#/$defs/assurance" },
|
|
150
|
+
"rejects-foreign-references": { "$ref": "#/$defs/assurance" },
|
|
151
|
+
"requires-write-acknowledgment": { "$ref": "#/$defs/assurance" },
|
|
152
|
+
"converges-on-second-apply": { "$ref": "#/$defs/assurance" },
|
|
153
|
+
"verifies-exact-counts": { "$ref": "#/$defs/assurance" },
|
|
154
|
+
"production-fails-closed": { "$ref": "#/$defs/assurance" },
|
|
155
|
+
"guard-at-the-choke-point": { "$ref": "#/$defs/assurance" },
|
|
156
|
+
"enumerates-before-mutating": { "$ref": "#/$defs/assurance" }
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"waivers": {
|
|
160
|
+
"type": "array",
|
|
161
|
+
"description": "Dated IOUs for entities that genuinely cannot be classified yet. A waived entity is treated as preserve for safety and stays a visible finding; it never counts as classified.",
|
|
162
|
+
"items": {
|
|
163
|
+
"type": "object",
|
|
164
|
+
"additionalProperties": true,
|
|
165
|
+
"required": ["id", "reason", "owner", "ticket", "recordedAt"],
|
|
166
|
+
"properties": {
|
|
167
|
+
"id": { "type": "string", "minLength": 1 },
|
|
168
|
+
"reason": { "type": "string", "minLength": 1 },
|
|
169
|
+
"owner": { "type": "string", "minLength": 1 },
|
|
170
|
+
"ticket": { "type": "string", "minLength": 1 },
|
|
171
|
+
"recordedAt": { "type": "string", "minLength": 1 }
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"$defs": {
|
|
177
|
+
"assurance": {
|
|
178
|
+
"type": "object",
|
|
179
|
+
"additionalProperties": true,
|
|
180
|
+
"required": ["evidence"],
|
|
181
|
+
"properties": {
|
|
182
|
+
"evidence": {
|
|
183
|
+
"type": "string",
|
|
184
|
+
"minLength": 1,
|
|
185
|
+
"description": "Pointer to the test, guard, role, or grant that proves this property."
|
|
186
|
+
},
|
|
187
|
+
"note": { "type": "string", "minLength": 1 }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# State contract
|
|
2
|
+
|
|
3
|
+
`state-contract.json` is this project's declaration of every persistent entity and the reset policy
|
|
4
|
+
that governs it, required by Lisa's `reset-seed-coverage` rule.
|
|
5
|
+
|
|
6
|
+
Copy `state-contract.example.json` to `state-contract.json` and fill it in. Until that file exists,
|
|
7
|
+
the state-classification check reports `not-adopted` — adoption is an explicit act, so no repo
|
|
8
|
+
silently passes a gate it never wired.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
node scripts/check-state-classification.mjs
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Schema: `scripts/schemas/lisa-state-contract.v1.schema.json`.
|
|
15
|
+
|
|
16
|
+
## The two things the template cannot do for you
|
|
17
|
+
|
|
18
|
+
**Classify by provenance, not by observation.** "The table looked empty" is not evidence it is
|
|
19
|
+
unused. Row-count statistics are approximations, and a table nobody has analyzed reports rows it
|
|
20
|
+
holds. Ask who writes it and whether anything can put it back. Prefer `preserve` when unsure — an
|
|
21
|
+
over-preserved entity leaks; an over-cleared one destroys.
|
|
22
|
+
|
|
23
|
+
**Include state that is not rows.** Identity-provider objects, object-storage prefixes, search
|
|
24
|
+
indexes, queues and dead-letter backlogs, caches with a persistence tier, derived and materialized
|
|
25
|
+
views, runtime-created jobs, and outbound side effects all belong in `entities`. Leaked test state is
|
|
26
|
+
most expensive exactly where nobody thought to look.
|
|
27
|
+
|
|
28
|
+
## The four policies
|
|
29
|
+
|
|
30
|
+
| Policy | Meaning |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `fixture-owned` | The reset may delete records it owns here. Requires an `ownership` predicate and a `sweptBy` routine — an entity the suite creates but nothing removes is the leak this contract exists to catch. |
|
|
33
|
+
| `preserve` | Left untouched. Catalog, reference data, anything a migration seeds, anything belonging to someone real. |
|
|
34
|
+
| `derived-rebuild` | Recomputed from its sources after the reset, then proven converged. |
|
|
35
|
+
| `forbidden` | The reset must be structurally unable to touch it. Requires `enforcedBy` naming a control outside the reset process — a role, a revoked grant, a credential boundary. "The script does not touch it" is not an enforcement. |
|
|
36
|
+
|
|
37
|
+
## No persistent state at all?
|
|
38
|
+
|
|
39
|
+
Set `"mode": "declared-noop"` and fill in the `noop` block (reason, owner, capability-manifest
|
|
40
|
+
reference) instead of `entities`. The check verifies that claim against the repository rather than
|
|
41
|
+
trusting it: a repo showing persistence signals may not declare a reset noop.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "lisa-state-contract-v1",
|
|
3
|
+
"contractVersion": "REPLACE-ME-state-v1",
|
|
4
|
+
"mode": "contract",
|
|
5
|
+
"owner": "REPLACE-ME-team-or-role",
|
|
6
|
+
"environments": [
|
|
7
|
+
{
|
|
8
|
+
"name": "dev",
|
|
9
|
+
"identitySource": "REPLACE-ME: how the environment identity is resolved SERVER-SIDE. A caller-supplied --stage, URL or public build-time variable is a request to check against this, never the answer.",
|
|
10
|
+
"resetAllowed": true
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "production",
|
|
14
|
+
"identitySource": "REPLACE-ME",
|
|
15
|
+
"resetAllowed": false
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"fixtureIdentity": {
|
|
19
|
+
"description": "REPLACE-ME: how a fixture-owned record is recognized. Everything the reset may delete must match this; anything else belongs to someone real.",
|
|
20
|
+
"idPattern": "REPLACE-ME-or-remove",
|
|
21
|
+
"reservedPrincipals": []
|
|
22
|
+
},
|
|
23
|
+
"entities": [
|
|
24
|
+
{
|
|
25
|
+
"id": "REPLACE-ME.example_table",
|
|
26
|
+
"kind": "table",
|
|
27
|
+
"policy": "fixture-owned",
|
|
28
|
+
"reason": "REPLACE-ME: one sentence a reviewer can check.",
|
|
29
|
+
"owner": "REPLACE-ME",
|
|
30
|
+
"ownership": "REPLACE-ME: the predicate identifying records the reset may delete. Never 'everything in this entity'.",
|
|
31
|
+
"sweptBy": "REPLACE-ME: the routine that actually removes them. A fixture-owned entity nothing sweeps is the leak this contract exists to catch."
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"assurances": {
|
|
35
|
+
"preserves-non-fixture-data": { "evidence": "REPLACE-ME: test or role" },
|
|
36
|
+
"rejects-reserved-id-collision": { "evidence": "REPLACE-ME" },
|
|
37
|
+
"rejects-foreign-references": { "evidence": "REPLACE-ME" },
|
|
38
|
+
"requires-write-acknowledgment": { "evidence": "REPLACE-ME" },
|
|
39
|
+
"converges-on-second-apply": { "evidence": "REPLACE-ME" },
|
|
40
|
+
"verifies-exact-counts": { "evidence": "REPLACE-ME" },
|
|
41
|
+
"production-fails-closed": { "evidence": "REPLACE-ME" },
|
|
42
|
+
"guard-at-the-choke-point": { "evidence": "REPLACE-ME" },
|
|
43
|
+
"enumerates-before-mutating": { "evidence": "REPLACE-ME" }
|
|
44
|
+
},
|
|
45
|
+
"waivers": []
|
|
46
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upstream-evidence-manifest.d.ts","sourceRoot":"","sources":["../../src/core/upstream-evidence-manifest.ts"],"names":[],"mappings":"AACA,iFAAiF;AACjF,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"upstream-evidence-manifest.d.ts","sourceRoot":"","sources":["../../src/core/upstream-evidence-manifest.ts"],"names":[],"mappings":"AACA,iFAAiF;AACjF,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA0tEpE,CAAC;AAEL,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CA0zNjE,CAAC;AAEL,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAk6I/D,CAAC"}
|