Skip to content

Commit 883f750

Browse files
author
StackMemory Bot (CLI)
committed
feat(company-os): add company-os CLI command with list/validate/audit subcommands
1 parent 4f0e203 commit 883f750

13 files changed

Lines changed: 1211 additions & 0 deletions

docs/specs/COMPANY-OS-PROSE.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# Company OS PROSE Overview
2+
3+
> PROSE = **P**urpose, **R**ules & Constraints, **O**bservables, **S**cenarios, **E**xpectations
4+
>
5+
> Expectations are grounded in **SOPs** stored in the Company OS wiki.
6+
7+
This document describes StackMemory's Company OS behavior in plain English. Each section is intentionally testable and maps directly to integration tests in `src/__tests__/integration/company-os.test.ts`.
8+
9+
The contract layer of PROSE is derived from SOPs: every Expectation below corresponds to a procedural guarantee that QA can validate and that can be turned into executable scripts.
10+
11+
---
12+
13+
## P — Purpose
14+
15+
Company OS is a lightweight operating system for a small team. It turns recurring company processes into documented, auditable, and testable procedures so the team can delegate, onboard, and scale without losing context.
16+
17+
### P.1 Process discoverability
18+
Any team member can find the current version of any company process in the `wiki/` directory.
19+
20+
### P.2 Cross-session continuity
21+
Decisions and audit records written during one session must be retrievable in subsequent sessions.
22+
23+
---
24+
25+
## R — Rules & Constraints
26+
27+
### R.1 SOP schema
28+
Every SOP in the Company OS wiki must contain Objective, Procedure, Verification, and Non-compliance sections.
29+
30+
### R.2 PROSE reference
31+
Every SOP must reference a valid PROSE Expectation ID.
32+
33+
### R.3 Idempotent audits
34+
Running an audit command must not mutate process state.
35+
36+
---
37+
38+
## O — Observables
39+
40+
### O.1 SOP list
41+
`stackmemory company-os list` must list all SOPs in `wiki/` with their IDs and statuses.
42+
43+
### O.2 Audit status
44+
`stackmemory company-os audit <process>` must report the compliance status for the process.
45+
46+
### O.3 Decision retrieval
47+
Decisions recorded against a company process must be retrievable by process name.
48+
49+
---
50+
51+
## S — Scenarios
52+
53+
### S.1 SOP creation
54+
Adding a SOP to `wiki/` makes it discoverable and subject to validation.
55+
56+
### S.2 Audit run
57+
Running an audit evaluates the process against its SOP and records the result.
58+
59+
### S.3 Decision record
60+
Recording a decision against a process persists it with rationale and timestamp.
61+
62+
---
63+
64+
## E — Expectations
65+
66+
### E.1 Onboarding completeness
67+
Every new hire has documented accounts, hardware, and access before their start date.
68+
69+
**SOP basis:** `SOP-301 New Hire Onboarding` — onboarding must be complete before day one.
70+
71+
### E.2 Expense policy compliance
72+
All reimbursed expenses have manager and finance approval.
73+
74+
**SOP basis:** `SOP-302 Expense Approval` — reimbursement requires documented approval.
75+
76+
### E.3 Offboarding access removal
77+
Departing employees lose access to company systems within 24 hours of termination.
78+
79+
**SOP basis:** `SOP-303 Access Revocation` — access must be revoked within the SLA window.
80+
81+
### E.4 Security incident response SLA
82+
Security incidents are contained within the severity-based SLA.
83+
84+
**SOP basis:** `SOP-304 Security Incident Response` — Severity 1 incidents within 2 hours, Severity 2 within 24 hours.
85+
86+
### E.5 PTO request approval workflow
87+
All paid time off is requested, approved, and recorded before it begins.
88+
89+
**SOP basis:** `SOP-305 PTO Request` — reimbursement requires documented approval.
90+
91+
### E.6 Vendor security review
92+
Vendors with data access complete a security review before onboarding.
93+
94+
**SOP basis:** `SOP-306 Vendor Onboarding` — no data access without Security sign-off.
95+
96+
### E.7 Data retention enforcement
97+
Data is retained, archived, or deleted according to policy.
98+
99+
**SOP basis:** `SOP-307 Data Retention` — no data kept past retention without exception.
100+
101+
### E.8 Emergency contact completeness
102+
Every active employee has a current emergency contact on file.
103+
104+
**SOP basis:** `SOP-308 Emergency Contact Update` — contacts verified annually.
105+
106+
### E.9 Decision-derived process documentation
107+
Recurring decisions captured in frames are reflected in derived SOPs so the team does not re-debate them.
108+
109+
**SOP basis:** `SOP-401 Decision-derived Process` — derived from DECISION anchors in the wiki compiler.
110+
111+
### E.10 Constraint-derived process documentation
112+
Recurring constraints captured in frames are reflected in derived SOPs so the team respects known boundaries.
113+
114+
**SOP basis:** `SOP-402 Constraint-derived Process` — derived from CONSTRAINT anchors in the wiki compiler.
115+
116+
### E.11 Risk-derived process documentation
117+
Recurring risks captured in frames are reflected in derived SOPs so the team mitigates them consistently.
118+
119+
**SOP basis:** `SOP-403 Risk-derived Process` — derived from RISK anchors in the wiki compiler.
120+
121+
### E.12 Fact-derived process documentation
122+
Recurring facts captured in frames are reflected in derived SOPs so the team operates from shared knowledge.
123+
124+
**SOP basis:** `SOP-404 Fact-derived Process` — derived from FACT anchors in the wiki compiler.
125+
126+
---
127+
128+
## SOP → PROSE → Tests workflow
129+
130+
```
131+
SOP (company process)
132+
133+
134+
PROSE Expectation (plain-English contract)
135+
136+
137+
Integration test (executable validation)
138+
139+
140+
Provenant decision log (audit trail)
141+
```
142+
143+
For example, `SOP-301 New Hire Onboarding` becomes PROSE `E.1`, which becomes the test `onboarding records are complete`. QA can run the same test suite to verify SOP compliance, and the test can be used to generate or validate automation scripts.
144+
145+
---
146+
147+
## Test mapping
148+
149+
| PROSE ID | SOP basis | Test case |
150+
|----------|-----------|-----------|
151+
| P.1 || `lists SOPs in the company OS wiki` |
152+
| P.2 || `retrieves company-os decisions across sessions` |
153+
| R.1 || `rejects SOPs missing required sections` |
154+
| R.2 || `rejects SOPs with invalid PROSE references` |
155+
| R.3 || `audit commands do not mutate state` |
156+
| O.1 || `lists SOPs with IDs and statuses` |
157+
| O.2 || `reports audit status for a process` |
158+
| O.3 || `retrieves decisions by process name` |
159+
| S.1 || `adding a SOP makes it discoverable` |
160+
| S.2 || `running an audit records the result` |
161+
| S.3 || `recording a decision persists rationale` |
162+
| E.1 | `SOP-301 New Hire Onboarding` | `onboarding records are complete` |
163+
| E.2 | `SOP-302 Expense Approval` | `expenses have required approvals` |
164+
| E.3 | `SOP-303 Access Revocation` | `access is revoked within SLA` |
165+
| E.4 | `SOP-304 Security Incident Response` | `incidents are contained within SLA` |
166+
| E.5 | `SOP-305 PTO Request` | `PTO is approved before it begins` |
167+
| E.6 | `SOP-306 Vendor Onboarding` | `vendors have security review` |
168+
| E.7 | `SOP-307 Data Retention` | `data retention is enforced` |
169+
| E.8 | `SOP-308 Emergency Contact Update` | `emergency contacts are current` |
170+
| E.9 | `SOP-401 Decision-derived Process` | `decision-derived SOP is generated` |
171+
| E.10 | `SOP-402 Constraint-derived Process` | `constraint-derived SOP is generated` |
172+
| E.11 | `SOP-403 Risk-derived Process` | `risk-derived SOP is generated` |
173+
| E.12 | `SOP-404 Fact-derived Process` | `fact-derived SOP is generated` |

scripts/log-company-os-results.ts

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
#!/usr/bin/env tsx
2+
/**
3+
* Run the Company OS PROSE integration tests and log the results
4+
* into a Provenant knowledge graph as SOP-compliance decisions.
5+
*
6+
* Usage:
7+
* npx tsx scripts/log-company-os-results.ts [path/to/provenant.db]
8+
*
9+
* Requires PROVENANT_DB env var or a database path argument.
10+
*/
11+
12+
import { execSync } from 'node:child_process';
13+
import { mkdirSync } from 'node:fs';
14+
import { resolve, dirname } from 'node:path';
15+
import { fileURLToPath } from 'node:url';
16+
import { Database } from '../packages/provenant/src/schema/database.js';
17+
18+
const __dirname = dirname(fileURLToPath(import.meta.url));
19+
20+
interface VitestResult {
21+
testResults?: Array<{
22+
assertionResults: Array<{
23+
title: string;
24+
fullName: string;
25+
status: 'passed' | 'failed';
26+
duration: number;
27+
}>;
28+
}>;
29+
numPassedTests?: number;
30+
numFailedTests?: number;
31+
}
32+
33+
function runTests(): VitestResult {
34+
const testFile = resolve(
35+
__dirname,
36+
'../src/__tests__/integration/company-os.test.ts'
37+
);
38+
const raw = execSync(
39+
`npx vitest run "${testFile}" --reporter=json --silent`,
40+
{
41+
cwd: resolve(__dirname, '..'),
42+
encoding: 'utf8',
43+
timeout: 300_000,
44+
env: {
45+
...process.env,
46+
VITEST: undefined,
47+
NODE_ENV: undefined,
48+
},
49+
}
50+
);
51+
const start = raw.indexOf('{');
52+
if (start === -1) {
53+
throw new Error('No JSON output from vitest');
54+
}
55+
return JSON.parse(raw.slice(start)) as VitestResult;
56+
}
57+
58+
function mapTestToSop(
59+
testName: string,
60+
fullName: string
61+
): { sop?: string; proseId?: string } {
62+
const mapping: Record<string, { sop: string; proseId: string }> = {
63+
'onboarding SOP covers accounts, hardware, and access': {
64+
sop: 'SOP-301 New Hire Onboarding',
65+
proseId: 'E.1',
66+
},
67+
'expense SOP requires manager and finance approval': {
68+
sop: 'SOP-302 Expense Approval',
69+
proseId: 'E.2',
70+
},
71+
'offboarding SOP defines a 24-hour access revocation SLA': {
72+
sop: 'SOP-303 Access Revocation',
73+
proseId: 'E.3',
74+
},
75+
'incident response SOP defines severity-based containment SLA': {
76+
sop: 'SOP-304 Security Incident Response',
77+
proseId: 'E.4',
78+
},
79+
'PTO SOP requires manager approval before time off': {
80+
sop: 'SOP-305 PTO Request',
81+
proseId: 'E.5',
82+
},
83+
'vendor SOP requires security review before data access': {
84+
sop: 'SOP-306 Vendor Onboarding',
85+
proseId: 'E.6',
86+
},
87+
'data retention SOP defines retention tiers and deletion logging': {
88+
sop: 'SOP-307 Data Retention',
89+
proseId: 'E.7',
90+
},
91+
'emergency contact SOP requires annual verification': {
92+
sop: 'SOP-308 Emergency Contact Update',
93+
proseId: 'E.8',
94+
},
95+
'decision-derived SOP is generated from DECISION anchors': {
96+
sop: 'SOP-401 Decision-derived Process',
97+
proseId: 'E.9',
98+
},
99+
'constraint-derived SOP is generated from CONSTRAINT anchors': {
100+
sop: 'SOP-402 Constraint-derived Process',
101+
proseId: 'E.10',
102+
},
103+
'risk-derived SOP is generated from RISK anchors': {
104+
sop: 'SOP-403 Risk-derived Process',
105+
proseId: 'E.11',
106+
},
107+
'fact-derived SOP is generated from FACT anchors': {
108+
sop: 'SOP-404 Fact-derived Process',
109+
proseId: 'E.12',
110+
},
111+
};
112+
113+
for (const [key, value] of Object.entries(mapping)) {
114+
if (testName.includes(key) || fullName.includes(key)) {
115+
return value;
116+
}
117+
}
118+
return {};
119+
}
120+
121+
function main(): void {
122+
const dbPath =
123+
process.argv[2] ?? process.env['PROVENANT_DB'] ?? '.provenant/graph.db';
124+
if (!dbPath) {
125+
console.error(
126+
'Provide a Provenant database path as an argument or set PROVENANT_DB'
127+
);
128+
process.exit(1);
129+
}
130+
131+
mkdirSync(dirname(dbPath), { recursive: true });
132+
133+
console.log('Running Company OS integration tests...');
134+
const result = runTests();
135+
const tests = result.testResults ?? [];
136+
137+
if (tests.length === 0) {
138+
console.error('No test results found');
139+
process.exit(1);
140+
}
141+
142+
console.log(
143+
`Test run complete: ${result.numPassedTests ?? 0} passed, ${result.numFailedTests ?? 0} failed`
144+
);
145+
146+
const db = new Database(dbPath);
147+
try {
148+
const runId = `company-os-run-${Date.now()}`;
149+
let logged = 0;
150+
151+
const allTests = tests.flatMap((file) => file.assertionResults ?? []);
152+
153+
for (const test of allTests) {
154+
const { sop, proseId } = mapTestToSop(test.title, test.fullName);
155+
if (!sop || !proseId) continue;
156+
157+
const passed = test.status === 'passed';
158+
const content = passed
159+
? `${proseId} / ${sop}: compliance verified by integration test`
160+
: `${proseId} / ${sop}: compliance NOT verified by integration test`;
161+
162+
const node = db.insertNode({
163+
type: 'decision',
164+
content,
165+
embedding: null,
166+
actor: 'company-os-harness',
167+
confidence: passed ? 0.95 : 0.4,
168+
});
169+
170+
const source = db.insertSource({
171+
system: 'company-os-test-run',
172+
external_id: `${runId}:${proseId}`,
173+
raw_payload: JSON.stringify({
174+
testName: test.title,
175+
fullName: test.fullName,
176+
status: test.status,
177+
duration: test.duration,
178+
proseId,
179+
sop,
180+
}),
181+
hash: `${runId}:${proseId}`,
182+
});
183+
184+
db.linkNodeToSource(
185+
node.id,
186+
source.id,
187+
'company-os-test-run',
188+
`${runId}:${proseId}`
189+
);
190+
logged++;
191+
}
192+
193+
console.log(`Logged ${logged} SOP-compliance decisions to ${dbPath}`);
194+
} finally {
195+
db.close();
196+
}
197+
}
198+
199+
main();

0 commit comments

Comments
 (0)