dsh-env-manager-plugin 0.1.0 → 0.1.1
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/LICENSE +21 -21
- package/README.md +273 -250
- package/client.js +2581 -2581
- package/cordis.patch.yml +4 -4
- package/docs/00-project/current-state.md +32 -6
- package/docs/00-project/glossary.md +215 -215
- package/docs/00-project/project-brief.md +114 -114
- package/docs/00-project/roadmap.md +89 -89
- package/docs/01-architecture/DSH_Environment_Service_Memory_Skill_Brainstorm.md +493 -493
- package/docs/01-architecture/api-verification.md +416 -416
- package/docs/01-architecture/architecture-overview.md +222 -222
- package/docs/01-architecture/data-model.md +930 -930
- package/docs/01-architecture/decisions/ADR-0001-plugin-as-bundle.md +29 -29
- package/docs/01-architecture/decisions/ADR-0002-file-based-storage.md +25 -25
- package/docs/01-architecture/decisions/ADR-0003-skill-router-over-search.md +25 -25
- package/docs/01-architecture/decisions/ADR-0004-typescript-host-js-client.md +31 -31
- package/docs/01-architecture/decisions/ADR-0005-layered-rule-resolution.md +36 -36
- package/docs/01-architecture/decisions/ADR-0006-credentials-as-references.md +30 -30
- package/docs/01-architecture/decisions/ADR-0007-session-scoped-default-environment.md +28 -28
- package/docs/01-architecture/decisions/ADR-0008-memory-bridge-not-second-store.md +31 -31
- package/docs/01-architecture/decisions/ADR-0009-client-host-http-transport.md +87 -87
- package/docs/01-architecture/decisions/ADR-0010-environment-plane-model.md +87 -87
- package/docs/01-architecture/decisions/ADR-0011-k8s-node-execution-model.md +92 -92
- package/docs/01-architecture/design.md +666 -666
- package/docs/01-architecture/detailed-design.md +961 -961
- package/docs/01-architecture/implementation-plan.md +323 -323
- package/docs/01-architecture/module-boundaries.md +306 -306
- package/docs/01-architecture/security-model.md +227 -227
- package/docs/01-architecture/storage-contract.md +224 -224
- package/docs/01-architecture/tool-contract.md +438 -438
- package/docs/01-architecture/ui-design.md +587 -587
- package/docs/02-harness/agent-behavior.md +36 -36
- package/docs/02-harness/change-snapshot-policy.md +29 -29
- package/docs/02-harness/client-ui-integration.md +110 -110
- package/docs/02-harness/context-policy.md +43 -43
- package/docs/02-harness/harness-standard.md +91 -91
- package/docs/02-harness/task-execution-policy.md +26 -26
- package/docs/02-harness/verification-policy.md +97 -97
- package/docs/03-openspec/archive-rule.md +25 -25
- package/docs/03-openspec/bugfix-rule.md +30 -30
- package/docs/03-openspec/design-rule.md +33 -33
- package/docs/03-openspec/openspec-usage-guide.md +31 -31
- package/docs/03-openspec/proposal-rule.md +70 -70
- package/docs/03-openspec/spec-rule.md +33 -33
- package/docs/03-openspec/tasks-rule.md +31 -31
- package/docs/04-development/coding-style.md +67 -67
- package/docs/04-development/dependency-policy.md +43 -43
- package/docs/04-development/development-guide.md +85 -85
- package/docs/04-development/directory-convention.md +105 -105
- package/docs/04-development/local-run-guide.md +61 -55
- package/docs/04-development/testing-guide.md +102 -102
- package/docs/05-domain/deployment-template.md +76 -76
- package/docs/05-domain/environment-template.md +165 -165
- package/docs/05-domain/operation-binding-template.md +55 -55
- package/docs/05-domain/operation-record-template.md +55 -55
- package/docs/05-domain/prompt-template.md +90 -90
- package/docs/05-domain/rule-template.md +73 -73
- package/docs/05-domain/service-template.md +39 -39
- package/docs/06-operations/deployment-guide.md +54 -54
- package/docs/06-operations/release.md +198 -188
- package/docs/06-operations/security-policy.md +53 -53
- package/docs/06-operations/troubleshooting.md +141 -91
- package/docs/07-templates/adr-template.md +21 -21
- package/docs/07-templates/bugfix-template.md +11 -11
- package/docs/07-templates/case-template.md +15 -15
- package/docs/07-templates/design-template.md +29 -29
- package/docs/07-templates/proposal-template.md +19 -19
- package/docs/07-templates/spec-template.md +15 -15
- package/docs/07-templates/tasks-template.md +12 -12
- package/docs/99-archive/README.md +13 -13
- package/docs/README.md +142 -142
- package/icon.svg +4 -4
- package/index.js +31 -8
- package/lib/skill.js +37 -37
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +101 -99
- package/scripts/repair-profile.mjs +141 -0
|
@@ -1,224 +1,224 @@
|
|
|
1
|
-
# Storage Contract
|
|
2
|
-
|
|
3
|
-
Status: normative for V1.
|
|
4
|
-
|
|
5
|
-
Durable registry data is a directory of YAML files. Nothing else is authoritative.
|
|
6
|
-
|
|
7
|
-
Related: [data-model.md](./data-model.md), [design.md](./design.md) §5.
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## 1. Location
|
|
12
|
-
|
|
13
|
-
```text
|
|
14
|
-
<dataDir>/
|
|
15
|
-
├── environments/{environmentId}.yaml
|
|
16
|
-
├── services/{serviceId}.yaml
|
|
17
|
-
├── deployments/{deploymentId}.yaml
|
|
18
|
-
├── rules/{ruleProfileId}.yaml
|
|
19
|
-
├── operations/{bindingId}.yaml
|
|
20
|
-
├── sessions/{sessionId}.json
|
|
21
|
-
└── .backups/
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### 1.1 Resolving `dataDir`
|
|
25
|
-
|
|
26
|
-
Precedence:
|
|
27
|
-
|
|
28
|
-
1. Plugin config `dataDir`, when set (absolute path or path relative to the profile directory).
|
|
29
|
-
2. `profileContext.dir` → `<dir>/data/dsh-env-manager`.
|
|
30
|
-
3. `$DSH_PROFILE_DIR/data/dsh-env-manager`.
|
|
31
|
-
4. `<working directory>/data/dsh-env-manager` as a last resort for development only.
|
|
32
|
-
|
|
33
|
-
The chosen path is memoized, reported once at startup, and shown in the UI overview. It
|
|
34
|
-
is never derived from model input. Resolution order and fallbacks are implemented in
|
|
35
|
-
`src/storage/paths.ts` (detailed-design §4.1).
|
|
36
|
-
|
|
37
|
-
### 1.2 Creation
|
|
38
|
-
|
|
39
|
-
- The directory tree is created on first use.
|
|
40
|
-
- A missing directory is not an error; an unwritable directory is an error with `STORAGE_UNWRITABLE`.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## 2. File rules
|
|
45
|
-
|
|
46
|
-
| Rule | Value |
|
|
47
|
-
|---|---|
|
|
48
|
-
| Encoding | UTF-8, no BOM |
|
|
49
|
-
| Line endings | LF on write; CRLF tolerated on read |
|
|
50
|
-
| Format | YAML 1.2 |
|
|
51
|
-
| Extension | `.yaml` for records, `.json` for session state |
|
|
52
|
-
| Name | `{id}.yaml`, where `id` matches `^[a-z0-9][a-z0-9-]{0,62}$` |
|
|
53
|
-
| Extra files | Ignored unless they match the extension; ignored files are not deleted |
|
|
54
|
-
|
|
55
|
-
A record file whose `id` differs from its filename is reported by `env_validate` and treated as invalid on load.
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## 3. Record envelope
|
|
60
|
-
|
|
61
|
-
Every record carries:
|
|
62
|
-
|
|
63
|
-
```yaml
|
|
64
|
-
id: string
|
|
65
|
-
schemaVersion: 1
|
|
66
|
-
createdAt: 2026-11-01T03:00:00.000Z
|
|
67
|
-
updatedAt: 2026-11-01T03:00:00.000Z
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
- `createdAt` is set by storage on create.
|
|
71
|
-
- `updatedAt` is set by storage on every successful write.
|
|
72
|
-
- A write input may include both fields; storage overrides them. `createdAt` is
|
|
73
|
-
preserved from the existing file on update, so a caller cannot rewrite history.
|
|
74
|
-
- The stored record always contains both fields.
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## 4. Atomic write protocol
|
|
79
|
-
|
|
80
|
-
```text
|
|
81
|
-
1. Serialize the record to YAML.
|
|
82
|
-
2. Validate the serialized document by parsing it back and running schema validation.
|
|
83
|
-
3. Open `.${id}.${pid}.${randomUUID()}.tmp` in the target directory.
|
|
84
|
-
4. Write UTF-8, fsync, close.
|
|
85
|
-
5. Copy the previous file into `.backups/<kind>/<id>/<timestamp>.yaml`, prune to 5.
|
|
86
|
-
6. Rename over the target (atomic on the same volume).
|
|
87
|
-
7. On a caught failure before rename, delete the temp file and leave the target intact.
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Constraints:
|
|
91
|
-
|
|
92
|
-
- Never write directly to the target file.
|
|
93
|
-
- Never leave a temp file behind on success or on a caught failure. A crash can leave
|
|
94
|
-
one; startup removes `*.tmp` older than one hour.
|
|
95
|
-
- A backup failure does not fail the write; it is reported as a warning.
|
|
96
|
-
- Never delete a record file that failed to parse; surface a diagnostic instead.
|
|
97
|
-
- Storage does not reload the registry; the application layer does after a successful
|
|
98
|
-
write.
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## 5. Read behavior
|
|
103
|
-
|
|
104
|
-
```text
|
|
105
|
-
1. Enumerate `*.yaml` in the directory.
|
|
106
|
-
2. Parse each file.
|
|
107
|
-
3. Schema-validate.
|
|
108
|
-
4. On parse error: record `RECORD_INVALID` diagnostic, skip the file.
|
|
109
|
-
5. On unknown schemaVersion: record `SCHEMA_UNSUPPORTED` warning, skip the file.
|
|
110
|
-
6. Build an in-memory map keyed by id.
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
Reads never modify files. A failed file stays on disk for the user to fix.
|
|
114
|
-
|
|
115
|
-
If a directory is unreadable, the loader returns an empty map plus an error diagnostic; tools still serve whatever other directories loaded.
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## 6. Registry lifecycle
|
|
120
|
-
|
|
121
|
-
- V1 loads the registry at the start of every application request.
|
|
122
|
-
- Concurrent requests share one in-flight load.
|
|
123
|
-
- A successful write triggers a reload before the request returns.
|
|
124
|
-
- The registry is an in-memory snapshot; it is never persisted.
|
|
125
|
-
- V1 has no index files and no watcher. A scan of a few hundred small YAML files is
|
|
126
|
-
fast enough; an mtime-keyed cache is added only with measured need.
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## 7. Session state
|
|
131
|
-
|
|
132
|
-
```text
|
|
133
|
-
sessions/{sessionId}.json
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
```json
|
|
137
|
-
{
|
|
138
|
-
"schemaVersion": 1,
|
|
139
|
-
"sessionId": "session-abc",
|
|
140
|
-
"defaultEnvironmentId": "test-a",
|
|
141
|
-
"updatedAt": "2026-11-01T03:00:00.000Z"
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
Rules:
|
|
146
|
-
|
|
147
|
-
- Written atomically with the same protocol as records.
|
|
148
|
-
- A missing file means "no default".
|
|
149
|
-
- A corrupt file is treated as "no default" and reported as `persisted: false`; it is
|
|
150
|
-
not deleted, so the user can inspect it.
|
|
151
|
-
- A process-local cache mirrors the last value so a failed write still works until
|
|
152
|
-
restart (detailed-design §9).
|
|
153
|
-
- Session files are not registry records and are never scanned into the registry.
|
|
154
|
-
- V1 uses this file store; a projection over the durable session log is a later
|
|
155
|
-
refinement (detailed-design §9).
|
|
156
|
-
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
## 8. Referential integrity
|
|
160
|
-
|
|
161
|
-
Storage itself does not enforce cross-record references; the registry does, on load and on write:
|
|
162
|
-
|
|
163
|
-
- Broken references are reported by `env_validate`.
|
|
164
|
-
- On load, an invalid reference produces a warning; the record stays usable for name lookups.
|
|
165
|
-
- On write, an invalid reference is rejected (`RECORD_INVALID` with details).
|
|
166
|
-
|
|
167
|
-
This split keeps a single bad file from making the whole registry unusable.
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## 9. Backups
|
|
172
|
-
|
|
173
|
-
V1 keeps one rolling backup per write:
|
|
174
|
-
|
|
175
|
-
```text
|
|
176
|
-
.backups/{kind}/{id}/{timestamp}.yaml
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
- At most 5 backups per record; older ones are pruned.
|
|
180
|
-
- Backups are best-effort: a backup failure does not fail the write, but emits a warning.
|
|
181
|
-
- Backups are not a history feature. They exist to recover from an accidental overwrite.
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## 10. Migration
|
|
186
|
-
|
|
187
|
-
- `schemaVersion` gates compatibility.
|
|
188
|
-
- V1 accepts only `1`.
|
|
189
|
-
- A future migration must:
|
|
190
|
-
1. read old files,
|
|
191
|
-
2. write new files atomically,
|
|
192
|
-
3. keep a backup,
|
|
193
|
-
4. report counts,
|
|
194
|
-
5. never delete the old file until the new one is verified.
|
|
195
|
-
|
|
196
|
-
V1 implements no migration.
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
## 11. What must never be stored
|
|
201
|
-
|
|
202
|
-
- Passwords, tokens, private keys, kubeconfigs.
|
|
203
|
-
- Raw command output or logs.
|
|
204
|
-
- Copy of credential values.
|
|
205
|
-
- Session conversation content.
|
|
206
|
-
|
|
207
|
-
A violation found in validation is reported as `RECORD_INVALID` with the field path but without echoing the value.
|
|
208
|
-
|
|
209
|
-
---
|
|
210
|
-
|
|
211
|
-
## 12. Concurrency
|
|
212
|
-
|
|
213
|
-
- Writers are serialized in-process; the plugin is one Host process per profile.
|
|
214
|
-
- Multi-process writers are last-write-wins; no file locks in V1.
|
|
215
|
-
- Readers never block writers.
|
|
216
|
-
- A write that fails validation leaves the previous file untouched.
|
|
217
|
-
|
|
218
|
-
---
|
|
219
|
-
|
|
220
|
-
## 13. Repository hygiene
|
|
221
|
-
|
|
222
|
-
- `data/` is git-ignored.
|
|
223
|
-
- The repository ships no registry data, only schemas, examples in docs, and tests fixtures.
|
|
224
|
-
- Test fixtures live under `tests/fixtures/` and contain no real hostnames, IPs or URLs.
|
|
1
|
+
# Storage Contract
|
|
2
|
+
|
|
3
|
+
Status: normative for V1.
|
|
4
|
+
|
|
5
|
+
Durable registry data is a directory of YAML files. Nothing else is authoritative.
|
|
6
|
+
|
|
7
|
+
Related: [data-model.md](./data-model.md), [design.md](./design.md) §5.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. Location
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
<dataDir>/
|
|
15
|
+
├── environments/{environmentId}.yaml
|
|
16
|
+
├── services/{serviceId}.yaml
|
|
17
|
+
├── deployments/{deploymentId}.yaml
|
|
18
|
+
├── rules/{ruleProfileId}.yaml
|
|
19
|
+
├── operations/{bindingId}.yaml
|
|
20
|
+
├── sessions/{sessionId}.json
|
|
21
|
+
└── .backups/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 1.1 Resolving `dataDir`
|
|
25
|
+
|
|
26
|
+
Precedence:
|
|
27
|
+
|
|
28
|
+
1. Plugin config `dataDir`, when set (absolute path or path relative to the profile directory).
|
|
29
|
+
2. `profileContext.dir` → `<dir>/data/dsh-env-manager`.
|
|
30
|
+
3. `$DSH_PROFILE_DIR/data/dsh-env-manager`.
|
|
31
|
+
4. `<working directory>/data/dsh-env-manager` as a last resort for development only.
|
|
32
|
+
|
|
33
|
+
The chosen path is memoized, reported once at startup, and shown in the UI overview. It
|
|
34
|
+
is never derived from model input. Resolution order and fallbacks are implemented in
|
|
35
|
+
`src/storage/paths.ts` (detailed-design §4.1).
|
|
36
|
+
|
|
37
|
+
### 1.2 Creation
|
|
38
|
+
|
|
39
|
+
- The directory tree is created on first use.
|
|
40
|
+
- A missing directory is not an error; an unwritable directory is an error with `STORAGE_UNWRITABLE`.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 2. File rules
|
|
45
|
+
|
|
46
|
+
| Rule | Value |
|
|
47
|
+
|---|---|
|
|
48
|
+
| Encoding | UTF-8, no BOM |
|
|
49
|
+
| Line endings | LF on write; CRLF tolerated on read |
|
|
50
|
+
| Format | YAML 1.2 |
|
|
51
|
+
| Extension | `.yaml` for records, `.json` for session state |
|
|
52
|
+
| Name | `{id}.yaml`, where `id` matches `^[a-z0-9][a-z0-9-]{0,62}$` |
|
|
53
|
+
| Extra files | Ignored unless they match the extension; ignored files are not deleted |
|
|
54
|
+
|
|
55
|
+
A record file whose `id` differs from its filename is reported by `env_validate` and treated as invalid on load.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 3. Record envelope
|
|
60
|
+
|
|
61
|
+
Every record carries:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
id: string
|
|
65
|
+
schemaVersion: 1
|
|
66
|
+
createdAt: 2026-11-01T03:00:00.000Z
|
|
67
|
+
updatedAt: 2026-11-01T03:00:00.000Z
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- `createdAt` is set by storage on create.
|
|
71
|
+
- `updatedAt` is set by storage on every successful write.
|
|
72
|
+
- A write input may include both fields; storage overrides them. `createdAt` is
|
|
73
|
+
preserved from the existing file on update, so a caller cannot rewrite history.
|
|
74
|
+
- The stored record always contains both fields.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 4. Atomic write protocol
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
1. Serialize the record to YAML.
|
|
82
|
+
2. Validate the serialized document by parsing it back and running schema validation.
|
|
83
|
+
3. Open `.${id}.${pid}.${randomUUID()}.tmp` in the target directory.
|
|
84
|
+
4. Write UTF-8, fsync, close.
|
|
85
|
+
5. Copy the previous file into `.backups/<kind>/<id>/<timestamp>.yaml`, prune to 5.
|
|
86
|
+
6. Rename over the target (atomic on the same volume).
|
|
87
|
+
7. On a caught failure before rename, delete the temp file and leave the target intact.
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Constraints:
|
|
91
|
+
|
|
92
|
+
- Never write directly to the target file.
|
|
93
|
+
- Never leave a temp file behind on success or on a caught failure. A crash can leave
|
|
94
|
+
one; startup removes `*.tmp` older than one hour.
|
|
95
|
+
- A backup failure does not fail the write; it is reported as a warning.
|
|
96
|
+
- Never delete a record file that failed to parse; surface a diagnostic instead.
|
|
97
|
+
- Storage does not reload the registry; the application layer does after a successful
|
|
98
|
+
write.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 5. Read behavior
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
1. Enumerate `*.yaml` in the directory.
|
|
106
|
+
2. Parse each file.
|
|
107
|
+
3. Schema-validate.
|
|
108
|
+
4. On parse error: record `RECORD_INVALID` diagnostic, skip the file.
|
|
109
|
+
5. On unknown schemaVersion: record `SCHEMA_UNSUPPORTED` warning, skip the file.
|
|
110
|
+
6. Build an in-memory map keyed by id.
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Reads never modify files. A failed file stays on disk for the user to fix.
|
|
114
|
+
|
|
115
|
+
If a directory is unreadable, the loader returns an empty map plus an error diagnostic; tools still serve whatever other directories loaded.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 6. Registry lifecycle
|
|
120
|
+
|
|
121
|
+
- V1 loads the registry at the start of every application request.
|
|
122
|
+
- Concurrent requests share one in-flight load.
|
|
123
|
+
- A successful write triggers a reload before the request returns.
|
|
124
|
+
- The registry is an in-memory snapshot; it is never persisted.
|
|
125
|
+
- V1 has no index files and no watcher. A scan of a few hundred small YAML files is
|
|
126
|
+
fast enough; an mtime-keyed cache is added only with measured need.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 7. Session state
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
sessions/{sessionId}.json
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"schemaVersion": 1,
|
|
139
|
+
"sessionId": "session-abc",
|
|
140
|
+
"defaultEnvironmentId": "test-a",
|
|
141
|
+
"updatedAt": "2026-11-01T03:00:00.000Z"
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Rules:
|
|
146
|
+
|
|
147
|
+
- Written atomically with the same protocol as records.
|
|
148
|
+
- A missing file means "no default".
|
|
149
|
+
- A corrupt file is treated as "no default" and reported as `persisted: false`; it is
|
|
150
|
+
not deleted, so the user can inspect it.
|
|
151
|
+
- A process-local cache mirrors the last value so a failed write still works until
|
|
152
|
+
restart (detailed-design §9).
|
|
153
|
+
- Session files are not registry records and are never scanned into the registry.
|
|
154
|
+
- V1 uses this file store; a projection over the durable session log is a later
|
|
155
|
+
refinement (detailed-design §9).
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 8. Referential integrity
|
|
160
|
+
|
|
161
|
+
Storage itself does not enforce cross-record references; the registry does, on load and on write:
|
|
162
|
+
|
|
163
|
+
- Broken references are reported by `env_validate`.
|
|
164
|
+
- On load, an invalid reference produces a warning; the record stays usable for name lookups.
|
|
165
|
+
- On write, an invalid reference is rejected (`RECORD_INVALID` with details).
|
|
166
|
+
|
|
167
|
+
This split keeps a single bad file from making the whole registry unusable.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 9. Backups
|
|
172
|
+
|
|
173
|
+
V1 keeps one rolling backup per write:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
.backups/{kind}/{id}/{timestamp}.yaml
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- At most 5 backups per record; older ones are pruned.
|
|
180
|
+
- Backups are best-effort: a backup failure does not fail the write, but emits a warning.
|
|
181
|
+
- Backups are not a history feature. They exist to recover from an accidental overwrite.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 10. Migration
|
|
186
|
+
|
|
187
|
+
- `schemaVersion` gates compatibility.
|
|
188
|
+
- V1 accepts only `1`.
|
|
189
|
+
- A future migration must:
|
|
190
|
+
1. read old files,
|
|
191
|
+
2. write new files atomically,
|
|
192
|
+
3. keep a backup,
|
|
193
|
+
4. report counts,
|
|
194
|
+
5. never delete the old file until the new one is verified.
|
|
195
|
+
|
|
196
|
+
V1 implements no migration.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 11. What must never be stored
|
|
201
|
+
|
|
202
|
+
- Passwords, tokens, private keys, kubeconfigs.
|
|
203
|
+
- Raw command output or logs.
|
|
204
|
+
- Copy of credential values.
|
|
205
|
+
- Session conversation content.
|
|
206
|
+
|
|
207
|
+
A violation found in validation is reported as `RECORD_INVALID` with the field path but without echoing the value.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 12. Concurrency
|
|
212
|
+
|
|
213
|
+
- Writers are serialized in-process; the plugin is one Host process per profile.
|
|
214
|
+
- Multi-process writers are last-write-wins; no file locks in V1.
|
|
215
|
+
- Readers never block writers.
|
|
216
|
+
- A write that fails validation leaves the previous file untouched.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 13. Repository hygiene
|
|
221
|
+
|
|
222
|
+
- `data/` is git-ignored.
|
|
223
|
+
- The repository ships no registry data, only schemas, examples in docs, and tests fixtures.
|
|
224
|
+
- Test fixtures live under `tests/fixtures/` and contain no real hostnames, IPs or URLs.
|