@gregiteen/ssss-cli 0.8.0 → 0.9.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/CHANGELOG.md +55 -4
- package/README.md +42 -84
- package/VERSION +1 -1
- package/conformance/README.md +1 -1
- package/conformance/fixtures.json +4 -48
- package/conformance/reference-bundle.ucw.json +22 -21
- package/docs/help/bundle.md +2 -2
- package/docs/help/overview.md +9 -6
- package/docs/help/semantic.md +5 -4
- package/docs/ssss-spec.md +42 -86
- package/package.json +22 -3
- package/registry/core.json +22 -29
- package/scripts/build-reference-bundle.mjs +0 -20
- package/scripts/cmd-adapter.mjs +29 -0
- package/scripts/cmd-import.mjs +1 -1
- package/scripts/cmd-migrate.mjs +26 -0
- package/scripts/cmd-new.mjs +5 -5
- package/scripts/cmd-primitive.mjs +48 -0
- package/scripts/cmd-registry.mjs +25 -0
- package/scripts/cmd-semantic.mjs +6 -8
- package/scripts/conformance-09.mjs +331 -0
- package/scripts/conformance.mjs +153 -186
- package/scripts/generate-sbom.mjs +96 -0
- package/scripts/phase9-cross-host-corpus.mjs +223 -0
- package/scripts/ssss.mjs +8 -2
- package/skills/ssss/SKILL.md +32 -208
- package/skills/ssss/evals/evals.json +3 -3
- package/skills/ssss/references/contract-reference.md +7 -8
- package/skills/ssss/scripts/validate-schema.mjs +1 -44
- package/src/authorization.mjs +62 -0
- package/src/bundle.mjs +41 -5
- package/src/engine.mjs +101 -503
- package/src/events.mjs +155 -0
- package/src/guard.mjs +32 -0
- package/src/http.mjs +26 -0
- package/src/idempotency.mjs +55 -0
- package/src/kernel.mjs +260 -0
- package/src/leases.mjs +173 -0
- package/src/primitive.mjs +227 -0
- package/src/projections.mjs +133 -0
- package/src/registry.mjs +190 -39
- package/src/semantic.mjs +124 -316
- package/src/ui.mjs +100 -0
- package/src/validator.mjs +87 -0
- package/src/vfs.mjs +203 -0
- package/types/kernel.d.ts +48 -0
- package/docs/help/localization.md +0 -43
- package/scripts/cmd-localize.mjs +0 -44
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Phase 9 — shared cross-host command corpus.
|
|
4
|
+
*
|
|
5
|
+
* Runs a normalized set of Operation Contract envelopes through the package
|
|
6
|
+
* kernel (MemoryVfs + memory durable stores) and prints a machine-readable
|
|
7
|
+
* report. Hosts can re-run the same envelopes via their bridges and compare
|
|
8
|
+
* success/valid/type verdicts against this reference.
|
|
9
|
+
*/
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import os from 'node:os';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import crypto from 'node:crypto';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { createKernel, canonicalRequestHash } from '../src/kernel.mjs';
|
|
16
|
+
import { FileSystemVfs } from '../src/vfs.mjs';
|
|
17
|
+
import { MemoryEventStore } from '../src/events.mjs';
|
|
18
|
+
import { MemoryIdempotencyStore } from '../src/idempotency.mjs';
|
|
19
|
+
import { MemoryLeaseStore } from '../src/leases.mjs';
|
|
20
|
+
import { createValidator } from '../src/validator.mjs';
|
|
21
|
+
import { loadRegistries } from '../src/registry.mjs';
|
|
22
|
+
|
|
23
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
|
|
25
|
+
function ruleContent(name) {
|
|
26
|
+
return [
|
|
27
|
+
'---',
|
|
28
|
+
'type: rule',
|
|
29
|
+
`title: ${name}`,
|
|
30
|
+
`description: Phase 9 corpus rule ${name}`,
|
|
31
|
+
'timestamp: 2026-07-10T00:00:00Z',
|
|
32
|
+
`name: ${name}`,
|
|
33
|
+
'---',
|
|
34
|
+
'',
|
|
35
|
+
`Body for ${name}.`,
|
|
36
|
+
'',
|
|
37
|
+
].join('\n');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function spanishRuleContent() {
|
|
41
|
+
return [
|
|
42
|
+
'---',
|
|
43
|
+
'type: rule',
|
|
44
|
+
'title: Bienvenida',
|
|
45
|
+
'description: Regla estructural de corpus multilingüe',
|
|
46
|
+
'timestamp: 2026-07-10T00:00:00Z',
|
|
47
|
+
'name: bienvenida',
|
|
48
|
+
'---',
|
|
49
|
+
'',
|
|
50
|
+
'Cuerpo en español.',
|
|
51
|
+
'',
|
|
52
|
+
].join('\n');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const CORPUS = [
|
|
56
|
+
{
|
|
57
|
+
id: 'corpus-rule-create',
|
|
58
|
+
envelope: {
|
|
59
|
+
type: 'operation',
|
|
60
|
+
workspace_id: 'ws-corpus',
|
|
61
|
+
idempotency_key: 'corpus-rule-1',
|
|
62
|
+
path: 'rules/welcome.md',
|
|
63
|
+
content: ruleContent('welcome'),
|
|
64
|
+
},
|
|
65
|
+
expect: { success: true, valid: true },
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'corpus-rule-idempotent-replay',
|
|
69
|
+
envelope: {
|
|
70
|
+
type: 'operation',
|
|
71
|
+
workspace_id: 'ws-corpus',
|
|
72
|
+
idempotency_key: 'corpus-rule-1',
|
|
73
|
+
path: 'rules/welcome.md',
|
|
74
|
+
content: ruleContent('welcome'),
|
|
75
|
+
},
|
|
76
|
+
expect: { success: true, valid: true, replay: true },
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'corpus-rule-idempotent-conflict',
|
|
80
|
+
envelope: {
|
|
81
|
+
type: 'operation',
|
|
82
|
+
workspace_id: 'ws-corpus',
|
|
83
|
+
idempotency_key: 'corpus-rule-1',
|
|
84
|
+
path: 'rules/welcome.md',
|
|
85
|
+
content: ruleContent('welcome-changed'),
|
|
86
|
+
},
|
|
87
|
+
expect: { success: false },
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 'corpus-dry-run',
|
|
91
|
+
envelope: {
|
|
92
|
+
type: 'operation',
|
|
93
|
+
workspace_id: 'ws-corpus',
|
|
94
|
+
idempotency_key: 'corpus-dry-1',
|
|
95
|
+
path: 'rules/dry.md',
|
|
96
|
+
content: ruleContent('dry'),
|
|
97
|
+
dry_run: true,
|
|
98
|
+
},
|
|
99
|
+
expect: { success: true, valid: true, dry_run: true },
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'corpus-multilingual-rule',
|
|
103
|
+
envelope: {
|
|
104
|
+
type: 'operation',
|
|
105
|
+
workspace_id: 'ws-corpus',
|
|
106
|
+
idempotency_key: 'corpus-es-1',
|
|
107
|
+
path: 'rules/bienvenida.md',
|
|
108
|
+
content: spanishRuleContent(),
|
|
109
|
+
},
|
|
110
|
+
expect: { success: true, valid: true },
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: 'corpus-missing-actor-denied',
|
|
114
|
+
envelope: {
|
|
115
|
+
type: 'operation',
|
|
116
|
+
workspace_id: 'ws-corpus',
|
|
117
|
+
idempotency_key: 'corpus-no-actor',
|
|
118
|
+
path: 'rules/no-actor.md',
|
|
119
|
+
content: ruleContent('no-actor'),
|
|
120
|
+
},
|
|
121
|
+
principal: null,
|
|
122
|
+
expect: { success: false },
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
function principal() {
|
|
127
|
+
return {
|
|
128
|
+
id: 'phase9:corpus',
|
|
129
|
+
kind: 'system',
|
|
130
|
+
workspaceIds: ['ws-corpus'],
|
|
131
|
+
capabilities: ['*:*'],
|
|
132
|
+
authentication: { provider: 'phase9-corpus', assurance: 'system' },
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function main() {
|
|
137
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ssss-phase9-corpus-'));
|
|
138
|
+
const registrySet = loadRegistries();
|
|
139
|
+
const validator = createValidator({ registrySet });
|
|
140
|
+
const kernel = createKernel({
|
|
141
|
+
vfs: new FileSystemVfs(root),
|
|
142
|
+
eventStore: new MemoryEventStore(),
|
|
143
|
+
leaseStore: new MemoryLeaseStore(),
|
|
144
|
+
idempotencyStore: new MemoryIdempotencyStore(),
|
|
145
|
+
validator,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const results = [];
|
|
149
|
+
for (const caseDef of CORPUS) {
|
|
150
|
+
const p =
|
|
151
|
+
caseDef.principal === null
|
|
152
|
+
? null
|
|
153
|
+
: caseDef.principal || principal();
|
|
154
|
+
let result;
|
|
155
|
+
try {
|
|
156
|
+
if (!p) {
|
|
157
|
+
// Simulate host fail-closed before kernel when identity missing
|
|
158
|
+
result = {
|
|
159
|
+
success: false,
|
|
160
|
+
validation: { valid: false, errors: ['Missing actor'] },
|
|
161
|
+
};
|
|
162
|
+
} else {
|
|
163
|
+
result = await kernel.execute(caseDef.envelope, { principal: p });
|
|
164
|
+
}
|
|
165
|
+
} catch (error) {
|
|
166
|
+
result = {
|
|
167
|
+
success: false,
|
|
168
|
+
validation: { valid: false, errors: [error.message] },
|
|
169
|
+
error: error.message,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const verdict = {
|
|
174
|
+
id: caseDef.id,
|
|
175
|
+
success: !!result.success,
|
|
176
|
+
valid: !!result.validation?.valid,
|
|
177
|
+
replay: !!result.replay,
|
|
178
|
+
dry_run: !!result.dry_run || !!caseDef.envelope.dry_run,
|
|
179
|
+
type: result.validation?.type || null,
|
|
180
|
+
errors: result.validation?.errors || [],
|
|
181
|
+
request_hash: canonicalRequestHash(caseDef.envelope),
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const ok =
|
|
185
|
+
(caseDef.expect.success === undefined ||
|
|
186
|
+
verdict.success === caseDef.expect.success) &&
|
|
187
|
+
(caseDef.expect.valid === undefined ||
|
|
188
|
+
verdict.valid === caseDef.expect.valid) &&
|
|
189
|
+
(caseDef.expect.replay === undefined ||
|
|
190
|
+
verdict.replay === caseDef.expect.replay) &&
|
|
191
|
+
(caseDef.expect.dry_run === undefined ||
|
|
192
|
+
verdict.dry_run === caseDef.expect.dry_run);
|
|
193
|
+
|
|
194
|
+
results.push({ ...verdict, passed: ok });
|
|
195
|
+
console.log(`${ok ? '✅' : '❌'} ${caseDef.id} success=${verdict.success} valid=${verdict.valid}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const report = {
|
|
199
|
+
suite: 'phase9-cross-host-corpus',
|
|
200
|
+
package: '@gregiteen/ssss-cli',
|
|
201
|
+
version: JSON.parse(
|
|
202
|
+
fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8'),
|
|
203
|
+
).version,
|
|
204
|
+
generated_at: new Date().toISOString(),
|
|
205
|
+
passed: results.every((r) => r.passed),
|
|
206
|
+
results,
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const outDir = path.join(__dirname, '../artifacts');
|
|
210
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
211
|
+
const outFile = path.join(outDir, 'phase9-cross-host-corpus.json');
|
|
212
|
+
fs.writeFileSync(outFile, `${JSON.stringify(report, null, 2)}\n`);
|
|
213
|
+
console.log(`\nReport: ${outFile}`);
|
|
214
|
+
console.log(`Overall: ${report.passed ? 'PASS' : 'FAIL'} (${results.filter((r) => r.passed).length}/${results.length})`);
|
|
215
|
+
|
|
216
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
217
|
+
process.exit(report.passed ? 0 : 1);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
main().catch((error) => {
|
|
221
|
+
console.error(error);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
});
|
package/scripts/ssss.mjs
CHANGED
|
@@ -36,9 +36,12 @@ Vault → bundle → tenant lifecycle:
|
|
|
36
36
|
import <bundle> Replay a bundle/plan into a target vault (idempotent).
|
|
37
37
|
|
|
38
38
|
Authoring & conformance:
|
|
39
|
+
primitive <verb> Create, validate, inspect, migrate, or emit types.
|
|
40
|
+
registry <verb> Compose, lock, or verify an effective registry.
|
|
41
|
+
adapter conformance Run machine-readable adapter contract suites.
|
|
42
|
+
migrate 0.8-to-0.9 Diagnose and plan a non-destructive 0.9 migration.
|
|
39
43
|
autolink [dir] Generate OKF wiki links across a vault.
|
|
40
44
|
semantic <vault> Build/query a deterministic semantic projection (§11.9).
|
|
41
|
-
localize <vault> Materialize approved locale overlays outside the vault.
|
|
42
45
|
conformance Run the canonical conformance suite (spec §12).
|
|
43
46
|
--engine | --endpoint <url> [--token <pat>]
|
|
44
47
|
|
|
@@ -63,7 +66,10 @@ const MODULES = {
|
|
|
63
66
|
provision: './cmd-provision.mjs',
|
|
64
67
|
import: './cmd-import.mjs',
|
|
65
68
|
semantic: './cmd-semantic.mjs',
|
|
66
|
-
|
|
69
|
+
primitive: './cmd-primitive.mjs',
|
|
70
|
+
registry: './cmd-registry.mjs',
|
|
71
|
+
adapter: './cmd-adapter.mjs',
|
|
72
|
+
migrate: './cmd-migrate.mjs',
|
|
67
73
|
help: './cmd-help.mjs',
|
|
68
74
|
};
|
|
69
75
|
|
package/skills/ssss/SKILL.md
CHANGED
|
@@ -1,225 +1,49 @@
|
|
|
1
1
|
---
|
|
2
2
|
type: skill
|
|
3
|
-
title: SSSS
|
|
3
|
+
title: SSSS Protocol Reference
|
|
4
4
|
name: ssss
|
|
5
|
-
description: "
|
|
6
|
-
timestamp: 2026-07-
|
|
5
|
+
description: "Use this skill when reading, writing, parsing, validating, or extending SSSS -- the Structured Semantic Syntax System: the SSSS Core Contract API, VFS-native primitives, operation/patch/event envelopes, leases, and projections. MANDATORY: You MUST read the full SKILL.md file before executing."
|
|
6
|
+
timestamp: 2026-07-15T00:00:00Z
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
# SSSS — Structured Semantic Syntax System
|
|
9
|
+
# SSSS — Structured Semantic Syntax System Reference
|
|
10
10
|
|
|
11
|
-
SSSS is a
|
|
12
|
-
state is typed Markdown plus append-only events. Databases, indexes, queues,
|
|
13
|
-
dashboards, and search stores are host projections unless explicitly documented
|
|
14
|
-
as external resources.
|
|
11
|
+
You are operating in a repository that implements, extends, or relies on the **Structured Semantic Syntax System (SSSS)**. SSSS is a database-free, Markdown-first schema and mutation contract for AI-agent state.
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
This skill provides the normative rules for interacting with an SSSS-compliant vault or host engine (like Total Recall).
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
## ⚠️ The VFS-First Mandate (Absolute Rule)
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
`registry/core.json`, and `docs/ssss-spec.md` when they exist.
|
|
22
|
-
2. Treat `registry/core.json` as the machine-readable primitive contract and
|
|
23
|
-
`docs/ssss-spec.md` as the normative explanation.
|
|
24
|
-
3. Treat `src/engine.mjs`, `src/runtime.mjs`, `src/semantic.mjs`,
|
|
25
|
-
`src/bundle.mjs`, `src/registry.mjs`, and `src/frontmatter.mjs` as the
|
|
26
|
-
reference behavior.
|
|
27
|
-
4. Treat host schemas and services as adapters or extension registries. Never
|
|
28
|
-
promote host-only fields into the core standard without an explicit spec and
|
|
29
|
-
registry change.
|
|
30
|
-
5. Read the current package name and version instead of hard-coding an alias.
|
|
31
|
-
In this checkout the published package is `@gregiteen/ssss-cli`; the CLI is
|
|
32
|
-
`ssss`.
|
|
17
|
+
**NEVER use raw database inserts, updates, or deletes to mutate application state in an SSSS environment!**
|
|
33
18
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
19
|
+
All persistent state (memories, agents, workflows, tasks) lives in the Virtual File System (VFS) as Markdown files with YAML frontmatter. The VFS is the absolute source of truth.
|
|
20
|
+
- If you are interacting via CLI: Use `npx total-recall remember` or `npx total-recall recall`.
|
|
21
|
+
- If you are building host code: You must route mutations through the SSSS **Operation Contract** engine (which handles idempotency, leasing, and semantic indexing), or use the provided API wrappers. Do not bypass the engine to write files directly.
|
|
37
22
|
|
|
38
|
-
##
|
|
23
|
+
## SSSS Core Concepts
|
|
39
24
|
|
|
40
|
-
|
|
25
|
+
### 1. Primitives (The Data Model)
|
|
26
|
+
Data in SSSS is defined by standard primitives (e.g. `workflow`, `assistant`, `skill`, `memory`). Each primitive has a defined schema (in `registry/core.json` or extension registries) and belongs to a specific Portability Class:
|
|
27
|
+
- `structural`: Logic and system prompts (e.g. rules, workflows). Included in export templates.
|
|
28
|
+
- `tenant_private`: User data (e.g. chats, tasks). NEVER included in templates.
|
|
29
|
+
- `resource_bound`: Requires external setup (e.g. Twilio numbers). Exported only as a requirement.
|
|
41
30
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
6. Skills, examples, README prose, and copied mirrors.
|
|
31
|
+
### 2. The Operation Contract (Envelopes)
|
|
32
|
+
When an SSSS engine processes a write, it receives an **Envelope**:
|
|
33
|
+
- `operation`: Creates or completely replaces a document.
|
|
34
|
+
- `patch`: Merges partial data into a document (e.g. updating task status).
|
|
35
|
+
- `event`: Appends an immutable log entry to a document.
|
|
36
|
+
- `delete`: Tombstones a replace-type document.
|
|
49
37
|
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
### 3. Idempotency and Leases
|
|
39
|
+
- **Idempotency**: All mutations must provide an `idempotency_key`. The engine ensures duplicate submissions do not result in duplicate state.
|
|
40
|
+
- **Leases**: Background tasks and workflows use the Lease store to acquire temporary locks on documents to prevent race conditions during execution.
|
|
52
41
|
|
|
53
|
-
|
|
42
|
+
### 4. Bundles (.ucw)
|
|
43
|
+
An SSSS vault can be packaged into a `.ucw` (Universal Containerized Workspace) bundle. A bundle is a portable snapshot containing a manifest, deterministic file paths, and content hashes for cryptographic integrity.
|
|
54
44
|
|
|
55
|
-
|
|
56
|
-
documents require the universal fields:
|
|
45
|
+
## Validation
|
|
57
46
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- `timestamp`
|
|
62
|
-
|
|
63
|
-
Primitive-specific required fields are additive. An SSSS-managed skill also
|
|
64
|
-
requires `name`; a schema-v2 memory has knowledge-graph fields; a workflow
|
|
65
|
-
requires `name`.
|
|
66
|
-
|
|
67
|
-
Unknown frontmatter fields must be preserved for forward compatibility. Never
|
|
68
|
-
drop a nested map, array, or unknown field during parse/serialize or patch.
|
|
69
|
-
|
|
70
|
-
Registry declarations are executable contract. Enforce `required_fields`,
|
|
71
|
-
`required_when`, `enums`, `patterns`, `immutable_fields`, `references`,
|
|
72
|
-
`append_only`, and `portability`. Reject malformed extension definitions,
|
|
73
|
-
symlinked registry files, and core or sibling type collisions during load.
|
|
74
|
-
|
|
75
|
-
## Mutation Contract
|
|
76
|
-
|
|
77
|
-
Agent-generated mutations flow through the Operation Contract:
|
|
78
|
-
|
|
79
|
-
```text
|
|
80
|
-
validate envelope
|
|
81
|
-
-> verify safe workspace/idempotency/actor identifiers
|
|
82
|
-
-> resolve and contain the target path
|
|
83
|
-
-> replay or reject the idempotency key + request hash
|
|
84
|
-
-> authorize with verified actor identity (fail closed)
|
|
85
|
-
-> validate any active lease (fail closed)
|
|
86
|
-
-> validate universal + primitive-specific content
|
|
87
|
-
-> commit atomically
|
|
88
|
-
-> append the audit event
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
The mutation envelopes are:
|
|
92
|
-
|
|
93
|
-
- `operation` — create or fully replace a replace-type document.
|
|
94
|
-
- `patch` — merge an existing replace-type document without changing `type`.
|
|
95
|
-
- `event` — append an immutable event record.
|
|
96
|
-
- `delete` — remove a replace-type document and emit an audit event; reject
|
|
97
|
-
append-type targets.
|
|
98
|
-
|
|
99
|
-
Use `dry_run: true` for model-generated preflight. Idempotency is scoped by the
|
|
100
|
-
effective request, not the key alone: the same request replays, while the same
|
|
101
|
-
workspace/key with a different request hash is a conflict.
|
|
102
|
-
|
|
103
|
-
## Append, Lease, and Path Safety
|
|
104
|
-
|
|
105
|
-
- `conversation` and `run` are append-only. Preserve prior bytes and append new
|
|
106
|
-
records; never rewrite or delete them.
|
|
107
|
-
- Events are immutable.
|
|
108
|
-
- Paths must be relative, contained vault paths. Reject absolute paths,
|
|
109
|
-
backslashes, null bytes, empty segments, `.`/`..`, directory targets, and
|
|
110
|
-
symlink escapes.
|
|
111
|
-
- Leases are actor-owned, operation-linked, expiring locks. Missing, mismatched,
|
|
112
|
-
malformed, or unreadable lease state fails closed.
|
|
113
|
-
- Hosts must overwrite caller-supplied actor data with verified session identity
|
|
114
|
-
before authorization.
|
|
115
|
-
|
|
116
|
-
## Workflow Runtime
|
|
117
|
-
|
|
118
|
-
Workflow frontmatter owns the schedule. Cron, daemon, webhook, file watcher, and
|
|
119
|
-
event-loop processes are wake-up mechanisms, not a second scheduling database.
|
|
120
|
-
|
|
121
|
-
Use `@gregiteen/ssss-cli/runtime` to deterministically derive the trigger event,
|
|
122
|
-
task, and run envelopes. Duplicate ticks must replay idempotently. Queues and
|
|
123
|
-
task dashboards are disposable projections over workflow state and events.
|
|
124
|
-
|
|
125
|
-
## Bundles and Portability
|
|
126
|
-
|
|
127
|
-
Every document primitive resolves to one portability class:
|
|
128
|
-
|
|
129
|
-
- `structural` — reusable model shipped in templates and sale bundles.
|
|
130
|
-
- `tenant_private` — operator/customer runtime data; excluded from template and
|
|
131
|
-
sale exports.
|
|
132
|
-
- `resource_bound` — exported only as a requirement declaration; never leak the
|
|
133
|
-
seller's bound resource value.
|
|
134
|
-
|
|
135
|
-
Bundle paths must be unique, safe, and symlink-free. Validate content hashes,
|
|
136
|
-
required extensions, primitive inventory, core version, parameters, and link
|
|
137
|
-
integrity before import. Preflight the complete plan before the first commit so a
|
|
138
|
-
late invalid envelope cannot leave a partial install. Provisioning produces
|
|
139
|
-
deterministic Operation Contract envelopes; re-import must be a no-op.
|
|
140
|
-
|
|
141
|
-
## Semantic Search and Localization
|
|
142
|
-
|
|
143
|
-
Treat semantic indexes and localized trees as disposable projections. Use
|
|
144
|
-
`@gregiteen/ssss-cli/semantic`, `ssss semantic`, and `ssss localize` for the
|
|
145
|
-
dependency-free reference behavior.
|
|
146
|
-
|
|
147
|
-
- Index only `structural` documents by default. Include `tenant_private` and
|
|
148
|
-
`resource_bound` sources only after an explicit authorized opt-in.
|
|
149
|
-
- Derive stable identity from `semantic_id`, then `resource`, then source path.
|
|
150
|
-
- Build edges from explicit `relations`, wiki links, and Markdown links.
|
|
151
|
-
- Keep projection output outside the source vault; reject symlinks and unsafe paths,
|
|
152
|
-
and stage the complete tree before publishing it.
|
|
153
|
-
- Model localization as a `translation` document pointing to an existing
|
|
154
|
-
structural source and its exact SHA-256 content hash.
|
|
155
|
-
- Translate only `title`, `description`, and body. Preserve types, ids, enums,
|
|
156
|
-
permissions, status, portability, relations, and paths from the source.
|
|
157
|
-
- Apply approved overlays by default. Reject stale hashes, duplicate locale/source
|
|
158
|
-
overlays, recursive translations, private sources, and immutable identity edits.
|
|
159
|
-
|
|
160
|
-
## Scope and Host Adapters
|
|
161
|
-
|
|
162
|
-
The core standard does not collapse host ownership layers. A host may implement
|
|
163
|
-
global/project or system/account/workspace overlays, but must document precedence
|
|
164
|
-
and preserve isolation. Shared system skills should be inherited through an
|
|
165
|
-
overlay rather than copied into every workspace.
|
|
166
|
-
|
|
167
|
-
When working in Total Recall, use its validated-write and memory-validator
|
|
168
|
-
adapter if those modules exist. In another host, locate its extension registry
|
|
169
|
-
and conformance bridge. Do not quote Total Recall paths as universal SSSS
|
|
170
|
-
architecture.
|
|
171
|
-
|
|
172
|
-
## Procedure for Changes
|
|
173
|
-
|
|
174
|
-
1. Classify the change: core primitive, contract behavior, runtime behavior,
|
|
175
|
-
semantic/localization behavior, bundle/provisioning behavior, projection, or
|
|
176
|
-
host extension.
|
|
177
|
-
2. Inspect the registry, spec section, implementation, fixtures, and host bridge
|
|
178
|
-
for that surface.
|
|
179
|
-
3. Make the smallest coherent change across code and canon.
|
|
180
|
-
4. Add positive, negative, replay, and invalid-path cases where applicable.
|
|
181
|
-
5. Run focused validation, then the full conformance gate.
|
|
182
|
-
6. Update skill/reference mirrors only after the executable contract is green.
|
|
183
|
-
|
|
184
|
-
## Validation
|
|
185
|
-
|
|
186
|
-
Validate a Markdown document with the dependency-free skill helper:
|
|
187
|
-
|
|
188
|
-
```bash
|
|
189
|
-
node skills/ssss/scripts/validate-schema.mjs path/to/document.md
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
In the SSSS reference repository, the required gate is:
|
|
193
|
-
|
|
194
|
-
```bash
|
|
195
|
-
npm test
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
It covers registry/engine parity, shipped-skill conformance, Operation Contract
|
|
199
|
-
fixtures, workflow runtime behavior, lease/frontmatter regressions,
|
|
200
|
-
extension-registry hardening, semantic/localization behavior,
|
|
201
|
-
bundle/provisioning round trips, and CLI smoke tests.
|
|
202
|
-
|
|
203
|
-
For host adapters, run the host's named SSSS conformance command as well. Do not
|
|
204
|
-
substitute a loose YAML parse or a generic typecheck for the SSSS gate.
|
|
205
|
-
|
|
206
|
-
## Do Not
|
|
207
|
-
|
|
208
|
-
- Do not treat an installed skill, copied spec, or README as newer than the live
|
|
209
|
-
registry and conformance suite.
|
|
210
|
-
- Do not use raw file writes for agent-generated vault mutations.
|
|
211
|
-
- Do not make a derived database/index/queue the canonical record.
|
|
212
|
-
- Do not add a primitive in prose without registry and fixture coverage.
|
|
213
|
-
- Do not translate symbolic control fields or index private content by default.
|
|
214
|
-
- Do not materialize a projection inside its source vault.
|
|
215
|
-
- Do not mix document primitives with contract envelopes.
|
|
216
|
-
- Do not claim conformance from HTTP success or file creation alone.
|
|
217
|
-
- Do not publish package names, versions, or exporter identities without reading
|
|
218
|
-
them from current package metadata.
|
|
219
|
-
|
|
220
|
-
## References
|
|
221
|
-
|
|
222
|
-
Read `references/contract-reference.md` for the compact topology, primitive
|
|
223
|
-
families, package entry points, and drift checklist. For normative detail, read
|
|
224
|
-
the exact linked section of `docs/ssss-spec.md` rather than loading a stale
|
|
225
|
-
vendored copy.
|
|
47
|
+
If you are writing tests or schemas in a host repository, ensure that:
|
|
48
|
+
1. `MemoryNodeSchema` validations provide all required SSSS v2 properties (`status`, `created`, `updated`, `last_accessed`, `source`, `decay`).
|
|
49
|
+
2. Schema changes maintain strict compatibility with the Open Knowledge Format (OKF) standard if applicable.
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
"name": "ssss-semantic-default-is-private",
|
|
29
|
-
"assertion": "The skill requires structural-only semantic
|
|
29
|
+
"assertion": "The skill requires structural-only semantic projections by default, with explicit authorization before private or resource-bound indexing.",
|
|
30
30
|
"severity": "error"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
"name": "ssss-
|
|
34
|
-
"assertion": "The skill
|
|
33
|
+
"name": "ssss-runtime-rendering-preserves-controls",
|
|
34
|
+
"assertion": "The skill requires runtime multilingual rendering and preserves all symbolic control fields.",
|
|
35
35
|
"severity": "error"
|
|
36
36
|
}
|
|
37
37
|
]
|
|
@@ -11,7 +11,7 @@ This is an operational map. The normative source is the current
|
|
|
11
11
|
| `registry/extensions/*.json` | Host/application types that cannot redefine core primitives. |
|
|
12
12
|
| `src/engine.mjs` | Operation Contract, validation, authorization, leases, idempotency, atomic commit, audit. |
|
|
13
13
|
| `src/runtime.mjs` | Workflow trigger planning and deterministic event/task/run envelopes. |
|
|
14
|
-
| `src/semantic.mjs` | Deterministic
|
|
14
|
+
| `src/semantic.mjs` | Deterministic records/edges, multilingual embeddings, hybrid retrieval, and invariant rendering. |
|
|
15
15
|
| `src/bundle.mjs` | Export, validate, provision, import, portability filtering, link/hash integrity. |
|
|
16
16
|
| `src/registry.mjs` | Registry loading and type/portability resolution. |
|
|
17
17
|
| `src/frontmatter.mjs` | Dependency-free parse/serialize with unknown-field preservation. |
|
|
@@ -35,8 +35,7 @@ document types.
|
|
|
35
35
|
Current core document families include knowledge (`memory`), capability
|
|
36
36
|
(`skill`, `page`), governance (`rule`, `security_role`), work (`task`,
|
|
37
37
|
`workflow`), actors/catalog (`assistant`, `model`), transcripts (`conversation`,
|
|
38
|
-
`run`),
|
|
39
|
-
`release`).
|
|
38
|
+
`run`), and lifecycle/meta (`conflict`, `migration`, `release`, `primitive`).
|
|
40
39
|
|
|
41
40
|
The contract primitives are `operation`, `patch`, `event`, `delete`, and
|
|
42
41
|
`lease`.
|
|
@@ -77,15 +76,15 @@ For a bundle:
|
|
|
77
76
|
7. Internal links resolve after remapping.
|
|
78
77
|
8. Re-import replays without new commits.
|
|
79
78
|
|
|
80
|
-
For a semantic
|
|
79
|
+
For a multilingual semantic projection:
|
|
81
80
|
|
|
82
81
|
1. Records and index hashes are deterministic for identical inputs.
|
|
83
82
|
2. Stable identity, tokens, content hashes, portability, and graph edges are retained.
|
|
84
83
|
3. Private and resource-bound documents are excluded unless explicitly authorized.
|
|
85
|
-
4.
|
|
86
|
-
5.
|
|
87
|
-
6.
|
|
88
|
-
7.
|
|
84
|
+
4. Embedding records retain model identity and vector dimensions.
|
|
85
|
+
5. Lexical and semantic evidence remain separately inspectable.
|
|
86
|
+
6. Runtime rendering preserves all symbolic control fields.
|
|
87
|
+
7. Language selection never widens authorization or portability scope.
|
|
89
88
|
|
|
90
89
|
## Drift checklist
|
|
91
90
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import crypto from 'node:crypto';
|
|
5
4
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
5
|
|
|
7
6
|
const FALLBACK_UNIVERSAL = ['type', 'title', 'description', 'timestamp'];
|
|
@@ -20,7 +19,7 @@ const FALLBACK_REQUIRED = {
|
|
|
20
19
|
page: ['slug', 'name', 'sandbox_entry'],
|
|
21
20
|
migration: ['migration_id', 'from_version', 'to_version', 'status'],
|
|
22
21
|
release: ['release_id', 'version', 'schema_version', 'summary', 'released_at'],
|
|
23
|
-
|
|
22
|
+
primitive: ['primitive_id', 'namespace', 'version', 'name', 'mutation', 'portability', 'scopes', 'fields'],
|
|
24
23
|
};
|
|
25
24
|
const CONTRACT_TYPES = new Set(['operation', 'patch', 'event', 'delete', 'lease']);
|
|
26
25
|
const APPEND_TYPES = new Set(['conversation', 'run']);
|
|
@@ -120,46 +119,6 @@ function isSafeReferencePath(value) {
|
|
|
120
119
|
value.split('/').every((segment) => segment && segment !== '.' && segment !== '..');
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
function inferVaultRoot(target) {
|
|
124
|
-
let cursor = path.dirname(target);
|
|
125
|
-
while (path.dirname(cursor) !== cursor) {
|
|
126
|
-
if (path.basename(cursor) === 'translations') return path.dirname(cursor);
|
|
127
|
-
cursor = path.dirname(cursor);
|
|
128
|
-
}
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async function validateTranslationReference(target, data, registry, kernelRoot, errors, warnings) {
|
|
133
|
-
if (data.type !== 'translation' || isEmpty(data.source_path)) return;
|
|
134
|
-
if (!isSafeReferencePath(data.source_path)) {
|
|
135
|
-
errors.push(`Field 'source_path' must be a safe vault-relative Markdown path.`);
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
const vaultRoot = inferVaultRoot(target);
|
|
139
|
-
if (!vaultRoot) {
|
|
140
|
-
warnings.push("Cannot resolve translation source outside the canonical translations/<locale>/ layout.");
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
const source = path.resolve(vaultRoot, data.source_path);
|
|
144
|
-
const relative = path.relative(vaultRoot, source);
|
|
145
|
-
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
146
|
-
errors.push("Translation source_path escapes the vault.");
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
if (!fs.existsSync(source) || !fs.statSync(source).isFile() || fs.lstatSync(source).isSymbolicLink()) {
|
|
150
|
-
errors.push(`Translation source does not exist as a regular non-symlinked file: ${data.source_path}.`);
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
const raw = fs.readFileSync(source, 'utf8');
|
|
154
|
-
const parsed = await parseDocument(raw, kernelRoot);
|
|
155
|
-
if (parsed.data.type === 'translation') errors.push('Translations may not target another translation.');
|
|
156
|
-
const sourceDefinition = registry?.document_primitives?.[parsed.data.type];
|
|
157
|
-
const portability = parsed.data.x_portability || sourceDefinition?.portability;
|
|
158
|
-
if (portability !== 'structural') errors.push('Translations may target structural documents only.');
|
|
159
|
-
const hash = `sha256:${crypto.createHash('sha256').update(raw).digest('hex')}`;
|
|
160
|
-
if (data.source_hash !== hash) errors.push(`Translation source_hash is stale; expected '${hash}'.`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
122
|
export async function validateNode(filePath) {
|
|
164
123
|
const target = path.resolve(filePath);
|
|
165
124
|
const kernelRoot = findKernelRoot(path.dirname(target)) || findKernelRoot(process.cwd());
|
|
@@ -210,8 +169,6 @@ export async function validateNode(filePath) {
|
|
|
210
169
|
}
|
|
211
170
|
}
|
|
212
171
|
|
|
213
|
-
await validateTranslationReference(target, data, registry, kernelRoot, errors, warnings);
|
|
214
|
-
|
|
215
172
|
if (APPEND_TYPES.has(data.type) && body.trim() === '') {
|
|
216
173
|
warnings.push(`Append-only primitive '${data.type}' has an empty body.`);
|
|
217
174
|
}
|