Skip to content

Commit 4e709ec

Browse files
deepracticexsclaude
andcommitted
refactor: restructure API — rx.individual.activate, rx.inspect, rx.survey
- Rename RoleNamespace → IndividualNamespace (just activate) - Move inspect and survey to top-level methods on RoleXBuilder - Remove SurveyNamespace (survey is a world-level observation, not a command namespace) - Update all consumers: MCP server, tests, BDD steps, docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0faed91 commit 4e709ec

16 files changed

Lines changed: 108 additions & 112 deletions

File tree

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ import { localPlatform } from "@rolexjs/local-platform";
173173
// Create — synchronous, initialization is lazy
174174
const rx = createRoleX({ platform: localPlatform() });
175175

176-
// Activate a role
177-
const role = await rx.role.activate({ individual: "nuwa" });
176+
// Activate an individual
177+
const role = await rx.individual.activate({ individual: "nuwa" });
178178

179179
// Typed namespace API — 9 namespaces
180180
await rx.society.born({ id: "alice", content: "Feature: Alice\n A frontend engineer." });
@@ -204,19 +204,20 @@ const { tools, instructions } = rx.protocol;
204204

205205
`createRoleX()` returns a `RoleXBuilder` — a synchronous builder with lazy initialization. The first async call triggers init (genesis prototype, world bootstrap).
206206

207-
**9 typed namespaces:**
207+
**7 typed namespaces + 2 world-level methods:**
208208

209-
| Namespace | Purpose |
210-
|-----------|---------|
209+
| API | Purpose |
210+
|-----|---------|
211+
| `rx.individual` | Activate an individual — returns a stateful Role |
211212
| `rx.society` | Individuals & organizations — born, retire, teach, train, found, dissolve |
212213
| `rx.org` | Membership & governance — charter, hire, fire, establish, abolish |
213214
| `rx.position` | Roles & duties — charge, require, appoint, dismiss |
214215
| `rx.project` | Project management — scope, milestone, deliver, wiki |
215216
| `rx.product` | Product lifecycle — strategy, spec, release, channel |
216-
| `rx.survey` | World queries — list all entities |
217217
| `rx.issue` | Issue tracking — publish, comment, assign, label |
218218
| `rx.resource` | Resource management — add, push, pull, search |
219-
| `rx.role` | Role operations — activate, inspect, survey |
219+
| `rx.inspect()` | Examine any node's full state |
220+
| `rx.survey()` | List individuals, organizations, positions |
220221

221222
**Universal dispatch:**
222223

README.zh-CN.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ import { localPlatform } from "@rolexjs/local-platform";
173173
// 创建 — 同步返回,初始化延迟到首次调用
174174
const rx = createRoleX({ platform: localPlatform() });
175175

176-
// 激活角色
177-
const role = await rx.role.activate({ individual: "nuwa" });
176+
// 激活个体
177+
const role = await rx.individual.activate({ individual: "nuwa" });
178178

179179
// 类型化命名空间 API — 9 个命名空间
180180
await rx.society.born({ id: "alice", content: "Feature: Alice\n 一名前端工程师。" });
@@ -204,19 +204,20 @@ const { tools, instructions } = rx.protocol;
204204

205205
`createRoleX()` 返回 `RoleXBuilder` — 同步构建器,延迟初始化。首次异步调用触发初始化(genesis 原型、世界引导)。
206206

207-
**9 个类型化命名空间:**
207+
**7 个类型化命名空间 + 2 个世界级方法**
208208

209-
| 命名空间 | 用途 |
210-
|---------|------|
209+
| API | 用途 |
210+
|-----|------|
211+
| `rx.individual` | 激活个体 — 返回有状态的 Role |
211212
| `rx.society` | 个体与组织 — born, retire, teach, train, found, dissolve |
212213
| `rx.org` | 成员与治理 — charter, hire, fire, establish, abolish |
213214
| `rx.position` | 职位与职责 — charge, require, appoint, dismiss |
214215
| `rx.project` | 项目管理 — scope, milestone, deliver, wiki |
215216
| `rx.product` | 产品生命周期 — strategy, spec, release, channel |
216-
| `rx.survey` | 世界查询 — 列出所有实体 |
217217
| `rx.issue` | 议题追踪 — publish, comment, assign, label |
218218
| `rx.resource` | 资源管理 — add, push, pull, search |
219-
| `rx.role` | 角色操作 — activate, inspect, survey |
219+
| `rx.inspect()` | 查看任意节点的完整状态 |
220+
| `rx.survey()` | 列出个体、组织、职位 |
220221

221222
**统一调度:**
222223

apps/mcp-server/src/index.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,27 +89,20 @@ type ToolExecutor = (params: Record<string, unknown>) => Promise<string>;
8989

9090
const executors: Record<string, ToolExecutor> = {
9191
async inspect({ id }) {
92-
return await rolex.role.inspect({ id: id as string });
92+
return await rolex.inspect({ id: id as string });
9393
},
9494

9595
async survey({ type }) {
96-
const response = await rolex.rpc({
97-
jsonrpc: "2.0",
98-
method: "survey",
99-
params: type ? { type: type as string } : {},
100-
id: null,
101-
});
102-
if (response.error) throw new Error(response.error.message);
103-
return response.result as string;
96+
return await rolex.survey(type ? { type: type as string } : undefined);
10497
},
10598

10699
async activate({ roleId }) {
107100
try {
108-
const role = await rolex.role.activate({ individual: roleId as string });
101+
const role = await rolex.individual.activate({ individual: roleId as string });
109102
state.role = role;
110103
return await role.project();
111104
} catch {
112-
const all = await rolex.survey.list();
105+
const all = await rolex.survey();
113106
throw new Error(
114107
`"${roleId}" not found. Available:\n\n${JSON.stringify(all)}\n\nTry again with the correct id or alias.`
115108
);

apps/mcp-server/tests/mcp.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe("requireRole", () => {
3131

3232
it("returns role after activation", async () => {
3333
await rolex.society.born({ content: "Feature: Sean", id: "sean" });
34-
const role = await rolex.role.activate({ individual: "sean" });
34+
const role = await rolex.individual.activate({ individual: "sean" });
3535
state.role = role;
3636
expect(state.requireRole()).toBe(role);
3737
expect(state.requireRole().id).toBe("sean");
@@ -81,7 +81,7 @@ describe("render", () => {
8181

8282
it("Role methods return rendered 3-layer output", async () => {
8383
await rolex.society.born({ content: "Feature: Sean", id: "sean" });
84-
const role = await rolex.role.activate({ individual: "sean" });
84+
const role = await rolex.individual.activate({ individual: "sean" });
8585

8686
const output = await role.want("Feature: Test", "test-goal");
8787
// Layer 1: Status
@@ -100,7 +100,7 @@ describe("render", () => {
100100
describe("full execution flow", () => {
101101
it("completes want → plan → todo → finish → reflect → realize through Role API", async () => {
102102
await rolex.society.born({ content: "Feature: Sean", id: "sean" });
103-
const role = await rolex.role.activate({ individual: "sean" });
103+
const role = await rolex.individual.activate({ individual: "sean" });
104104
state.role = role;
105105

106106
// Want
@@ -153,7 +153,7 @@ describe("full execution flow", () => {
153153
describe("focus", () => {
154154
it("switches focused goal via Role", async () => {
155155
await rolex.society.born({ content: "Feature: Sean", id: "sean" });
156-
const role = await rolex.role.activate({ individual: "sean" });
156+
const role = await rolex.individual.activate({ individual: "sean" });
157157
state.role = role;
158158

159159
await role.want("Feature: Goal A", "goal-a");
@@ -175,7 +175,7 @@ describe("focus", () => {
175175
describe("selective cognition", () => {
176176
it("tracks multiple encounters, reflect consumes selectively", async () => {
177177
await rolex.society.born({ content: "Feature: Sean", id: "sean" });
178-
const role = await rolex.role.activate({ individual: "sean" });
178+
const role = await rolex.individual.activate({ individual: "sean" });
179179
state.role = role;
180180

181181
await role.want("Feature: Auth", "auth");

bdd/steps/context.steps.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ Given("no persisted context exists", async function (this: BddWorld) {
6666
When("I activate {string}", async function (this: BddWorld, name: string) {
6767
try {
6868
this.error = undefined;
69-
this.role = await this.rolex!.role.activate({ individual: name });
69+
this.role = await this.rolex!.individual.activate({ individual: name });
7070
} catch (e) {
7171
this.error = e as Error;
7272
this.role = undefined;

bdd/steps/direct.steps.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,25 @@ Then("it should fail", function (this: BddWorld) {
139139
// ===== Entity existence assertions =====
140140

141141
Then("individual {string} should exist", async function (this: BddWorld, id: string) {
142-
const result = await this.rolex!.survey.list({ type: "individual" });
142+
const response = await this.rolex!.rpc({
143+
jsonrpc: "2.0",
144+
method: "survey.list",
145+
params: { type: "individual" },
146+
id: null,
147+
});
148+
const result = response.result as any;
143149
const ids = (result.state.children ?? []).map((c: any) => c.id);
144150
assert.ok(ids.includes(id), `Individual "${id}" not found in survey: ${JSON.stringify(ids)}`);
145151
});
146152

147153
Then("organization {string} should exist", async function (this: BddWorld, id: string) {
148-
const result = await this.rolex!.survey.list({ type: "organization" });
154+
const response = await this.rolex!.rpc({
155+
jsonrpc: "2.0",
156+
method: "survey.list",
157+
params: { type: "organization" },
158+
id: null,
159+
});
160+
const result = response.result as any;
149161
const ids = (result.state.children ?? []).map((c: any) => c.id);
150162
assert.ok(ids.includes(id), `Organization "${id}" not found in survey: ${JSON.stringify(ids)}`);
151163
});

bdd/steps/isolation.steps.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Given(
1515
async function (this: BddWorld, id: string, goalId: string) {
1616
await this.rolex!.society.born({ content: `Feature: ${id}`, id });
1717
// Create goal through activate + want
18-
const role = await this.rolex!.role.activate({ individual: id });
18+
const role = await this.rolex!.individual.activate({ individual: id });
1919
await role.want(`Feature: ${goalId}`, goalId);
2020
}
2121
);
@@ -62,7 +62,7 @@ Then(
6262
"{string} should be under individual {string}",
6363
async function (this: BddWorld, nodeId: string, individualId: string) {
6464
// Use rendered project output to check node presence
65-
const role = await this.rolex!.role.activate({ individual: individualId });
65+
const role = await this.rolex!.individual.activate({ individual: individualId });
6666
const output = await role.project();
6767
assert.ok(
6868
output.includes(`(${nodeId})`),
@@ -74,7 +74,7 @@ Then(
7474
Then(
7575
"{string} should not be under individual {string}",
7676
async function (this: BddWorld, nodeId: string, individualId: string) {
77-
const role = await this.rolex!.role.activate({ individual: individualId });
77+
const role = await this.rolex!.individual.activate({ individual: individualId });
7878
const output = await role.project();
7979
assert.ok(
8080
!output.includes(`(${nodeId})`),
@@ -95,7 +95,7 @@ When("I restore role {string} from KV", async function (this: BddWorld, id: stri
9595
await this.newSession();
9696
try {
9797
this.error = undefined;
98-
this.role = await this.rolex!.role.activate({ individual: id });
98+
this.role = await this.rolex!.individual.activate({ individual: id });
9999
} catch (e) {
100100
this.error = e as Error;
101101
}
@@ -107,7 +107,7 @@ let firstRole: Role | undefined;
107107

108108
When("I activate role {string} again", async function (this: BddWorld, id: string) {
109109
firstRole = this.role;
110-
this.role = await this.rolex!.role.activate({ individual: id });
110+
this.role = await this.rolex!.individual.activate({ individual: id });
111111
});
112112

113113
Then("both activations should return the same Role instance", function (this: BddWorld) {
@@ -127,7 +127,7 @@ Then("I should receive a Role with id {string}", function (this: BddWorld, id: s
127127
When("I try to activate role {string}", async function (this: BddWorld, id: string) {
128128
try {
129129
this.error = undefined;
130-
this.role = await this.rolex!.role.activate({ individual: id });
130+
this.role = await this.rolex!.individual.activate({ individual: id });
131131
} catch (e) {
132132
this.error = e as Error;
133133
this.role = undefined;
@@ -147,7 +147,7 @@ Then("it should fail with {string}", function (this: BddWorld, message: string)
147147
Then(
148148
"role {string} should contain node {string}",
149149
async function (this: BddWorld, roleId: string, nodeId: string) {
150-
const role = await this.rolex!.role.activate({ individual: roleId });
150+
const role = await this.rolex!.individual.activate({ individual: roleId });
151151
const output = await role.project();
152152
assert.ok(output.includes(`(${nodeId})`), `Node "${nodeId}" not found in role "${roleId}"`);
153153
}

bdd/steps/role.steps.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type { BddWorld } from "../support/world";
1414
// ===== Activate =====
1515

1616
Given("I activate role {string}", async function (this: BddWorld, id: string) {
17-
this.role = await this.rolex!.role.activate({ individual: id });
17+
this.role = await this.rolex!.individual.activate({ individual: id });
1818
});
1919

2020
// ===== Execution =====

bdd/steps/serialization.steps.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ When(
2727
assert.ok(this.roleSnapshot, "No snapshot captured");
2828
// Simulate restore: new session + activate (which restores from persisted context)
2929
await this.newSession();
30-
this.role = await this.rolex!.role.activate({ individual: this.roleSnapshot.id });
30+
this.role = await this.rolex!.individual.activate({ individual: this.roleSnapshot.id });
3131
}
3232
);
3333

packages/core/src/builder.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,30 @@
33
*
44
* Usage:
55
* const rx = createBuilder({ platform, renderer });
6-
* const role = await rx.role.activate({ individual: "sean" });
6+
* const role = await rx.individual.activate({ individual: "sean" });
77
* await rx.society.born({ id: "alice", content: "Feature: Alice" });
88
*/
99

1010
import type {
1111
Caller,
12+
IndividualNamespace,
1213
IssueNamespace,
1314
OrgNamespace,
1415
PositionNamespace,
1516
ProductNamespace,
1617
ProjectNamespace,
1718
ResourceNamespace,
18-
RoleNamespace,
1919
SocietyNamespace,
20-
SurveyNamespace,
2120
} from "./namespaces.js";
2221
import {
22+
createIndividualNamespace,
2323
createIssueNamespace,
2424
createOrgNamespace,
2525
createPositionNamespace,
2626
createProductNamespace,
2727
createProjectNamespace,
2828
createResourceNamespace,
29-
createRoleNamespace,
3029
createSocietyNamespace,
31-
createSurveyNamespace,
3230
} from "./namespaces.js";
3331
import type { Platform, PrototypeData } from "./platform.js";
3432
import type { Renderer } from "./renderer.js";
@@ -47,8 +45,8 @@ export interface RoleXInternal {
4745
export interface RoleXBuilder {
4846
/** Society-level operations — born, retire, crown, teach, train, found, dissolve. */
4947
readonly society: SocietyNamespace;
50-
/** Role management — activate, inspect. */
51-
readonly role: RoleNamespace;
48+
/** Individual operations — activate. */
49+
readonly individual: IndividualNamespace;
5250
/** Organization operations — charter, hire, fire, admin, launch, establish. */
5351
readonly org: OrgNamespace;
5452
/** Position operations — charge, require, appoint, dismiss. */
@@ -57,13 +55,16 @@ export interface RoleXBuilder {
5755
readonly project: ProjectNamespace;
5856
/** Product operations — strategy, spec, release, channel, own. */
5957
readonly product: ProductNamespace;
60-
/** Survey — world-level queries. */
61-
readonly survey: SurveyNamespace;
6258
/** Issue tracking integration. */
6359
readonly issue: IssueNamespace;
6460
/** Resource management integration. */
6561
readonly resource: ResourceNamespace;
6662

63+
/** Inspect any node's full state — world-level observation. */
64+
inspect(params: { id: string }): Promise<string>;
65+
/** Survey the world — list individuals, organizations, positions. */
66+
survey(params?: { type?: string }): Promise<string>;
67+
6768
/** Tool schemas + world instructions — the unified contract for any channel adapter. */
6869
readonly protocol: Protocol;
6970

@@ -139,21 +140,20 @@ export function createBuilder(config: BuilderConfig): RoleXBuilder {
139140

140141
// Create namespace instances (synchronous — they're just wrappers)
141142
const _society = createSocietyNamespace(call);
142-
const _role = createRoleNamespace(call);
143+
const _individual = createIndividualNamespace(call);
143144
const _org = createOrgNamespace(call);
144145
const _position = createPositionNamespace(call);
145146
const _project = createProjectNamespace(call);
146147
const _product = createProductNamespace(call);
147-
const _survey = createSurveyNamespace(call);
148148
const _issue = createIssueNamespace(call);
149149
const _resource = createResourceNamespace(call);
150150

151151
return {
152152
get society() {
153153
return _society;
154154
},
155-
get role() {
156-
return _role;
155+
get individual() {
156+
return _individual;
157157
},
158158
get org() {
159159
return _org;
@@ -167,16 +167,21 @@ export function createBuilder(config: BuilderConfig): RoleXBuilder {
167167
get product() {
168168
return _product;
169169
},
170-
get survey() {
171-
return _survey;
172-
},
173170
get issue() {
174171
return _issue;
175172
},
176173
get resource() {
177174
return _resource;
178175
},
179176

177+
async inspect({ id }: { id: string }) {
178+
return call("inspect", { id });
179+
},
180+
181+
async survey(params?: { type?: string }) {
182+
return call("survey", params);
183+
},
184+
180185
protocol: defaultProtocol,
181186

182187
async rpc<T>(request: JsonRpcRequest): Promise<JsonRpcResponse<T>> {

0 commit comments

Comments
 (0)