@hassangameryt/freeflow 0.7.2 → 0.7.3
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/README.md +147 -127
- package/capabilities/cognitive-routing/SKILL.md +162 -93
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/pi-extension/dist/cognitive-routing-v2/config.js +35 -19
- package/pi-extension/dist/cognitive-routing-v2/projection.js +53 -44
- package/pi-extension/dist/cognitive-routing-v2/render.js +31 -10
- package/pi-extension/dist/cognitive-routing-v2/runtime.js +701 -105
- package/pi-extension/dist/cognitive-routing-v2/schemas.js +90 -24
- package/pi-extension/dist/cognitive-routing-v2/state.js +243 -27
- package/pi-extension/dist/cognitive-routing-v2/tools.js +19 -50
- package/pi-extension/dist/cognitive-routing-v2/types.js +5 -1
- package/pi-extension/dist/context-virtualization/runtime.js +29 -7
- package/pi-extension/dist/freeflow-context/tool.js +7 -6
- package/pi-extension/dist/index.js +36 -15
- package/pi-extension/dist/provider-support/astra/adapter.js +110 -0
- package/pi-extension/dist/provider-support/astra/history.js +125 -0
- package/pi-extension/dist/provider-support/astra/index.js +11 -0
- package/pi-extension/dist/provider-support/astra/session-state.js +114 -0
- package/pi-extension/dist/provider-support/index.js +4 -0
- package/pi-extension/dist/runtime/request-history.js +216 -0
- package/pi-extension/dist/runtime/runtime-context.js +29 -10
- package/pi-extension/dist/session-sources/events.js +22 -0
- package/pi-extension/dist/session-sources/provenance.js +32 -0
- package/pi-extension/dist/session-sources/sources.js +51 -7
- package/pi-extension/dist/settings/settings-ui.js +247 -47
- package/pi-extension/src/cognitive-routing-v2/config.ts +49 -19
- package/pi-extension/src/cognitive-routing-v2/projection.ts +53 -43
- package/pi-extension/src/cognitive-routing-v2/render.ts +31 -10
- package/pi-extension/src/cognitive-routing-v2/runtime.ts +712 -105
- package/pi-extension/src/cognitive-routing-v2/schemas.ts +95 -24
- package/pi-extension/src/cognitive-routing-v2/state.ts +244 -27
- package/pi-extension/src/cognitive-routing-v2/tools.ts +19 -50
- package/pi-extension/src/cognitive-routing-v2/types.ts +35 -3
- package/pi-extension/src/context-virtualization/runtime.ts +30 -8
- package/pi-extension/src/freeflow-context/tool.ts +7 -6
- package/pi-extension/src/index.ts +36 -14
- package/pi-extension/src/provider-support/astra/adapter.ts +108 -0
- package/pi-extension/src/provider-support/astra/history.ts +145 -0
- package/pi-extension/src/provider-support/astra/index.ts +12 -0
- package/pi-extension/src/provider-support/astra/session-state.ts +113 -0
- package/pi-extension/src/provider-support/index.ts +5 -0
- package/pi-extension/src/runtime/request-history.ts +243 -0
- package/pi-extension/src/runtime/runtime-context.ts +32 -10
- package/pi-extension/src/session-sources/events.ts +22 -0
- package/pi-extension/src/session-sources/provenance.ts +39 -0
- package/pi-extension/src/session-sources/sources.ts +77 -6
- package/pi-extension/src/settings/settings-ui.ts +276 -46
- package/pi-extension/tests/cache-reuse/history.test.js +117 -0
- package/pi-extension/tests/cache-reuse/native.test.js +91 -0
- package/pi-extension/tests/cache-reuse/settings.test.js +211 -0
- package/pi-extension/tests/cognitive-routing-v2/communication.test.js +94 -1
- package/pi-extension/tests/cognitive-routing-v2/delegation.test.js +557 -0
- package/pi-extension/tests/cognitive-routing-v2/native.test.js +34 -1
- package/pi-extension/tests/cognitive-routing-v2/persistence.test.js +55 -0
- package/pi-extension/tests/cognitive-routing-v2/recovery.test.js +800 -2
- package/pi-extension/tests/cognitive-routing-v2/render.test.js +15 -1
- package/pi-extension/tests/cognitive-routing-v2/runtime.test.js +273 -3
- package/pi-extension/tests/cognitive-routing-v2/state.test.js +312 -1
- package/pi-extension/tests/context-virtualization/extension.test.js +20 -10
- package/pi-extension/tests/context-virtualization/runtime.test.js +17 -3
- package/pi-extension/tests/fixtures/routing-native.js +4 -1
- package/pi-extension/tests/integration/mode-free-core.test.js +4 -3
- package/pi-extension/tests/integration/pi-extension.test.js +508 -29
- package/pi-extension/tests/integration/prompt-architecture.test.js +56 -40
- package/pi-extension/tests/integration/unaffected-regressions.test.js +3 -3
- package/pi-extension/tests/provider-support/astra-boundaries.test.js +75 -0
- package/pi-extension/tests/provider-support/astra.test.js +306 -0
- package/pi-extension/tests/provider-support/cli.test.js +92 -0
- package/pi-extension/tests/provider-support/native.test.js +183 -0
- package/plugin.json +1 -1
- package/runtime/prompts/cognitive-routing.md +4 -4
- package/skills/design-for-depth/SKILL.md +1 -1
- package/skills/design-for-depth/references/implementation-decisions.md +3 -3
- package/skills/discuss/SKILL.md +2 -2
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { mkdtemp, mkdir, writeFile, readFile, rm } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import { response } from "../fixtures/routing-native.js";
|
|
9
|
+
|
|
10
|
+
test(
|
|
11
|
+
"bundled Pi CLI loads Freeflow adapter and changes effort inside a native tool loop",
|
|
12
|
+
{ timeout: 30000 },
|
|
13
|
+
async () => {
|
|
14
|
+
const root = await mkdtemp(join(tmpdir(), "astra-cli-")),
|
|
15
|
+
agentDir = join(root, "agent");
|
|
16
|
+
try {
|
|
17
|
+
await mkdir(agentDir);
|
|
18
|
+
await writeFile(
|
|
19
|
+
join(agentDir, "auth.json"),
|
|
20
|
+
JSON.stringify({ openai: { type: "api_key", key: "fixture-not-real" } }),
|
|
21
|
+
);
|
|
22
|
+
await writeFile(
|
|
23
|
+
join(agentDir, "settings.json"),
|
|
24
|
+
JSON.stringify({
|
|
25
|
+
defaultProvider: "openai",
|
|
26
|
+
defaultModel: "gpt-6-astra",
|
|
27
|
+
defaultThinkingLevel: "low",
|
|
28
|
+
transport: "sse",
|
|
29
|
+
compaction: { enabled: false },
|
|
30
|
+
retry: { enabled: false, maxRetries: 0, provider: { maxRetries: 0 } },
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
const capture = join(root, "requests.json"),
|
|
34
|
+
extension = join(root, "fixture.mjs");
|
|
35
|
+
await writeFile(
|
|
36
|
+
extension,
|
|
37
|
+
`import {writeFileSync} from 'node:fs';\n${response.toString()}\nexport default function(pi){pi.registerTool({name:'probe_raise_effort',label:'Probe effort',description:'Fixture only',parameters:{type:'object',properties:{}},execute:async()=>{pi.setThinkingLevel('high');return {content:[{type:'text',text:'Changed desired effort.'}]};}});const bodies=[];globalThis.fetch=async(url,init)=>{if(String(url)!=='https://api.openai.com/v1/responses')throw Error('Unexpected network');const body=JSON.parse(String(init.body));bodies.push(body);writeFileSync(${JSON.stringify(capture)},JSON.stringify(bodies));if(bodies.length>2)throw Error('Unexpected extra request');return response(bodies.length,bodies.length===1?[{name:'probe_raise_effort',args:{}}]:[],'OK');};}`,
|
|
38
|
+
);
|
|
39
|
+
const cli = fileURLToPath(new URL("./bundle/cli.js", import.meta.resolve("@earendil-works/pi-coding-agent")));
|
|
40
|
+
const entry = fileURLToPath(new URL("../../freeflow/index.js", import.meta.url));
|
|
41
|
+
const child = spawn(
|
|
42
|
+
process.execPath,
|
|
43
|
+
[
|
|
44
|
+
cli,
|
|
45
|
+
"-p",
|
|
46
|
+
"--mode",
|
|
47
|
+
"json",
|
|
48
|
+
"--no-extensions",
|
|
49
|
+
"--no-skills",
|
|
50
|
+
"--no-context-files",
|
|
51
|
+
"--no-prompt-templates",
|
|
52
|
+
"--no-themes",
|
|
53
|
+
"-e",
|
|
54
|
+
extension,
|
|
55
|
+
"-e",
|
|
56
|
+
entry,
|
|
57
|
+
"Run the effort fixture.",
|
|
58
|
+
],
|
|
59
|
+
{
|
|
60
|
+
cwd: root,
|
|
61
|
+
env: {
|
|
62
|
+
PATH: process.env.PATH,
|
|
63
|
+
PI_CODING_AGENT_DIR: agentDir,
|
|
64
|
+
PI_OFFLINE: "1",
|
|
65
|
+
PI_TELEMETRY: "0",
|
|
66
|
+
PI_SKIP_VERSION_CHECK: "1",
|
|
67
|
+
},
|
|
68
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
let output = "";
|
|
72
|
+
child.stdout.on("data", (d) => (output += d));
|
|
73
|
+
child.stderr.on("data", (d) => (output += d));
|
|
74
|
+
const timer = setTimeout(() => child.kill("SIGKILL"), 20000);
|
|
75
|
+
const code = await new Promise((resolve, reject) => {
|
|
76
|
+
child.on("error", reject);
|
|
77
|
+
child.on("close", resolve);
|
|
78
|
+
});
|
|
79
|
+
clearTimeout(timer);
|
|
80
|
+
assert.equal(code, 0, output.slice(-4000));
|
|
81
|
+
const bodies = JSON.parse(await readFile(capture, "utf8"));
|
|
82
|
+
assert.equal(bodies.length, 2);
|
|
83
|
+
assert.equal(bodies[1].reasoning.effort, "low");
|
|
84
|
+
const updates = bodies[1].input.filter((i) => i.type === "configuration_update");
|
|
85
|
+
assert.deepEqual(updates, [{ type: "configuration_update", reasoning: { effort: "high" } }]);
|
|
86
|
+
assert.ok(bodies[1].input.some((i) => i.type === "function_call_output"));
|
|
87
|
+
assert.match(output, /OK/);
|
|
88
|
+
} finally {
|
|
89
|
+
await rm(root, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
);
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { mkdtemp, mkdir, rm, readFile } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import {
|
|
7
|
+
createAgentSession,
|
|
8
|
+
DefaultResourceLoader,
|
|
9
|
+
ModelRuntime,
|
|
10
|
+
SessionManager,
|
|
11
|
+
SettingsManager,
|
|
12
|
+
} from "@earendil-works/pi-coding-agent";
|
|
13
|
+
import freeflow from "../../dist/index.js";
|
|
14
|
+
import { registerProviderSupport } from "../../dist/provider-support/index.js";
|
|
15
|
+
import { ENTRY_TYPE } from "../../dist/provider-support/astra/history.js";
|
|
16
|
+
import { response } from "../fixtures/routing-native.js";
|
|
17
|
+
|
|
18
|
+
async function native(extension, run) {
|
|
19
|
+
const root = await mkdtemp(join(tmpdir(), "astra-native-")),
|
|
20
|
+
agentDir = join(root, "agent");
|
|
21
|
+
await mkdir(agentDir);
|
|
22
|
+
const previousFetch = globalThis.fetch,
|
|
23
|
+
requests = [],
|
|
24
|
+
errors = [];
|
|
25
|
+
let session;
|
|
26
|
+
globalThis.fetch = async (url, init) => {
|
|
27
|
+
assert.match(String(url), /^https:\/\/api\.openai\.com\/v1\/responses$/);
|
|
28
|
+
requests.push(JSON.parse(String(init.body)));
|
|
29
|
+
assert.ok(requests.length <= 12);
|
|
30
|
+
return response(requests.length, [], "OK");
|
|
31
|
+
};
|
|
32
|
+
try {
|
|
33
|
+
const runtime = await ModelRuntime.create({
|
|
34
|
+
authPath: join(agentDir, "auth.json"),
|
|
35
|
+
modelsPath: null,
|
|
36
|
+
modelsStorePath: join(agentDir, "models.json"),
|
|
37
|
+
allowModelNetwork: false,
|
|
38
|
+
});
|
|
39
|
+
await runtime.setRuntimeApiKey("openai", "fixture-only-key");
|
|
40
|
+
const settings = SettingsManager.inMemory({
|
|
41
|
+
transport: "sse",
|
|
42
|
+
compaction: { enabled: false, keepRecentTokens: 1, reserveTokens: 1 },
|
|
43
|
+
retry: { enabled: false, maxRetries: 0, provider: { maxRetries: 0 } },
|
|
44
|
+
});
|
|
45
|
+
const manager = SessionManager.create(root, join(root, "sessions"));
|
|
46
|
+
let cancelCompaction = false;
|
|
47
|
+
const loader = new DefaultResourceLoader({
|
|
48
|
+
cwd: root,
|
|
49
|
+
agentDir,
|
|
50
|
+
settingsManager: settings,
|
|
51
|
+
noExtensions: true,
|
|
52
|
+
noSkills: true,
|
|
53
|
+
noPromptTemplates: true,
|
|
54
|
+
noThemes: true,
|
|
55
|
+
noContextFiles: true,
|
|
56
|
+
systemPrompt: "Reply OK.",
|
|
57
|
+
extensionFactories: [
|
|
58
|
+
extension,
|
|
59
|
+
(pi) =>
|
|
60
|
+
pi.on("session_before_compact", () =>
|
|
61
|
+
cancelCompaction
|
|
62
|
+
? { cancel: true }
|
|
63
|
+
: {
|
|
64
|
+
compaction: {
|
|
65
|
+
summary: "Older material summarized.",
|
|
66
|
+
firstKeptEntryId: manager.getLeafId(),
|
|
67
|
+
tokensBefore: 100,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
),
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
await loader.reload();
|
|
74
|
+
assert.deepEqual(loader.getExtensions().errors, []);
|
|
75
|
+
({ session } = await createAgentSession({
|
|
76
|
+
cwd: root,
|
|
77
|
+
agentDir,
|
|
78
|
+
modelRuntime: runtime,
|
|
79
|
+
model: runtime.getModel("openai", "gpt-6-astra"),
|
|
80
|
+
thinkingLevel: "low",
|
|
81
|
+
settingsManager: settings,
|
|
82
|
+
sessionManager: manager,
|
|
83
|
+
resourceLoader: loader,
|
|
84
|
+
tools: [],
|
|
85
|
+
}));
|
|
86
|
+
await session.bindExtensions({ mode: "print", onError: (e) => errors.push(e) });
|
|
87
|
+
const prompt = async (text, effort) => {
|
|
88
|
+
if (effort) session.setThinkingLevel(effort);
|
|
89
|
+
await session.prompt(text);
|
|
90
|
+
await session.waitForIdle();
|
|
91
|
+
assert.equal(session.messages.at(-1)?.stopReason, "stop");
|
|
92
|
+
assert.deepEqual(errors, []);
|
|
93
|
+
return requests.at(-1);
|
|
94
|
+
};
|
|
95
|
+
await run({
|
|
96
|
+
session,
|
|
97
|
+
manager,
|
|
98
|
+
requests,
|
|
99
|
+
prompt,
|
|
100
|
+
root,
|
|
101
|
+
cancelCompaction: () => {
|
|
102
|
+
cancelCompaction = true;
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
assert.deepEqual(errors, []);
|
|
106
|
+
} finally {
|
|
107
|
+
session?.dispose();
|
|
108
|
+
globalThis.fetch = previousFetch;
|
|
109
|
+
await rm(root, { recursive: true, force: true });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const updates = (p) =>
|
|
113
|
+
p.input.flatMap((x, i) => (x.type === "configuration_update" ? [{ index: i, effort: x.reasoning.effort }] : []));
|
|
114
|
+
|
|
115
|
+
test("real Pi request dispatch, reload, native tree navigation and compaction", { timeout: 30000 }, async () => {
|
|
116
|
+
await native(registerProviderSupport, async ({ session, manager, requests, prompt }) => {
|
|
117
|
+
await prompt("first", "low");
|
|
118
|
+
const high = await prompt("second", "high");
|
|
119
|
+
assert.equal(high.reasoning.effort, "low");
|
|
120
|
+
assert.equal(session.thinkingLevel, "high");
|
|
121
|
+
assert.deepEqual(updates(high), [{ index: 3, effort: "high" }]);
|
|
122
|
+
await session.reload();
|
|
123
|
+
const low = await prompt("third", "low");
|
|
124
|
+
assert.deepEqual(low.input.slice(0, high.input.length), high.input);
|
|
125
|
+
assert.deepEqual(updates(low), [
|
|
126
|
+
{ index: 3, effort: "high" },
|
|
127
|
+
{ index: 6, effort: "low" },
|
|
128
|
+
]);
|
|
129
|
+
const branchPoint = manager
|
|
130
|
+
.getBranch()
|
|
131
|
+
.find((e) => e.message?.role === "user" && e.message.content?.some?.((b) => b.text === "second"));
|
|
132
|
+
assert.ok(branchPoint);
|
|
133
|
+
// Native tree navigation selects real ancestry; the discarded later Low update must not survive.
|
|
134
|
+
await session.navigateTree(branchPoint.id, { summarize: false });
|
|
135
|
+
const sibling = await prompt("sibling", "medium");
|
|
136
|
+
assert.ok(updates(sibling).every((x) => x.effort !== "low"));
|
|
137
|
+
await session.compact();
|
|
138
|
+
const compacted = await prompt("after summary", "high");
|
|
139
|
+
assert.equal(compacted.reasoning.effort, "high");
|
|
140
|
+
assert.deepEqual(updates(compacted), []);
|
|
141
|
+
const persisted = await readFile(manager.getSessionFile(), "utf8");
|
|
142
|
+
assert.ok(persisted.includes(ENTRY_TYPE));
|
|
143
|
+
assert.ok(!manager.getBranch().some((e) => e.customType === "freeflow-routing-v2"));
|
|
144
|
+
assert.equal(requests.length, 5);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test(
|
|
149
|
+
"the Freeflow extension adapts Astra without repository activation or Cognitive Routing",
|
|
150
|
+
{ timeout: 30000 },
|
|
151
|
+
async () => {
|
|
152
|
+
await native(freeflow, async ({ session, manager, prompt }) => {
|
|
153
|
+
await prompt("one", "low");
|
|
154
|
+
const p = await prompt("two", "high");
|
|
155
|
+
assert.equal(p.reasoning.effort, "low");
|
|
156
|
+
assert.equal(session.thinkingLevel, "high");
|
|
157
|
+
assert.ok(updates(p).some((x) => x.effort === "high"));
|
|
158
|
+
assert.ok(manager.getBranch().some((e) => e.customType === ENTRY_TYPE));
|
|
159
|
+
assert.ok(!manager.getBranch().some((e) => e.customType === "freeflow-routing-v2"));
|
|
160
|
+
assert.ok(!(p.tools ?? []).some((t) => t.name.startsWith("freeflow_")));
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
test(
|
|
166
|
+
"rapid native effort changes coalesce and cancelled compaction releases adaptation",
|
|
167
|
+
{ timeout: 30000 },
|
|
168
|
+
async () => {
|
|
169
|
+
await native(registerProviderSupport, async ({ session, prompt, cancelCompaction }) => {
|
|
170
|
+
await prompt("first", "low");
|
|
171
|
+
session.setThinkingLevel("high");
|
|
172
|
+
session.setThinkingLevel("max");
|
|
173
|
+
session.setThinkingLevel("medium");
|
|
174
|
+
const medium = await prompt("second");
|
|
175
|
+
assert.deepEqual(updates(medium), [{ index: 3, effort: "medium" }]);
|
|
176
|
+
cancelCompaction();
|
|
177
|
+
await assert.rejects(session.compact(), /cancelled/);
|
|
178
|
+
const high = await prompt("third", "high");
|
|
179
|
+
assert.equal(high.reasoning.effort, "low");
|
|
180
|
+
assert.equal(updates(high).at(-1).effort, "high");
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
);
|
package/plugin.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
## Cognitive Routing Cue
|
|
2
2
|
|
|
3
|
-
Cognitive Routing
|
|
3
|
+
Cognitive Routing places work across configured profiles in one agent/session to improve quality, continuity, responsiveness, and total cost together. Coordinator owns user interaction, governing direction, delegation, and acceptance. When enabled, Helper is the normal delegate for supporting work; Executor is commissioned for substantive or consequential results, including implementation and artifacts. Helper and Executor share ordinary active history; only Coordinator delegates and only one profile executes at a time.
|
|
4
4
|
|
|
5
|
-
Use the latest Runtime State for control, profile, and current responsibility.
|
|
5
|
+
Use the latest Runtime State for control, profile, delegation mode, and current responsibility. In Automatic control, follow the selected mode: helper-only permits Coordinator substantive production with Helper support; executor-only delegates environment work to Executor; both uses Helper by default for support and Executor for substantive work. A mode change does not retarget an accepted assignment or its recovery. Under Manual control, the held Coordinator, Helper, or Executor follows ordinary unsplit Workflow without Automatic role restrictions. Do not release the user's hold. When routing is inactive, stop applying this split.
|
|
6
6
|
|
|
7
|
-
Before relying on
|
|
7
|
+
Before relying on Automatic routing, read the complete cognitive-routing skill if its body is absent. This bootstrap read is the only environment call in that response. If unavailable, stop and report the missing method. Reload it after context loss before applying remembered routing rules.
|
|
8
8
|
|
|
9
|
-
When projection is on,
|
|
9
|
+
When projection is on, the active worker must project every completed skill and instructional-reference read, including this bootstrap read. Follow the skill for work placement, environment access, evidence, handoffs, and recorded-worker recovery. Under Automatic routing, a worker return or passing check is not Coordinator acceptance; completed Slice closure requires Coordinator's supported judgment and explicit closure instruction. Manual control follows ordinary Workflow and Track Work instead.
|
|
@@ -30,7 +30,7 @@ A large mechanical change may need no design escalation. A one-line change may n
|
|
|
30
30
|
|
|
31
31
|
Use the lens early when interface, ownership, state, or failure choices could harden into caller contracts. It can support discussion, a Spec or Plan, implementation preparation, or selecting a test seam.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Read [Implementation Decisions](references/implementation-decisions.md) when unresolved representation, identity, ownership, algorithm, dependency, or failure choices could materially change a technical recommendation or invalidate significant dependent work. Apply it before recommending a mechanism during discussion, writing its guiding design, or beginning substantial implementation. Explore alternatives against the current goal and constraints; select a supported mechanism or identify the missing observation or user-owned choice. Leave ordinary mechanics free. The reference helps make those choices explicit and check their realization, not impose a blueprint on every task.
|
|
34
34
|
|
|
35
35
|
Once a boundary is supported, do not reopen it merely because the skill remains in context. Re-enter when evidence shows growing caller coordination, scattered policy, exposed internal states, fragile test choreography, unclear dependency/failure ownership, or an invalidated design assumption.
|
|
36
36
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Implementation Decisions
|
|
2
2
|
|
|
3
|
-
Read this
|
|
3
|
+
Read this when unresolved representation, identity, ownership, algorithm, dependency, or failure choices could materially change a technical recommendation or invalidate significant dependent work. Apply it before recommending a mechanism during discussion, writing its guiding design, or beginning substantial implementation. Skip it for a supported local change whose remaining mechanics do not alter those boundaries.
|
|
4
4
|
|
|
5
5
|
Use this method under Design for Depth and the current activity. It does not create another planning phase, document requirement, approval gate, or compute role.
|
|
6
6
|
|
|
7
7
|
## Identify What Implementation Would Still Have To Invent
|
|
8
8
|
|
|
9
|
-
Start from the
|
|
9
|
+
Start from the current goal and constraints, relevant source evidence, and existing design. During discussion, mark unsettled outcomes and approaches as provisional: compare their consequences without turning an explored option into an accepted requirement. Select supported engineering details within the agreement; return user-owned choices through the current activity. Ask:
|
|
10
10
|
|
|
11
11
|
> Which remaining choices could change correctness, complexity, failure behavior, or force substantial dependent work to be redone?
|
|
12
12
|
|
|
@@ -73,4 +73,4 @@ Weak direction: "Make persistence idempotent and robust."
|
|
|
73
73
|
|
|
74
74
|
Useful direction: "The append owner distinguishes observed acknowledgment from an uncertain attempt. An equal entry in memory does not resolve an earlier failure. Validate before mutation; publish accepted state only at the supported acknowledgment boundary. Test append advancing memory then failing, followed by the identical operation: uncertainty must remain until supported reconciliation. Also test an acknowledged duplicate so the implementation does not reject every retry. Do not infer filesystem durability from readback. Reconsider the mechanism if the actual host boundary differs."
|
|
75
75
|
|
|
76
|
-
Stop when the next implementation has a supported approach and intentional local freedom
|
|
76
|
+
Stop when the current discussion has a supported recommendation or explicit open question, or the next implementation has a supported approach and intentional local freedom. Preserve provisional versus accepted decisions when passing the result back to the current activity; discussion does not authorize implementation. Do not pursue a complete blueprint for later work whose premises remain unsettled.
|
package/skills/discuss/SKILL.md
CHANGED
|
@@ -26,6 +26,8 @@ Identify which understanding is missing:
|
|
|
26
26
|
- **What:** the problem or opportunity, desired result, accepted behavior, constraints, non-goals, and what would count as success.
|
|
27
27
|
- **How:** the mechanism, dependencies, affected boundaries, tradeoffs, and evidence needed to produce that result in the actual environment.
|
|
28
28
|
|
|
29
|
+
Use [Design for Depth](../design-for-depth/SKILL.md) when representation, identity, ownership, interfaces, algorithms, state, dependencies, or failure behavior materially shape the choice. If unresolved choices could materially change a technical recommendation or invalidate significant dependent work, read its Implementation Decisions method before recommending a mechanism. Use it to explain the differences that matter between viable approaches, not to turn ordinary discussion or a supported local change into an architecture exercise.
|
|
30
|
+
|
|
29
31
|
These questions can be answered together. Reuse what remains supported instead of running two compulsory discovery passes. A detailed request may settle what while leaving how open; an investigation may reveal that the initial problem description was wrong.
|
|
30
32
|
|
|
31
33
|
Keep supported facts and explicit decisions distinct from hypotheses, proposed mechanisms, and unresolved choices. Do not turn an assistant recommendation into a requirement because it is repeated or recorded.
|
|
@@ -57,8 +59,6 @@ Ask about priorities, behavior, constraints, and tradeoffs the user owns. Keep o
|
|
|
57
59
|
|
|
58
60
|
Before recommending a new obligation, distinguish a requirement from a limitation of the current approach. Explain consequences in user terms: "requires changing and distributing a patched host," not merely "needs a provenance interface." Include a simpler in-scope alternative when one is supported. Do not weaken required behavior to make an approach look simpler.
|
|
59
61
|
|
|
60
|
-
Use [Design for Depth](../design-for-depth/SKILL.md) when ownership, interfaces, state, dependencies, or failure behavior materially shape the choice. A lens is not a reason to design a broader system.
|
|
61
|
-
|
|
62
62
|
## Frame And Assess A Learning Action
|
|
63
63
|
|
|
64
64
|
Use an experiment or prototype when existing evidence cannot settle a material question and exercising behavior can distinguish the remaining answers. A separate prototype should isolate the uncertainty more safely or economically than changing production; unfamiliarity alone does not require one.
|