@jstn-sdk/ma 0.1.11 → 0.1.13
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/.codex/agents/Architect.toml +0 -2
- package/.codex/agents/Auditor.toml +0 -2
- package/.codex/agents/Builder.toml +0 -2
- package/.codex/agents/Flow.toml +0 -2
- package/.codex/agents/Sage.toml +0 -2
- package/.codex/agents/Vibe.toml +0 -2
- package/.codex/hooks.json +14 -13
- package/.codex/prompts/enforcement.md +4 -0
- package/.codex/prompts/skill-contract.md +4 -0
- package/COVERAGE.md +211 -0
- package/DEMO.md +265 -0
- package/README.md +287 -37
- package/bin/ma.js +232 -71
- package/data/clone-data.ledger.json +41 -0
- package/data/clone-data.proof.json +50 -0
- package/data/clone-data.rvf +37 -0
- package/docs/README.md +7 -1
- package/docs/getting-started.md +108 -37
- package/docs/installed-sdk.md +23 -0
- package/docs/mcp-setup.md +65 -1
- package/docs/onboarding.md +18 -2
- package/docs/prompt-guidance-contract.md +17 -0
- package/docs/prompt-guidance-fragments/active-autonomy-core.md +7 -0
- package/docs/qa/release-issue-gates-0.1.13.json +644 -0
- package/docs/qa/release-readiness-0.1.13.md +116 -0
- package/docs/qa/release-readiness-0.1.5.md +1 -1
- package/docs/reference/native-engineering-patterns.md +35 -0
- package/docs/reference/native-security-playbooks.md +27 -0
- package/docs/reference/native-source-selection.md +27 -0
- package/docs/reference/native-style-and-deslop.md +20 -0
- package/docs/release-spec.md +37 -10
- package/docs/skills-publishing.md +25 -1
- package/docs/skills.md +37 -12
- package/index.js +222 -2
- package/mcp/collections.json +23 -6
- package/mcp/local/code-intel.js +113 -0
- package/mcp/local/memory.js +46 -0
- package/mcp/local/playbooks.js +168 -0
- package/mcp/local/state.js +71 -0
- package/mcp/local/team-run.js +113 -0
- package/mcp/local/trace.js +60 -0
- package/mcp/local-capabilities.json +56 -0
- package/mcp/native-playbooks.json +117 -0
- package/mcp/servers.json +34 -0
- package/package.json +8 -2
- package/plugins/meta-architect/.app.json +1 -1
- package/plugins/meta-architect/.codex-plugin/plugin.json +4 -4
- package/plugins/meta-architect/.mcp.json +1 -1
- package/plugins/meta-architect/README.md +34 -1
- package/plugins/meta-architect/obsidian/main.js +401 -0
- package/plugins/meta-architect/obsidian/manifest.json +9 -0
- package/plugins/meta-architect/obsidian/styles.css +7 -0
- package/plugins/meta-architect/skills/align/SKILL.md +24 -0
- package/plugins/meta-architect/skills/align/agents/openai.yaml +4 -0
- package/plugins/meta-architect/skills/align/references/shared-language.md +24 -0
- package/plugins/meta-architect/skills/arch/SKILL.md +2 -0
- package/plugins/meta-architect/skills/build/SKILL.md +3 -0
- package/plugins/meta-architect/skills/cleanup/SKILL.md +23 -0
- package/plugins/meta-architect/skills/cleanup/agents/openai.yaml +4 -0
- package/plugins/meta-architect/skills/cleanup/references/style-and-deslop.md +18 -0
- package/plugins/meta-architect/skills/diagnose/SKILL.md +24 -0
- package/plugins/meta-architect/skills/diagnose/agents/openai.yaml +4 -0
- package/plugins/meta-architect/skills/flow/SKILL.md +2 -0
- package/plugins/meta-architect/skills/maestro/SKILL.md +36 -3
- package/plugins/meta-architect/skills/maestro/agents/openai.yaml +2 -2
- package/plugins/meta-architect/skills/maestro/references/native-ingest-map.md +44 -0
- package/plugins/meta-architect/skills/sage/SKILL.md +5 -1
- package/plugins/meta-architect/skills/sage/references/source-selection.md +36 -0
- package/plugins/meta-architect/skills/tdd/SKILL.md +24 -0
- package/plugins/meta-architect/skills/tdd/agents/openai.yaml +4 -0
- package/plugins/meta-architect/skills/vet/SKILL.md +5 -1
- package/plugins/meta-architect/skills/vet/references/security-playbooks.md +30 -0
- package/plugins/meta-architect/skills/vibe/SKILL.md +2 -0
- package/scripts/active-autonomy-hook.mjs +96 -0
- package/scripts/build-linux-packages.mjs +328 -0
- package/scripts/doctor.js +36 -4
- package/scripts/install.sh +28 -0
- package/scripts/linux-package-lib.mjs +40 -0
- package/scripts/linux-package-smoke.mjs +103 -0
- package/scripts/ralph/prompt.md +35 -0
- package/scripts/release-sync.js +13 -6
- package/scripts/release-verify.js +166 -1
- package/skills/align/SKILL.md +24 -0
- package/skills/align/agents/openai.yaml +4 -0
- package/skills/align/references/shared-language.md +24 -0
- package/skills/arch/SKILL.md +2 -0
- package/skills/build/SKILL.md +3 -0
- package/skills/cleanup/SKILL.md +23 -0
- package/skills/cleanup/agents/openai.yaml +4 -0
- package/skills/cleanup/references/style-and-deslop.md +18 -0
- package/skills/diagnose/SKILL.md +24 -0
- package/skills/diagnose/agents/openai.yaml +4 -0
- package/skills/flow/SKILL.md +2 -0
- package/skills/index.json +21 -6
- package/skills/maestro/SKILL.md +36 -3
- package/skills/maestro/agents/openai.yaml +2 -2
- package/skills/maestro/references/native-ingest-map.md +44 -0
- package/skills/sage/SKILL.md +5 -1
- package/skills/sage/references/source-selection.md +36 -0
- package/skills/tdd/SKILL.md +24 -0
- package/skills/tdd/agents/openai.yaml +4 -0
- package/skills/vet/SKILL.md +5 -1
- package/skills/vet/references/security-playbooks.md +30 -0
- package/skills/vibe/SKILL.md +2 -0
- package/src/bootstrap.js +141 -24
- package/src/build-gate.js +2 -2
- package/src/decision-log.js +12 -9
- package/src/launcher.js +4 -0
- package/src/mcp-config.js +130 -8
- package/src/mcp-live-client.js +289 -3
- package/src/paths.js +37 -1
- package/src/policy.js +1 -1
- package/src/release-issue-gates.js +190 -0
- package/src/release-state.js +30 -1
- package/src/runtime/active-autonomy-core.js +208 -0
- package/src/runtime/alignment-sentinel.js +165 -0
- package/src/runtime/architect-review.js +88 -0
- package/src/runtime/build-readiness.js +62 -0
- package/src/runtime/code-graph-rehearse.js +113 -0
- package/src/runtime/context-economy-core.js +276 -0
- package/src/runtime/continuity-notes.js +79 -0
- package/src/runtime/core-source-ingest.js +379 -0
- package/src/runtime/detached-provider.js +74 -0
- package/src/runtime/environment-awareness-core.js +460 -0
- package/src/runtime/exposure-catalog.js +276 -0
- package/src/runtime/guidance-stack.js +42 -0
- package/src/runtime/helper-orchestration-core.js +307 -0
- package/src/runtime/learning-loop-core.js +238 -0
- package/src/runtime/maestro-events.js +18 -0
- package/src/runtime/maestro-manager.js +605 -0
- package/src/runtime/maestro-state.js +125 -0
- package/src/runtime/mcp-policy.js +192 -0
- package/src/runtime/obsidian-integration-core.js +851 -0
- package/src/runtime/obsidian-plugin-bridge.js +739 -0
- package/src/runtime/orchestrator.js +158 -0
- package/src/runtime/prompt-strategy-core.js +230 -0
- package/src/runtime/quorum-review.js +90 -0
- package/src/runtime/ralph-execution-core.js +217 -0
- package/src/runtime/redaction-gateway.js +174 -0
- package/src/runtime/runtime-state.js +1223 -0
- package/src/runtime/semantic-recording-core.js +147 -0
- package/src/runtime/signal-hooks.js +67 -0
- package/src/runtime/skills-registry-export.js +670 -0
- package/src/runtime/startup-path.js +14 -0
- package/src/runtime/universal-plugin-broker-core.js +575 -0
- package/src/runtime/workspace-intelligence-runtime.js +674 -0
- package/src/runtime/workspace-virtualizer.js +102 -0
- package/src/runtime/workspaces.js +25 -0
- package/src/runtime-artifacts.js +407 -84
- package/src/skill-installer.js +53 -5
- package/src/skills.js +1454 -78
- package/src/state-sync.js +51 -8
- package/docs/qa/release-readiness-0.1.11.md +0 -79
- package/plugins/meta-architect/skills/meta-architect/SKILL.md +0 -32
- package/plugins/meta-architect/skills/meta-architect/agents/openai.yaml +0 -4
- package/skills/meta-architect/SKILL.md +0 -32
- package/skills/meta-architect/agents/openai.yaml +0 -4
- /package/plugins/meta-architect/skills/{meta-architect → maestro}/references/core-release-rules.md +0 -0
- /package/skills/{meta-architect → maestro}/references/core-release-rules.md +0 -0
package/scripts/doctor.js
CHANGED
|
@@ -1,15 +1,51 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
|
+
import {
|
|
5
|
+
getDebArtifactName,
|
|
6
|
+
getPacmanArtifactName,
|
|
7
|
+
getRpmArtifactName,
|
|
8
|
+
} from "./linux-package-lib.mjs";
|
|
9
|
+
|
|
10
|
+
const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
|
|
4
11
|
|
|
5
12
|
const checks = [
|
|
6
13
|
["package.json", fs.existsSync("package.json")],
|
|
7
14
|
["skills/index.json", fs.existsSync("skills/index.json")],
|
|
8
15
|
["dist/meta-architect-skills.tgz", fs.existsSync("dist/meta-architect-skills.tgz")],
|
|
16
|
+
[
|
|
17
|
+
`dist/${getDebArtifactName(pkg.version)}`,
|
|
18
|
+
fs.existsSync(`dist/${getDebArtifactName(pkg.version)}`),
|
|
19
|
+
],
|
|
20
|
+
[
|
|
21
|
+
`dist/${getPacmanArtifactName(pkg.version)}`,
|
|
22
|
+
fs.existsSync(`dist/${getPacmanArtifactName(pkg.version)}`),
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
`dist/${getRpmArtifactName(pkg.version)}`,
|
|
26
|
+
fs.existsSync(`dist/${getRpmArtifactName(pkg.version)}`),
|
|
27
|
+
],
|
|
9
28
|
[".codex/hooks.json", fs.existsSync(".codex/hooks.json")],
|
|
10
29
|
[".ma/decisions.json", fs.existsSync(".ma/decisions.json")],
|
|
11
30
|
[".ma/release.json", fs.existsSync(".ma/release.json")],
|
|
31
|
+
[
|
|
32
|
+
".ma/context/helper-orchestration-core.json",
|
|
33
|
+
fs.existsSync(".ma/context/helper-orchestration-core.json"),
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
".ma/context/environment-awareness-core.json",
|
|
37
|
+
fs.existsSync(".ma/context/environment-awareness-core.json"),
|
|
38
|
+
],
|
|
39
|
+
[
|
|
40
|
+
".ma/context/universal-plugin-broker-core.json",
|
|
41
|
+
fs.existsSync(".ma/context/universal-plugin-broker-core.json"),
|
|
42
|
+
],
|
|
12
43
|
["docs/release-spec.md", fs.existsSync("docs/release-spec.md")],
|
|
44
|
+
["DEMO.md", fs.existsSync("DEMO.md")],
|
|
45
|
+
["COVERAGE.md", fs.existsSync("COVERAGE.md")],
|
|
46
|
+
["data/clone-data.proof.json", fs.existsSync("data/clone-data.proof.json")],
|
|
47
|
+
["data/clone-data.ledger.json", fs.existsSync("data/clone-data.ledger.json")],
|
|
48
|
+
["data/clone-data.rvf", fs.existsSync("data/clone-data.rvf")],
|
|
13
49
|
[".agents/plugins/marketplace.json", fs.existsSync(".agents/plugins/marketplace.json")],
|
|
14
50
|
["plugins/meta-architect/.app.json", fs.existsSync("plugins/meta-architect/.app.json")],
|
|
15
51
|
[
|
|
@@ -17,10 +53,6 @@ const checks = [
|
|
|
17
53
|
fs.existsSync("plugins/meta-architect/.codex-plugin/plugin.json"),
|
|
18
54
|
],
|
|
19
55
|
["plugins/meta-architect/.mcp.json", fs.existsSync("plugins/meta-architect/.mcp.json")],
|
|
20
|
-
[
|
|
21
|
-
"missions/collaborative-whiteboard/mission.md",
|
|
22
|
-
fs.existsSync("missions/collaborative-whiteboard/mission.md"),
|
|
23
|
-
],
|
|
24
56
|
["prompts/architect.md", fs.existsSync("prompts/architect.md")],
|
|
25
57
|
];
|
|
26
58
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
MA_PACKAGE="${MA_PACKAGE:-@jstn-sdk/ma@latest}"
|
|
5
|
+
CODEX_PACKAGE="${CODEX_PACKAGE:-@openai/codex@latest}"
|
|
6
|
+
|
|
7
|
+
need_cmd() {
|
|
8
|
+
command -v "$1" >/dev/null 2>&1 || {
|
|
9
|
+
echo "meta-architect install: missing required command: $1" >&2
|
|
10
|
+
exit 1
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
need_cmd npm
|
|
15
|
+
need_cmd node
|
|
16
|
+
|
|
17
|
+
echo "meta-architect install: installing Codex + Meta-Architect"
|
|
18
|
+
npm i -g "$CODEX_PACKAGE" "$MA_PACKAGE"
|
|
19
|
+
|
|
20
|
+
if command -v ma >/dev/null 2>&1; then
|
|
21
|
+
echo "meta-architect install: seeding local MA runtime"
|
|
22
|
+
ma setup >/dev/null
|
|
23
|
+
echo "meta-architect install: ready"
|
|
24
|
+
echo "start: ma --madmax --high"
|
|
25
|
+
else
|
|
26
|
+
echo "meta-architect install: ma command not found after npm install" >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
export const LINUX_PACKAGE_NAME = "meta-architect";
|
|
4
|
+
export const LINUX_PACKAGE_REVISION = "1";
|
|
5
|
+
|
|
6
|
+
export function getPackArtifactName(packageName, version) {
|
|
7
|
+
return `${packageName.replace(/^@/, "").replace("/", "-")}-${version}.tgz`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getPackArtifactPath(distRoot, packageName, version) {
|
|
11
|
+
return path.join(distRoot, getPackArtifactName(packageName, version));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getDebArtifactName(version) {
|
|
15
|
+
return `${LINUX_PACKAGE_NAME}_${version}_all.deb`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getDebArtifactPath(distRoot, version) {
|
|
19
|
+
return path.join(distRoot, getDebArtifactName(version));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function getPacmanArtifactName(version) {
|
|
23
|
+
return `${LINUX_PACKAGE_NAME}-${version}-${LINUX_PACKAGE_REVISION}-any.pkg.tar.xz`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getPacmanArtifactPath(distRoot, version) {
|
|
27
|
+
return path.join(distRoot, getPacmanArtifactName(version));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function getRpmArtifactName(version) {
|
|
31
|
+
return `${LINUX_PACKAGE_NAME}-${version}-${LINUX_PACKAGE_REVISION}.noarch.rpm`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getRpmArtifactPath(distRoot, version) {
|
|
35
|
+
return path.join(distRoot, getRpmArtifactName(version));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getLinuxPackageManifestPath(distRoot) {
|
|
39
|
+
return path.join(distRoot, "linux-package-manifest.json");
|
|
40
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import assert from "node:assert/strict";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import fs from "node:fs/promises";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import process from "node:process";
|
|
9
|
+
import {
|
|
10
|
+
getDebArtifactPath,
|
|
11
|
+
getPacmanArtifactPath,
|
|
12
|
+
getRpmArtifactPath,
|
|
13
|
+
LINUX_PACKAGE_NAME,
|
|
14
|
+
} from "./linux-package-lib.mjs";
|
|
15
|
+
|
|
16
|
+
const repoRoot = process.cwd();
|
|
17
|
+
const pkg = JSON.parse(await fs.readFile(path.join(repoRoot, "package.json"), "utf8"));
|
|
18
|
+
const version = pkg.version;
|
|
19
|
+
const distRoot = path.join(repoRoot, "dist");
|
|
20
|
+
|
|
21
|
+
function run(command, args, options = {}) {
|
|
22
|
+
return spawnSync(command, args, {
|
|
23
|
+
encoding: "utf8",
|
|
24
|
+
stdio: "pipe",
|
|
25
|
+
...options,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function runBinary(command, args, options = {}) {
|
|
30
|
+
return spawnSync(command, args, {
|
|
31
|
+
encoding: null,
|
|
32
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
33
|
+
stdio: "pipe",
|
|
34
|
+
...options,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function smokeExtractedRoot(extractRoot, label) {
|
|
39
|
+
const workRoot = path.join(extractRoot, `${label}-project`);
|
|
40
|
+
const codexHome = path.join(extractRoot, `${label}-codex-home`);
|
|
41
|
+
await fs.mkdir(workRoot, { recursive: true });
|
|
42
|
+
await fs.mkdir(codexHome, { recursive: true });
|
|
43
|
+
const maBin = path.join(extractRoot, "usr", "bin", "ma");
|
|
44
|
+
const env = {
|
|
45
|
+
...process.env,
|
|
46
|
+
CODEX_HOME: codexHome,
|
|
47
|
+
MA_DISABLE_LIVE_MCP: "1",
|
|
48
|
+
META_ARCHITECT_PREFIX: extractRoot,
|
|
49
|
+
};
|
|
50
|
+
const setupResult = run(maBin, ["setup"], { cwd: workRoot, env });
|
|
51
|
+
assert.equal(setupResult.status, 0, setupResult.stderr || setupResult.stdout);
|
|
52
|
+
await fs.access(path.join(workRoot, ".ma", "release.json"));
|
|
53
|
+
await fs.access(path.join(workRoot, ".ma", "decisions.json"));
|
|
54
|
+
await fs.access(path.join(extractRoot, "usr", "bin", "meta-architect"));
|
|
55
|
+
const statusResult = run(maBin, ["status"], { cwd: workRoot, env });
|
|
56
|
+
assert.equal(statusResult.status, 0, statusResult.stderr || statusResult.stdout);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function main() {
|
|
60
|
+
if (process.platform !== "linux") {
|
|
61
|
+
throw new Error("Native Linux package smoke validation is supported only on Linux hosts");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "meta-architect-linux-smoke-"));
|
|
65
|
+
const debExtractRoot = path.join(tempRoot, "deb");
|
|
66
|
+
const pacmanExtractRoot = path.join(tempRoot, "pacman");
|
|
67
|
+
const rpmExtractRoot = path.join(tempRoot, "rpm");
|
|
68
|
+
await fs.mkdir(debExtractRoot, { recursive: true });
|
|
69
|
+
await fs.mkdir(pacmanExtractRoot, { recursive: true });
|
|
70
|
+
await fs.mkdir(rpmExtractRoot, { recursive: true });
|
|
71
|
+
|
|
72
|
+
const debArtifactPath = getDebArtifactPath(distRoot, version);
|
|
73
|
+
const pacmanArtifactPath = getPacmanArtifactPath(distRoot, version);
|
|
74
|
+
const rpmArtifactPath = getRpmArtifactPath(distRoot, version);
|
|
75
|
+
const extractDeb = run("dpkg-deb", ["-x", debArtifactPath, debExtractRoot], { cwd: repoRoot });
|
|
76
|
+
assert.equal(extractDeb.status, 0, extractDeb.stderr || extractDeb.stdout);
|
|
77
|
+
const extractPacman = run("tar", ["-xJf", pacmanArtifactPath, "-C", pacmanExtractRoot], {
|
|
78
|
+
cwd: repoRoot,
|
|
79
|
+
});
|
|
80
|
+
assert.equal(extractPacman.status, 0, extractPacman.stderr || extractPacman.stdout);
|
|
81
|
+
const archiveConversion = runBinary("rpm2archive", [rpmArtifactPath], { cwd: rpmExtractRoot });
|
|
82
|
+
assert.equal(
|
|
83
|
+
archiveConversion.status,
|
|
84
|
+
0,
|
|
85
|
+
archiveConversion.stderr?.toString("utf8") || archiveConversion.stdout?.toString("utf8"),
|
|
86
|
+
);
|
|
87
|
+
const rpmArchivePath = path.join(rpmExtractRoot, `${path.basename(rpmArtifactPath)}.tgz`);
|
|
88
|
+
await fs.writeFile(rpmArchivePath, archiveConversion.stdout);
|
|
89
|
+
const extractRpm = run("tar", ["-xzf", rpmArchivePath, "-C", rpmExtractRoot], { cwd: repoRoot });
|
|
90
|
+
assert.equal(extractRpm.status, 0, extractRpm.stderr || extractRpm.stdout);
|
|
91
|
+
await fs.access(path.join(pacmanExtractRoot, ".PKGINFO"));
|
|
92
|
+
await fs.access(path.join(pacmanExtractRoot, "usr", "lib", LINUX_PACKAGE_NAME, "bin", "ma.js"));
|
|
93
|
+
await fs.access(path.join(rpmExtractRoot, "usr", "lib", LINUX_PACKAGE_NAME, "bin", "ma.js"));
|
|
94
|
+
|
|
95
|
+
await smokeExtractedRoot(debExtractRoot, "deb");
|
|
96
|
+
await smokeExtractedRoot(pacmanExtractRoot, "pacman");
|
|
97
|
+
await smokeExtractedRoot(rpmExtractRoot, "rpm");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
main().catch((error) => {
|
|
101
|
+
console.error(error.message);
|
|
102
|
+
process.exitCode = 1;
|
|
103
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Meta-Architect Ralph Execution Core
|
|
2
|
+
|
|
3
|
+
You are executing a Meta-Architect story contract, not an independent release authority.
|
|
4
|
+
|
|
5
|
+
## Required Inputs
|
|
6
|
+
|
|
7
|
+
1. Read `.ma/plans/prd.json`.
|
|
8
|
+
2. Read `.ma/plans/progress.txt`.
|
|
9
|
+
3. Pick the highest-priority story where `passes` is `false`.
|
|
10
|
+
4. Execute exactly one bounded story per iteration.
|
|
11
|
+
|
|
12
|
+
## MA Quality Gates
|
|
13
|
+
|
|
14
|
+
Before marking a story passed, verify:
|
|
15
|
+
|
|
16
|
+
- `$arch` architecture constraints remain satisfied.
|
|
17
|
+
- `$sage` evidence and source claims remain valid.
|
|
18
|
+
- `$flow` logic/state invariants remain valid.
|
|
19
|
+
- `$vet` security blockers are absent or explicitly owned.
|
|
20
|
+
- `$vibe` DX/UX constraints remain acceptable.
|
|
21
|
+
- `$build` real-workspace checks pass for the changed slice.
|
|
22
|
+
|
|
23
|
+
## Authority Boundaries
|
|
24
|
+
|
|
25
|
+
- Do not mutate `.ma/release.json` or `.ma/decisions.json` directly.
|
|
26
|
+
- Return authoritative status through `$maestro`, `$build`, or the owning lane.
|
|
27
|
+
- Treat Obsidian/vault context as `vault_context`, never `build_evidence`.
|
|
28
|
+
- Treat virtual workspace output as context only, never production proof.
|
|
29
|
+
- Treat code-graph rehearsal as a read-only trajectory preview.
|
|
30
|
+
|
|
31
|
+
## Completion Contract
|
|
32
|
+
|
|
33
|
+
Update story `passes` only after fresh verification evidence exists.
|
|
34
|
+
Append progress to `.ma/plans/progress.txt`.
|
|
35
|
+
Record reusable learnings in scoped guidance without overwriting the base workspace contract.
|
package/scripts/release-sync.js
CHANGED
|
@@ -238,12 +238,6 @@ function syncSupportingCode(oldVersion, nextVersion) {
|
|
|
238
238
|
replacement: `release-readiness-${nextVersion}.md`,
|
|
239
239
|
label: "skills QA path",
|
|
240
240
|
},
|
|
241
|
-
{
|
|
242
|
-
file: path.join("src", "mcp-live-client.js"),
|
|
243
|
-
search: `version: "${oldVersion}"`,
|
|
244
|
-
replacement: `version: "${nextVersion}"`,
|
|
245
|
-
label: "mcp live client version",
|
|
246
|
-
},
|
|
247
241
|
{
|
|
248
242
|
file: path.join("test", "package-install-smoke.test.js"),
|
|
249
243
|
search: `jstn-sdk-ma-${oldVersion}.tgz`,
|
|
@@ -262,6 +256,19 @@ function syncSupportingCode(oldVersion, nextVersion) {
|
|
|
262
256
|
const content = readText(entry.file);
|
|
263
257
|
writeText(entry.file, replaceRequired(content, entry.search, entry.replacement, entry.label));
|
|
264
258
|
}
|
|
259
|
+
|
|
260
|
+
const mcpLiveClientFile = path.join("src", "mcp-live-client.js");
|
|
261
|
+
const mcpLiveClient = readText(mcpLiveClientFile);
|
|
262
|
+
if (!/version: "[0-9]+\.[0-9]+\.[0-9]+(?:-dev)?"/.test(mcpLiveClient)) {
|
|
263
|
+
throw new Error("Expected to find mcp live client version declaration");
|
|
264
|
+
}
|
|
265
|
+
writeText(
|
|
266
|
+
mcpLiveClientFile,
|
|
267
|
+
mcpLiveClient.replace(
|
|
268
|
+
/version: "[0-9]+\.[0-9]+\.[0-9]+(?:-dev)?"/,
|
|
269
|
+
`version: "${nextVersion}-dev"`,
|
|
270
|
+
),
|
|
271
|
+
);
|
|
265
272
|
}
|
|
266
273
|
|
|
267
274
|
function rewriteReleaseState(nextVersion, previousVersion) {
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import process from "node:process";
|
|
6
|
+
import { validateReleaseIssueGates } from "../src/release-issue-gates.js";
|
|
6
7
|
|
|
7
8
|
const CANONICAL_PACKAGE = "@jstn-sdk/ma";
|
|
8
9
|
const CANONICAL_INSTALL = "npm i -g @openai/codex@latest @jstn-sdk/ma@latest";
|
|
10
|
+
const CDN_INSTALL =
|
|
11
|
+
"curl -fsSL https://cdn.jsdelivr.net/gh/JustineDevs/meta-architect@main/scripts/install.sh | sh";
|
|
9
12
|
const CANONICAL_LAUNCH = "ma --madmax --high";
|
|
10
13
|
const UNINSTALL_MA = "npm uninstall -g @jstn-sdk/ma";
|
|
11
14
|
const UNINSTALL_BOTH = "npm uninstall -g @jstn-sdk/ma @openai/codex";
|
|
@@ -40,10 +43,12 @@ function parseVersion(version) {
|
|
|
40
43
|
|
|
41
44
|
function verifyInstallBlock(file) {
|
|
42
45
|
const content = readText(file);
|
|
43
|
-
if (!content.includes(CANONICAL_INSTALL)) {
|
|
46
|
+
if (!content.includes(CANONICAL_INSTALL) && !content.includes(CDN_INSTALL)) {
|
|
44
47
|
return;
|
|
45
48
|
}
|
|
46
49
|
|
|
50
|
+
assert(content.includes(CDN_INSTALL), `${file}: missing jsDelivr POSIX installer command`);
|
|
51
|
+
assert(content.includes(CANONICAL_INSTALL), `${file}: missing canonical npm install command`);
|
|
47
52
|
assert(content.includes(CANONICAL_LAUNCH), `${file}: missing canonical launch command`);
|
|
48
53
|
assert(content.includes(UNINSTALL_MA), `${file}: missing uninstall Meta-Architect command`);
|
|
49
54
|
assert(
|
|
@@ -52,6 +57,146 @@ function verifyInstallBlock(file) {
|
|
|
52
57
|
);
|
|
53
58
|
}
|
|
54
59
|
|
|
60
|
+
function verifyNpmIgnore() {
|
|
61
|
+
assert(fs.existsSync(".npmignore"), ".npmignore: missing production package ignore file");
|
|
62
|
+
const content = readText(".npmignore");
|
|
63
|
+
for (const requiredPattern of [
|
|
64
|
+
".ma/",
|
|
65
|
+
".omx/",
|
|
66
|
+
"node_modules/",
|
|
67
|
+
".npm-cache/",
|
|
68
|
+
"dist/",
|
|
69
|
+
"test/",
|
|
70
|
+
".github/",
|
|
71
|
+
"*.tgz",
|
|
72
|
+
]) {
|
|
73
|
+
assert(
|
|
74
|
+
content.includes(requiredPattern),
|
|
75
|
+
`.npmignore: missing required production ignore pattern ${requiredPattern}`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function verifyDemoDoc({ version, gitTag }) {
|
|
81
|
+
assert(fs.existsSync("DEMO.md"), "DEMO.md: missing demo guide");
|
|
82
|
+
const content = readText("DEMO.md");
|
|
83
|
+
assert(content.includes(`Release line: \`${gitTag}\``), "DEMO.md: wrong release line");
|
|
84
|
+
assert(content.includes("Package: `@jstn-sdk/ma`"), "DEMO.md: missing package name");
|
|
85
|
+
assert(content.includes(CDN_INSTALL), "DEMO.md: missing jsDelivr installer");
|
|
86
|
+
assert(content.includes(CANONICAL_INSTALL), "DEMO.md: missing canonical npm install");
|
|
87
|
+
assert(content.includes(CANONICAL_LAUNCH), "DEMO.md: missing canonical launch");
|
|
88
|
+
assert(content.includes(UNINSTALL_MA), "DEMO.md: missing MA uninstall command");
|
|
89
|
+
assert(content.includes(UNINSTALL_BOTH), "DEMO.md: missing MA + Codex uninstall command");
|
|
90
|
+
assert(content.includes("npm run release:check"), "DEMO.md: missing full release demo command");
|
|
91
|
+
assert(
|
|
92
|
+
content.includes("Learning Loop Core") || content.includes("learning loop"),
|
|
93
|
+
"DEMO.md: missing learning loop coverage",
|
|
94
|
+
);
|
|
95
|
+
assert(content.includes("Obsidian"), "DEMO.md: missing Obsidian coverage");
|
|
96
|
+
assert(content.includes("Ralph"), "DEMO.md: missing Ralph execution coverage");
|
|
97
|
+
assert(content.includes("data/clone-data.proof.json"), "DEMO.md: missing clone-data proof");
|
|
98
|
+
assert(content.includes("COVERAGE.md"), "DEMO.md: missing coverage artifact");
|
|
99
|
+
assert(content.includes(`version line is \`${version}\``), "DEMO.md: missing current version");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function verifyCoverageDoc({ version, gitTag }) {
|
|
103
|
+
assert(fs.existsSync("COVERAGE.md"), "COVERAGE.md: missing coverage matrix");
|
|
104
|
+
const content = readText("COVERAGE.md");
|
|
105
|
+
assert(content.includes(`Target release: \`${gitTag}\``), "COVERAGE.md: wrong target release");
|
|
106
|
+
assert(
|
|
107
|
+
content.includes(`Package: \`@jstn-sdk/ma@${version}\``),
|
|
108
|
+
"COVERAGE.md: wrong package version",
|
|
109
|
+
);
|
|
110
|
+
assert(content.includes("Learning Loop Core"), "COVERAGE.md: missing learning-loop coverage");
|
|
111
|
+
assert(
|
|
112
|
+
content.includes("Helper Orchestration Core"),
|
|
113
|
+
"COVERAGE.md: missing helper orchestration coverage",
|
|
114
|
+
);
|
|
115
|
+
assert(
|
|
116
|
+
content.includes("Environment Awareness Core"),
|
|
117
|
+
"COVERAGE.md: missing environment awareness coverage",
|
|
118
|
+
);
|
|
119
|
+
assert(
|
|
120
|
+
content.includes("Universal Plugin Broker Core"),
|
|
121
|
+
"COVERAGE.md: missing universal plugin broker coverage",
|
|
122
|
+
);
|
|
123
|
+
assert(content.includes("Obsidian Integration Core"), "COVERAGE.md: missing Obsidian coverage");
|
|
124
|
+
assert(content.includes("Ralph Execution Core"), "COVERAGE.md: missing Ralph coverage");
|
|
125
|
+
assert(content.includes("36/36 passing"), "COVERAGE.md: missing current test count");
|
|
126
|
+
assert(
|
|
127
|
+
content.includes("This repository is not a toy demo."),
|
|
128
|
+
"COVERAGE.md: missing truth statement",
|
|
129
|
+
);
|
|
130
|
+
assert(!content.includes("@jstn-sdk/ma@0.1.0"), "COVERAGE.md: stale npm package version");
|
|
131
|
+
assert(!content.includes("v0.1.0 release bar"), "COVERAGE.md: stale release bar");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function verifyCanonicalSemanticSurfaces({ version, gitTag }) {
|
|
135
|
+
const usageWorkflow = readText(path.join("example", "usage-workflow.md"));
|
|
136
|
+
assert(
|
|
137
|
+
usageWorkflow.includes(`$maestro I want to harden Meta-Architect ${gitTag}`),
|
|
138
|
+
"example/usage-workflow.md: missing current $maestro release-hardening scenario",
|
|
139
|
+
);
|
|
140
|
+
for (const requiredTerm of ["Obsidian", "Ralph", "Caveman", "learning-loop"]) {
|
|
141
|
+
assert(
|
|
142
|
+
usageWorkflow.includes(requiredTerm),
|
|
143
|
+
`example/usage-workflow.md: missing ${requiredTerm} semantic-core term`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
for (const staleTerm of [
|
|
147
|
+
"Build a demo",
|
|
148
|
+
"demo app",
|
|
149
|
+
"collaborative whiteboard",
|
|
150
|
+
"smart contract security review",
|
|
151
|
+
"Timeline: 4 weeks",
|
|
152
|
+
"Delivery plan for v0.1.0",
|
|
153
|
+
"@jstn-sdk/ma@0.1.0",
|
|
154
|
+
]) {
|
|
155
|
+
assert(
|
|
156
|
+
!usageWorkflow.includes(staleTerm),
|
|
157
|
+
`example/usage-workflow.md: stale current-facing term ${staleTerm}`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const mission = readText(path.join("missions", "collaborative-whiteboard", "mission.md"));
|
|
162
|
+
assert(
|
|
163
|
+
mission.includes("# Mission: Semantic Release Hardening"),
|
|
164
|
+
"missions/collaborative-whiteboard/mission.md: stale mission title",
|
|
165
|
+
);
|
|
166
|
+
assert(
|
|
167
|
+
mission.includes("Obsidian is core vault-context infrastructure"),
|
|
168
|
+
"missions/collaborative-whiteboard/mission.md: missing Obsidian core mission contract",
|
|
169
|
+
);
|
|
170
|
+
assert(
|
|
171
|
+
mission.includes("Ralph is the execution loop"),
|
|
172
|
+
"missions/collaborative-whiteboard/mission.md: missing Ralph core mission contract",
|
|
173
|
+
);
|
|
174
|
+
assert(
|
|
175
|
+
!mission.toLowerCase().includes("real-time collaborative whiteboard"),
|
|
176
|
+
"missions/collaborative-whiteboard/mission.md: stale whiteboard mission text",
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const currentQa = readText(path.join("docs", "qa", `release-readiness-${version}.md`));
|
|
180
|
+
assert(
|
|
181
|
+
currentQa.includes("Harden Meta-Architect v0.1.13 semantic core"),
|
|
182
|
+
`docs/qa/release-readiness-${version}.md: missing realistic semantic smoke idea`,
|
|
183
|
+
);
|
|
184
|
+
assert(
|
|
185
|
+
!currentQa.includes('ma idea "Build a demo app"'),
|
|
186
|
+
`docs/qa/release-readiness-${version}.md: stale demo-app helper path`,
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
const archPrompt = readText(path.join("prompts", "architect.md"));
|
|
190
|
+
assert(
|
|
191
|
+
!archPrompt.includes("v0.1.0` skills library"),
|
|
192
|
+
"prompts/architect.md: stale v0.1.0 skills-library wording",
|
|
193
|
+
);
|
|
194
|
+
assert(
|
|
195
|
+
archPrompt.includes("current Meta-Architect skills library"),
|
|
196
|
+
"prompts/architect.md: missing current library wording",
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
55
200
|
function main() {
|
|
56
201
|
const pkg = readJson("package.json");
|
|
57
202
|
const lock = readJson("package-lock.json");
|
|
@@ -68,6 +213,13 @@ function main() {
|
|
|
68
213
|
pkg.publishConfig?.access === "public",
|
|
69
214
|
"package.json: publishConfig.access must be public",
|
|
70
215
|
);
|
|
216
|
+
assert(pkg.files?.includes("DEMO.md"), "package.json: files must include DEMO.md");
|
|
217
|
+
assert(pkg.files?.includes("COVERAGE.md"), "package.json: files must include COVERAGE.md");
|
|
218
|
+
|
|
219
|
+
verifyNpmIgnore();
|
|
220
|
+
verifyDemoDoc({ version, gitTag });
|
|
221
|
+
verifyCoverageDoc({ version, gitTag });
|
|
222
|
+
verifyCanonicalSemanticSurfaces({ version, gitTag });
|
|
71
223
|
|
|
72
224
|
const changelog = readText("CHANGELOG.md");
|
|
73
225
|
assert(changelog.includes(`## ${gitTag}`), "CHANGELOG.md: missing current version heading");
|
|
@@ -95,6 +247,17 @@ function main() {
|
|
|
95
247
|
const qa = readText(qaPath);
|
|
96
248
|
assert(qa.includes(`# Release Readiness ${version}`), `${qaPath}: wrong title version`);
|
|
97
249
|
|
|
250
|
+
const issueGatesPath = path.join("docs", "qa", `release-issue-gates-${version}.json`);
|
|
251
|
+
assert(fs.existsSync(issueGatesPath), `Missing release issue gate file: ${issueGatesPath}`);
|
|
252
|
+
const issueGates = validateReleaseIssueGates(readJson(issueGatesPath), {
|
|
253
|
+
version,
|
|
254
|
+
requirePassed: true,
|
|
255
|
+
});
|
|
256
|
+
assert(
|
|
257
|
+
issueGates.valid,
|
|
258
|
+
`${issueGatesPath}: release issue gates are not production-passed\n- ${issueGates.errors.join("\n- ")}`,
|
|
259
|
+
);
|
|
260
|
+
|
|
98
261
|
const pluginApp = readJson(path.join("plugins", "meta-architect", ".app.json"));
|
|
99
262
|
const pluginMcp = readJson(path.join("plugins", "meta-architect", ".mcp.json"));
|
|
100
263
|
const pluginManifest = readJson(
|
|
@@ -109,6 +272,8 @@ function main() {
|
|
|
109
272
|
|
|
110
273
|
for (const file of [
|
|
111
274
|
"README.md",
|
|
275
|
+
"DEMO.md",
|
|
276
|
+
"COVERAGE.md",
|
|
112
277
|
path.join("docs", "getting-started.md"),
|
|
113
278
|
path.join("docs", "onboarding.md"),
|
|
114
279
|
path.join("docs", "skills.md"),
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: align
|
|
3
|
+
description: "Use when the user needs scope alignment, shared language, or docs clarity before or between gated lanes."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Align
|
|
7
|
+
|
|
8
|
+
Use this skill inside Codex when the problem is ambiguity, drift, or mismatched language rather than missing implementation. `align` is a non-gating helper skill.
|
|
9
|
+
|
|
10
|
+
## Output
|
|
11
|
+
|
|
12
|
+
Produce:
|
|
13
|
+
- current ambiguity or mismatch
|
|
14
|
+
- normalized terminology
|
|
15
|
+
- scope boundary and exclusions
|
|
16
|
+
- acceptance checks or rewritten prompts
|
|
17
|
+
- exact next trigger, usually `$maestro` or the lane that owns the next decision
|
|
18
|
+
|
|
19
|
+
## Rules
|
|
20
|
+
|
|
21
|
+
- Align language and scope without creating a new release gate.
|
|
22
|
+
- Prefer tightening existing artifacts over inventing parallel docs.
|
|
23
|
+
- Keep terminology Meta-Architect-native for user-facing surfaces.
|
|
24
|
+
- Use `references/shared-language.md` for naming, taxonomy, and docs-clarity patterns.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Shared Language
|
|
2
|
+
|
|
3
|
+
Use this reference pack with `align` when terminology, scope, or docs are drifting.
|
|
4
|
+
|
|
5
|
+
## Naming rules
|
|
6
|
+
|
|
7
|
+
- `$maestro` is the only umbrella surface.
|
|
8
|
+
- `$arch -> $sage -> $flow -> $vet -> $vibe -> $build` remains the fixed gated sequence.
|
|
9
|
+
- `align`, `diagnose`, `tdd`, and `cleanup` are helper skills only.
|
|
10
|
+
- User-facing guidance stays Meta-Architect-native; external source names may appear as evidence, not as product surfaces.
|
|
11
|
+
|
|
12
|
+
## Alignment checklist
|
|
13
|
+
|
|
14
|
+
- Name the current artifact, lane, and decision owner.
|
|
15
|
+
- Replace vague nouns with one stable term.
|
|
16
|
+
- Separate what is in scope, out of scope, and not yet decided.
|
|
17
|
+
- Rewrite prompts or docs so the next trigger is obvious.
|
|
18
|
+
|
|
19
|
+
## Docs-clarity patterns
|
|
20
|
+
|
|
21
|
+
- Put the next trigger in one line.
|
|
22
|
+
- Distinguish terminal helper commands from in-session skills.
|
|
23
|
+
- Distinguish gated lanes from helper skills.
|
|
24
|
+
- Prefer concise, high-signal wording over long catalogs or branding-heavy lists.
|
package/skills/arch/SKILL.md
CHANGED
|
@@ -11,9 +11,11 @@ Use this skill inside Codex to turn a product idea into a concrete architecture
|
|
|
11
11
|
|
|
12
12
|
Produce:
|
|
13
13
|
- problem framing
|
|
14
|
+
- `decision`, `status`, `evidence`, `blockers`, `next_allowed_triggers`
|
|
14
15
|
- user and workload assumptions
|
|
15
16
|
- system architecture and subsystem boundaries
|
|
16
17
|
- stack recommendation with tradeoffs
|
|
18
|
+
- rejected alternatives with rationale
|
|
17
19
|
- data model and storage choices
|
|
18
20
|
- auth, security, and operational concerns
|
|
19
21
|
- phased delivery plan
|
package/skills/build/SKILL.md
CHANGED
|
@@ -14,11 +14,14 @@ Produce:
|
|
|
14
14
|
- blockers that still prevent implementation
|
|
15
15
|
- the narrowest viable build slice
|
|
16
16
|
- branch or worktree suggestions when relevant
|
|
17
|
+
- bounded execution state when the build lane is already in progress
|
|
17
18
|
- test and verification expectations
|
|
19
|
+
- repair path when the bounded slice needs another pass
|
|
18
20
|
- the exact next implementation step
|
|
19
21
|
|
|
20
22
|
## Rules
|
|
21
23
|
|
|
22
24
|
- Do not claim readiness if architecture, evidence, logic, security, or DX/UX gaps remain unresolved.
|
|
23
25
|
- Keep the recommended build slice small, testable, and reversible.
|
|
26
|
+
- Treat `$build` as the sole owner of `.ma/plans/build.md` and `build_status`.
|
|
24
27
|
- If the user wants code immediately and the path is clear, end with a concrete implementation plan rather than more review prose.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cleanup
|
|
3
|
+
description: "Use when the user wants contract-preserving simplification, anti-slop cleanup, or a final-pass polish after the main decision is made."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cleanup
|
|
7
|
+
|
|
8
|
+
Use this skill inside Codex when the core behavior is understood but the artifact still needs simplification, deslop work, or clearer prose. `cleanup` is a non-gating helper skill.
|
|
9
|
+
|
|
10
|
+
## Output
|
|
11
|
+
|
|
12
|
+
Produce:
|
|
13
|
+
- removable complexity or noisy wording
|
|
14
|
+
- behavior-preserving simplifications
|
|
15
|
+
- residual risks after cleanup
|
|
16
|
+
- exact next trigger, usually the owning lane or release verification
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
|
|
20
|
+
- Prefer deletion over addition.
|
|
21
|
+
- Preserve behavior and decision ownership while cleaning up.
|
|
22
|
+
- Keep user-facing wording concise and product-native.
|
|
23
|
+
- Use `references/style-and-deslop.md` for simplification and prose cleanup patterns.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Style And Deslop
|
|
2
|
+
|
|
3
|
+
Use this reference pack with `cleanup` when an artifact works but still feels bloated, generic, or hard to trust.
|
|
4
|
+
|
|
5
|
+
## Cleanup priorities
|
|
6
|
+
|
|
7
|
+
- remove repeated framing
|
|
8
|
+
- cut placeholder language and empty intensifiers
|
|
9
|
+
- collapse duplicate concepts into one stable term
|
|
10
|
+
- prefer shorter, sharper instructions when they preserve meaning
|
|
11
|
+
- delete unused or non-essential surface area before adding more structure
|
|
12
|
+
|
|
13
|
+
## Safe cleanup checks
|
|
14
|
+
|
|
15
|
+
- behavior or contract is unchanged
|
|
16
|
+
- the next trigger is still explicit
|
|
17
|
+
- helper-vs-gated distinctions remain intact
|
|
18
|
+
- no upstream brand names are introduced as product surfaces
|