@jstn-sdk/ma 0.1.12 → 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/.agents/plugins/marketplace.json +0 -0
- 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 +159 -16
- package/bin/ma.js +219 -14
- 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 +4 -1
- package/docs/assets/image/Screenshot(1).png +0 -0
- package/docs/assets/image/Screenshot(2).png +0 -0
- package/docs/assets/image/Screenshot(3).png +0 -0
- package/docs/assets/image/Screenshot(4).png +0 -0
- package/docs/assets/image/Screenshot(5).png +0 -0
- package/docs/assets/image/Screenshot(6).png +0 -0
- package/docs/assets/image/Screenshot(7).png +0 -0
- package/docs/assets/image/Screenshot(8).png +0 -0
- package/docs/assets/image/Screenshot(9).png +0 -0
- package/docs/assets/meta-architect-logo.png +0 -0
- package/docs/assets/meta-architect-logo.svg +0 -0
- package/docs/getting-started.md +38 -22
- package/docs/installed-sdk.md +0 -0
- package/docs/mcp-setup.md +35 -0
- 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.12.md → release-readiness-0.1.13.md} +25 -9
- package/docs/qa/release-readiness-0.1.5.md +1 -1
- package/docs/reference/native-engineering-patterns.md +0 -0
- package/docs/reference/native-security-playbooks.md +6 -0
- package/docs/reference/native-source-selection.md +6 -0
- package/docs/reference/native-style-and-deslop.md +0 -0
- package/docs/release-spec.md +25 -9
- package/docs/skills.md +14 -1
- package/index.js +222 -2
- package/mcp/collections.json +23 -6
- package/mcp/local/code-intel.js +0 -0
- package/mcp/local/memory.js +0 -0
- package/mcp/local/playbooks.js +0 -0
- package/mcp/local/state.js +0 -0
- package/mcp/local/team-run.js +48 -1
- package/mcp/local/trace.js +0 -0
- package/mcp/local-capabilities.json +0 -0
- package/mcp/native-playbooks.json +0 -0
- package/mcp/servers.json +24 -0
- package/package.json +5 -2
- package/plugins/meta-architect/.app.json +1 -1
- package/plugins/meta-architect/.codex-plugin/plugin.json +1 -1
- package/plugins/meta-architect/.mcp.json +1 -1
- package/plugins/meta-architect/README.md +8 -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 +0 -0
- package/plugins/meta-architect/skills/align/agents/openai.yaml +0 -0
- package/plugins/meta-architect/skills/align/references/shared-language.md +0 -0
- package/plugins/meta-architect/skills/arch/SKILL.md +2 -0
- package/plugins/meta-architect/skills/arch/agents/openai.yaml +0 -0
- package/plugins/meta-architect/skills/build/SKILL.md +3 -0
- package/plugins/meta-architect/skills/build/agents/openai.yaml +0 -0
- package/plugins/meta-architect/skills/cleanup/SKILL.md +0 -0
- package/plugins/meta-architect/skills/cleanup/agents/openai.yaml +0 -0
- package/plugins/meta-architect/skills/cleanup/references/style-and-deslop.md +0 -0
- package/plugins/meta-architect/skills/diagnose/SKILL.md +0 -0
- package/plugins/meta-architect/skills/diagnose/agents/openai.yaml +0 -0
- package/plugins/meta-architect/skills/flow/SKILL.md +2 -0
- package/plugins/meta-architect/skills/flow/agents/openai.yaml +0 -0
- package/plugins/meta-architect/skills/maestro/SKILL.md +0 -0
- package/plugins/meta-architect/skills/maestro/agents/openai.yaml +0 -0
- package/plugins/meta-architect/skills/maestro/references/core-release-rules.md +0 -0
- package/plugins/meta-architect/skills/maestro/references/native-ingest-map.md +0 -0
- package/plugins/meta-architect/skills/sage/SKILL.md +2 -0
- package/plugins/meta-architect/skills/sage/agents/openai.yaml +0 -0
- package/plugins/meta-architect/skills/sage/references/source-selection.md +8 -0
- package/plugins/meta-architect/skills/tdd/SKILL.md +0 -0
- package/plugins/meta-architect/skills/tdd/agents/openai.yaml +0 -0
- package/plugins/meta-architect/skills/vet/SKILL.md +2 -0
- package/plugins/meta-architect/skills/vet/agents/openai.yaml +0 -0
- package/plugins/meta-architect/skills/vet/references/security-playbooks.md +7 -0
- package/plugins/meta-architect/skills/vibe/SKILL.md +2 -0
- package/plugins/meta-architect/skills/vibe/agents/openai.yaml +0 -0
- package/scripts/active-autonomy-hook.mjs +96 -0
- package/scripts/biome-staged.js +0 -0
- package/scripts/build-linux-packages.mjs +0 -0
- package/scripts/doctor.js +17 -4
- package/scripts/install.sh +28 -0
- package/scripts/linux-package-lib.mjs +0 -0
- package/scripts/linux-package-smoke.mjs +0 -0
- package/scripts/plugin-sync.js +0 -0
- package/scripts/postinstall.js +0 -0
- package/scripts/ralph/prompt.md +35 -0
- package/scripts/release-metadata.js +0 -0
- package/scripts/release-sync.js +0 -0
- package/scripts/release-verify.js +166 -1
- package/scripts/setup-npmrc.js +0 -0
- package/skills/align/SKILL.md +0 -0
- package/skills/align/agents/openai.yaml +0 -0
- package/skills/align/references/shared-language.md +0 -0
- package/skills/arch/SKILL.md +2 -0
- package/skills/arch/agents/openai.yaml +0 -0
- package/skills/build/SKILL.md +3 -0
- package/skills/build/agents/openai.yaml +0 -0
- package/skills/cleanup/SKILL.md +0 -0
- package/skills/cleanup/agents/openai.yaml +0 -0
- package/skills/cleanup/references/style-and-deslop.md +0 -0
- package/skills/diagnose/SKILL.md +0 -0
- package/skills/diagnose/agents/openai.yaml +0 -0
- package/skills/flow/SKILL.md +2 -0
- package/skills/flow/agents/openai.yaml +0 -0
- package/skills/maestro/SKILL.md +0 -0
- package/skills/maestro/agents/openai.yaml +0 -0
- package/skills/maestro/references/core-release-rules.md +0 -0
- package/skills/maestro/references/native-ingest-map.md +0 -0
- package/skills/sage/SKILL.md +2 -0
- package/skills/sage/agents/openai.yaml +0 -0
- package/skills/sage/references/source-selection.md +8 -0
- package/skills/tdd/SKILL.md +0 -0
- package/skills/tdd/agents/openai.yaml +0 -0
- package/skills/vet/SKILL.md +2 -0
- package/skills/vet/agents/openai.yaml +0 -0
- package/skills/vet/references/security-playbooks.md +7 -0
- package/skills/vibe/SKILL.md +2 -0
- package/skills/vibe/agents/openai.yaml +0 -0
- package/src/bootstrap.js +17 -0
- package/src/build-gate.js +2 -2
- package/src/launcher.js +4 -0
- package/src/mcp-live-client.js +289 -3
- package/src/paths.js +4 -0
- package/src/policy.js +1 -1
- package/src/release-issue-gates.js +190 -0
- 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 +28 -4
- package/src/runtime/code-graph-rehearse.js +113 -0
- package/src/runtime/context-economy-core.js +276 -0
- package/src/runtime/continuity-notes.js +0 -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 +0 -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 +19 -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 +0 -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 +843 -2
- package/src/runtime/semantic-recording-core.js +147 -0
- package/src/runtime/signal-hooks.js +15 -0
- package/src/runtime/skills-registry-export.js +670 -0
- package/src/runtime/startup-path.js +0 -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 +0 -0
- package/src/runtime-artifacts.js +225 -62
- package/src/skill-installer.js +0 -0
- package/src/skills.js +876 -84
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { ensureDir, readJson, writeFileIfMissing } from "../fs-utils.js";
|
|
2
|
+
import { getRuntimeSubsystemPath } from "../paths.js";
|
|
3
|
+
|
|
4
|
+
export const activeAutonomyCoreSchemaVersion = "0.1.0";
|
|
5
|
+
|
|
6
|
+
export function getActiveAutonomyCorePath() {
|
|
7
|
+
return getRuntimeSubsystemPath("context", "active-autonomy-core.json");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function createDefaultActiveAutonomyCore() {
|
|
11
|
+
return {
|
|
12
|
+
schemaVersion: activeAutonomyCoreSchemaVersion,
|
|
13
|
+
product: "Meta-Architect",
|
|
14
|
+
purpose:
|
|
15
|
+
"Canonical MA contract that prevents passive chatbot behavior across prompts, skills, runtime hooks, and contributor rules.",
|
|
16
|
+
autonomy_directive: {
|
|
17
|
+
placement: "top_of_workspace_contract_before_other_guidance",
|
|
18
|
+
text: [
|
|
19
|
+
"YOU ARE AN AUTONOMOUS META-ARCHITECT WORKSPACE AGENT.",
|
|
20
|
+
"EXECUTE CLEAR, SAFE, REVERSIBLE, ALREADY-REQUESTED WORK TO VERIFIED COMPLETION.",
|
|
21
|
+
"DO NOT ASK WHETHER TO PROCEED ON AUTO-CONTINUE BRANCHES.",
|
|
22
|
+
"ASK ONLY FOR DESTRUCTIVE, IRREVERSIBLE, CREDENTIAL-GATED, EXTERNAL-PRODUCTION, OR MATERIALLY SCOPE-CHANGING ACTIONS.",
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
decision_rule: {
|
|
26
|
+
modes: ["AUTO-CONTINUE", "ASK"],
|
|
27
|
+
auto_continue_when: [
|
|
28
|
+
"clear_user_requested_work",
|
|
29
|
+
"local_or_workspace_scoped",
|
|
30
|
+
"low_risk",
|
|
31
|
+
"reversible",
|
|
32
|
+
"non_destructive",
|
|
33
|
+
"verification_path_available",
|
|
34
|
+
],
|
|
35
|
+
ask_only_when: [
|
|
36
|
+
"destructive_action",
|
|
37
|
+
"irreversible_action",
|
|
38
|
+
"credential_gated_action",
|
|
39
|
+
"external_production_side_effect",
|
|
40
|
+
"material_scope_change",
|
|
41
|
+
"missing_authority_blocks_progress",
|
|
42
|
+
],
|
|
43
|
+
banned_auto_continue_phrasing: [
|
|
44
|
+
"Should I proceed?",
|
|
45
|
+
"Would you like me to continue?",
|
|
46
|
+
"If you want, I can",
|
|
47
|
+
"If you'd like, I can",
|
|
48
|
+
"Tell me if you want me to",
|
|
49
|
+
"I can continue if you want",
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
completion_loop_contract: {
|
|
53
|
+
required_for: [
|
|
54
|
+
"$maestro",
|
|
55
|
+
"$build",
|
|
56
|
+
"ralph_execution_core",
|
|
57
|
+
"executor_roles",
|
|
58
|
+
"team_workers",
|
|
59
|
+
],
|
|
60
|
+
stop_conditions: [
|
|
61
|
+
"verified_complete",
|
|
62
|
+
"user_cancelled",
|
|
63
|
+
"closed_ask_condition_requires_user_input",
|
|
64
|
+
"same_blocker_repeated_three_times_with_no_safe_alternative",
|
|
65
|
+
],
|
|
66
|
+
completion_requires: [
|
|
67
|
+
"fresh_verification_evidence",
|
|
68
|
+
"explicit_outcome",
|
|
69
|
+
"changed_artifacts_or_no_change_reason",
|
|
70
|
+
"known_gaps_or_none",
|
|
71
|
+
],
|
|
72
|
+
terminal_outcomes: ["finished", "blocked", "failed", "cancelled", "askuserQuestion"],
|
|
73
|
+
},
|
|
74
|
+
runtime_enforcement: {
|
|
75
|
+
hook_layer: "active_autonomy_runtime",
|
|
76
|
+
stall_patterns: [
|
|
77
|
+
"should i proceed",
|
|
78
|
+
"would you like me to continue",
|
|
79
|
+
"if you want, i can",
|
|
80
|
+
"if you'd like, i can",
|
|
81
|
+
"tell me if you want me to",
|
|
82
|
+
"i can continue if you want",
|
|
83
|
+
"let me know if you want me to continue",
|
|
84
|
+
],
|
|
85
|
+
default_response:
|
|
86
|
+
"AUTO-CONTINUE: continue the current safe branch, execute the next reversible step, then verify before reporting.",
|
|
87
|
+
native_stop_policy: "block_passive_permission_handoff_when_auto_continue_applies",
|
|
88
|
+
},
|
|
89
|
+
contributor_contract: {
|
|
90
|
+
required_surfaces: [
|
|
91
|
+
"workspace_contract",
|
|
92
|
+
"role_prompts",
|
|
93
|
+
"skill_contracts",
|
|
94
|
+
"runtime_hook_policy",
|
|
95
|
+
"docs",
|
|
96
|
+
"tests",
|
|
97
|
+
],
|
|
98
|
+
regression_targets: [
|
|
99
|
+
"closed_ask_list_present",
|
|
100
|
+
"auto_continue_mode_present",
|
|
101
|
+
"permission_handoff_banned",
|
|
102
|
+
"completion_requires_fresh_evidence",
|
|
103
|
+
"terminal_outcome_required",
|
|
104
|
+
"hook_stall_patterns_present",
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
hard_rules: [
|
|
108
|
+
"Prompt instructions alone are insufficient; runtime hook policy must backstop passive handoffs.",
|
|
109
|
+
"AUTO-CONTINUE branches must state next action or evidence-backed result, not request permission.",
|
|
110
|
+
"ASK branches must name the exact closed-list reason that requires the user.",
|
|
111
|
+
"Completion claims require fresh verification evidence or an explicit validation gap.",
|
|
112
|
+
"Contributor edits must preserve anti-passive prompt patterns and hook policy.",
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function validateActiveAutonomyCore(value) {
|
|
118
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
119
|
+
throw new Error("active autonomy core must be an object");
|
|
120
|
+
}
|
|
121
|
+
if (value.schemaVersion !== activeAutonomyCoreSchemaVersion) {
|
|
122
|
+
throw new Error(`Unsupported active autonomy core schemaVersion: ${value.schemaVersion}`);
|
|
123
|
+
}
|
|
124
|
+
if (!value.decision_rule || typeof value.decision_rule !== "object") {
|
|
125
|
+
throw new Error("active autonomy core requires decision_rule");
|
|
126
|
+
}
|
|
127
|
+
if (!value.decision_rule.modes?.includes("AUTO-CONTINUE")) {
|
|
128
|
+
throw new Error("active autonomy core requires AUTO-CONTINUE mode");
|
|
129
|
+
}
|
|
130
|
+
if (!value.decision_rule.modes?.includes("ASK")) {
|
|
131
|
+
throw new Error("active autonomy core requires ASK mode");
|
|
132
|
+
}
|
|
133
|
+
if (
|
|
134
|
+
!Array.isArray(value.decision_rule.ask_only_when) ||
|
|
135
|
+
value.decision_rule.ask_only_when.length === 0
|
|
136
|
+
) {
|
|
137
|
+
throw new Error("active autonomy core requires closed ask_only_when list");
|
|
138
|
+
}
|
|
139
|
+
if (!value.runtime_enforcement?.stall_patterns?.includes("should i proceed")) {
|
|
140
|
+
throw new Error("active autonomy core requires passive stall pattern coverage");
|
|
141
|
+
}
|
|
142
|
+
if (
|
|
143
|
+
!value.completion_loop_contract?.completion_requires?.includes("fresh_verification_evidence")
|
|
144
|
+
) {
|
|
145
|
+
throw new Error("active autonomy core requires fresh verification evidence");
|
|
146
|
+
}
|
|
147
|
+
if (JSON.stringify(value).includes(".omx")) {
|
|
148
|
+
throw new Error("active autonomy core must not expose OMX runtime paths");
|
|
149
|
+
}
|
|
150
|
+
return value;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function classifyAutonomyBranch({ core, requested = true, riskSignals = [] }) {
|
|
154
|
+
const policy = validateActiveAutonomyCore(core);
|
|
155
|
+
const signals = new Set(riskSignals.map((signal) => `${signal}`.toLowerCase()));
|
|
156
|
+
const askReason = policy.decision_rule.ask_only_when.find((reason) =>
|
|
157
|
+
signals.has(reason.toLowerCase()),
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
if (!requested) {
|
|
161
|
+
return {
|
|
162
|
+
mode: "ASK",
|
|
163
|
+
reason: "missing_authority_blocks_progress",
|
|
164
|
+
permission_handoff_allowed: true,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (askReason) {
|
|
169
|
+
return {
|
|
170
|
+
mode: "ASK",
|
|
171
|
+
reason: askReason,
|
|
172
|
+
permission_handoff_allowed: true,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
mode: "AUTO-CONTINUE",
|
|
178
|
+
reason: "clear_safe_reversible_requested_work",
|
|
179
|
+
permission_handoff_allowed: false,
|
|
180
|
+
next_action_contract:
|
|
181
|
+
"state the next safe action or evidence-backed result; do not ask whether to proceed",
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function detectPassivePermissionHandoff(text, core = createDefaultActiveAutonomyCore()) {
|
|
186
|
+
const policy = validateActiveAutonomyCore(core);
|
|
187
|
+
const normalized = `${text}`.toLowerCase();
|
|
188
|
+
return policy.decision_rule.banned_auto_continue_phrasing.some((phrase) =>
|
|
189
|
+
normalized.includes(
|
|
190
|
+
phrase
|
|
191
|
+
.toLowerCase()
|
|
192
|
+
.replace(/\.\.\.$/, "")
|
|
193
|
+
.trim(),
|
|
194
|
+
),
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export async function seedActiveAutonomyCoreArtifacts() {
|
|
199
|
+
await ensureDir(getRuntimeSubsystemPath("context"));
|
|
200
|
+
await writeFileIfMissing(
|
|
201
|
+
getActiveAutonomyCorePath(),
|
|
202
|
+
`${JSON.stringify(createDefaultActiveAutonomyCore(), null, 2)}\n`,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export async function loadActiveAutonomyCore() {
|
|
207
|
+
return validateActiveAutonomyCore(await readJson(getActiveAutonomyCorePath()));
|
|
208
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { readJson, writeFileIfMissing, writeJson } from "../fs-utils.js";
|
|
2
|
+
import { getRuntimeStatePath } from "../paths.js";
|
|
3
|
+
|
|
4
|
+
const driftRuleDefinitions = [
|
|
5
|
+
{
|
|
6
|
+
skill: "$arch",
|
|
7
|
+
expectedDecisionStatus: "APPROVED",
|
|
8
|
+
releaseField: "architecture_status",
|
|
9
|
+
allowedReleaseValues: ["APPROVED"],
|
|
10
|
+
findingCode: "architecture_status_regressed",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
skill: "$sage",
|
|
14
|
+
expectedDecisionStatus: "VERIFIED",
|
|
15
|
+
releaseField: "evidence_status",
|
|
16
|
+
allowedReleaseValues: ["VERIFIED"],
|
|
17
|
+
findingCode: "evidence_status_regressed",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
skill: "$flow",
|
|
21
|
+
expectedDecisionStatus: "GREEN",
|
|
22
|
+
releaseField: "logic_status",
|
|
23
|
+
allowedReleaseValues: ["GREEN"],
|
|
24
|
+
findingCode: "logic_status_regressed",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
skill: "$vet",
|
|
28
|
+
expectedDecisionStatus: "GREEN",
|
|
29
|
+
releaseField: "security_status",
|
|
30
|
+
allowedReleaseValues: ["GREEN"],
|
|
31
|
+
findingCode: "security_status_regressed",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
skill: "$vibe",
|
|
35
|
+
expectedDecisionStatus: "GREEN",
|
|
36
|
+
releaseField: "experience_status",
|
|
37
|
+
allowedReleaseValues: ["GREEN", "WAIVED"],
|
|
38
|
+
findingCode: "experience_status_regressed",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
skill: "$build",
|
|
42
|
+
expectedDecisionStatus: "DONE",
|
|
43
|
+
releaseField: "build_status",
|
|
44
|
+
allowedReleaseValues: ["DONE"],
|
|
45
|
+
findingCode: "build_status_regressed",
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
export function getAlignmentSentinelPath() {
|
|
50
|
+
return getRuntimeStatePath("alignment-sentinel.json");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function createDefaultAlignmentSentinelReport() {
|
|
54
|
+
return {
|
|
55
|
+
schemaVersion: "0.1.0",
|
|
56
|
+
lastRunAt: null,
|
|
57
|
+
driftStatus: "CLEAR",
|
|
58
|
+
rebootPlanned: false,
|
|
59
|
+
rebootReason: null,
|
|
60
|
+
resumeTrigger: "$maestro",
|
|
61
|
+
baselineArtifacts: [
|
|
62
|
+
".ma/release.json",
|
|
63
|
+
".ma/decisions.json",
|
|
64
|
+
".ma/state/manager-runs.json",
|
|
65
|
+
".ma/state/maestro-state.json",
|
|
66
|
+
],
|
|
67
|
+
findings: [],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function seedAlignmentSentinelArtifacts() {
|
|
72
|
+
await writeFileIfMissing(
|
|
73
|
+
getAlignmentSentinelPath(),
|
|
74
|
+
`${JSON.stringify(createDefaultAlignmentSentinelReport(), null, 2)}\n`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function loadAlignmentSentinelReportOrDefault() {
|
|
79
|
+
try {
|
|
80
|
+
return await readJson(getAlignmentSentinelPath());
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
83
|
+
return createDefaultAlignmentSentinelReport();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function saveAlignmentSentinelReport(report) {
|
|
91
|
+
await writeJson(getAlignmentSentinelPath(), report);
|
|
92
|
+
return report;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getLatestDecisionBySkill(decisions = []) {
|
|
96
|
+
const latestBySkill = new Map();
|
|
97
|
+
for (const decision of decisions) {
|
|
98
|
+
if (!decision?.skill) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
latestBySkill.set(decision.skill, decision);
|
|
103
|
+
}
|
|
104
|
+
return latestBySkill;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function evaluateAlignmentDrift({ releaseState, decisionLog }) {
|
|
108
|
+
const latestDecisions = getLatestDecisionBySkill(decisionLog?.decisions ?? []);
|
|
109
|
+
const findings = [];
|
|
110
|
+
|
|
111
|
+
for (const rule of driftRuleDefinitions) {
|
|
112
|
+
const latestDecision = latestDecisions.get(rule.skill);
|
|
113
|
+
if (!latestDecision || latestDecision.status !== rule.expectedDecisionStatus) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const actualReleaseValue = releaseState?.[rule.releaseField];
|
|
118
|
+
if (rule.allowedReleaseValues.includes(actualReleaseValue)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
findings.push({
|
|
123
|
+
severity: "blocking",
|
|
124
|
+
findingCode: rule.findingCode,
|
|
125
|
+
skill: rule.skill,
|
|
126
|
+
expectedDecisionStatus: rule.expectedDecisionStatus,
|
|
127
|
+
releaseField: rule.releaseField,
|
|
128
|
+
expectedReleaseValues: rule.allowedReleaseValues,
|
|
129
|
+
actualReleaseValue,
|
|
130
|
+
decisionTimestamp: latestDecision.timestamp ?? null,
|
|
131
|
+
decisionSummary: latestDecision.decision ?? null,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
driftStatus: findings.length > 0 ? "DRIFTED" : "CLEAR",
|
|
137
|
+
rebootPlanned: findings.length > 0,
|
|
138
|
+
rebootReason:
|
|
139
|
+
findings.length > 0
|
|
140
|
+
? "Release state drifted from the latest approved lane-owned decisions."
|
|
141
|
+
: null,
|
|
142
|
+
resumeTrigger: "$maestro",
|
|
143
|
+
findings,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function createAlignmentRecoveryPlan(report) {
|
|
148
|
+
const findings = report?.findings ?? [];
|
|
149
|
+
return {
|
|
150
|
+
record_type: "alignment_recovery_plan",
|
|
151
|
+
driftStatus: report?.driftStatus ?? (findings.length > 0 ? "DRIFTED" : "CLEAR"),
|
|
152
|
+
rebootPlanned: findings.length > 0,
|
|
153
|
+
resumeTrigger: report?.resumeTrigger ?? "$maestro",
|
|
154
|
+
requiredActions: findings.map((finding) => ({
|
|
155
|
+
skill: finding.skill,
|
|
156
|
+
repairField: finding.releaseField,
|
|
157
|
+
expectedValues: finding.expectedReleaseValues,
|
|
158
|
+
actualValue: finding.actualReleaseValue,
|
|
159
|
+
action:
|
|
160
|
+
"Rehydrate from baseline runtime artifacts, then rerun the owning lane or restore lane-owned release state before worker dispatch resumes.",
|
|
161
|
+
})),
|
|
162
|
+
mayDispatchWorkers: findings.length === 0,
|
|
163
|
+
mayMutateReleaseStateDirectly: false,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import { readJson, writeFileIfMissing, writeJson } from "../fs-utils.js";
|
|
4
|
+
import { getRuntimeStatePath } from "../paths.js";
|
|
5
|
+
import { redactProviderBoundText, seedRedactionVault } from "./redaction-gateway.js";
|
|
6
|
+
|
|
7
|
+
export function getArchitectReviewPath() {
|
|
8
|
+
return getRuntimeStatePath("architect-review.json");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createDefaultArchitectReview() {
|
|
12
|
+
return {
|
|
13
|
+
schemaVersion: "0.1.0",
|
|
14
|
+
verdict: "NOT_RUN",
|
|
15
|
+
reviewer: null,
|
|
16
|
+
summary: null,
|
|
17
|
+
findings: [],
|
|
18
|
+
reviewedAt: null,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function seedArchitectReviewArtifacts() {
|
|
23
|
+
await writeFileIfMissing(
|
|
24
|
+
getArchitectReviewPath(),
|
|
25
|
+
`${JSON.stringify(createDefaultArchitectReview(), null, 2)}\n`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function loadArchitectReviewOrDefault() {
|
|
30
|
+
try {
|
|
31
|
+
return await readJson(getArchitectReviewPath());
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
34
|
+
return createDefaultArchitectReview();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function saveArchitectReview(review) {
|
|
42
|
+
await writeJson(getArchitectReviewPath(), review);
|
|
43
|
+
return review;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function runExternalArchitectReview({ prompt = "" } = {}) {
|
|
47
|
+
const command = process.env.MA_ARCHITECT_REVIEW_CMD?.trim();
|
|
48
|
+
if (!command) {
|
|
49
|
+
throw new Error("External architect review is not configured. Set MA_ARCHITECT_REVIEW_CMD.");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await seedRedactionVault();
|
|
53
|
+
const redactedPrompt = await redactProviderBoundText(prompt, {
|
|
54
|
+
kind: "architect-review-prompt",
|
|
55
|
+
});
|
|
56
|
+
const promptPath = getRuntimeStatePath("architect-review.prompt.md");
|
|
57
|
+
const outputPath = getRuntimeStatePath("architect-review.output.json");
|
|
58
|
+
await fs.writeFile(promptPath, `${redactedPrompt.sanitizedText.trimEnd()}\n`, "utf8");
|
|
59
|
+
|
|
60
|
+
const result = spawnSync("/bin/sh", ["-lc", command], {
|
|
61
|
+
cwd: process.cwd(),
|
|
62
|
+
env: {
|
|
63
|
+
...process.env,
|
|
64
|
+
MA_ARCHITECT_REVIEW_PROMPT: redactedPrompt.sanitizedText,
|
|
65
|
+
MA_ARCHITECT_REVIEW_PROMPT_FILE: promptPath,
|
|
66
|
+
MA_ARCHITECT_REVIEW_OUTPUT: outputPath,
|
|
67
|
+
},
|
|
68
|
+
encoding: "utf8",
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (result.status !== 0) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
result.stderr?.trim() || result.stdout?.trim() || "External architect review failed",
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const parsed = JSON.parse(await fs.readFile(outputPath, "utf8"));
|
|
78
|
+
const review = {
|
|
79
|
+
schemaVersion: "0.1.0",
|
|
80
|
+
verdict: parsed.verdict ?? "UNKNOWN",
|
|
81
|
+
reviewer: parsed.reviewer ?? "external",
|
|
82
|
+
summary: parsed.summary ?? null,
|
|
83
|
+
findings: Array.isArray(parsed.findings) ? parsed.findings : [],
|
|
84
|
+
reviewedAt: new Date().toISOString(),
|
|
85
|
+
};
|
|
86
|
+
await saveArchitectReview(review);
|
|
87
|
+
return review;
|
|
88
|
+
}
|
|
@@ -4,27 +4,51 @@ import {
|
|
|
4
4
|
formatNextAllowedTriggers,
|
|
5
5
|
} from "../build-gate.js";
|
|
6
6
|
|
|
7
|
-
export function evaluateRuntimeBuildReadiness(releaseState, runtimeSummary) {
|
|
7
|
+
export function evaluateRuntimeBuildReadiness(releaseState, runtimeSummary, options = {}) {
|
|
8
|
+
const enforceIssueGates = options.enforceIssueGates === true;
|
|
8
9
|
const releaseEvaluation = evaluateBuildGate(releaseState);
|
|
10
|
+
const missingArtifacts = runtimeSummary.missingArtifacts.filter(
|
|
11
|
+
(artifact) => enforceIssueGates || artifact !== "release.issueGates",
|
|
12
|
+
);
|
|
9
13
|
const controlPlaneBlockers = [
|
|
10
14
|
...runtimeSummary.invalidArtifacts.filter((artifact) =>
|
|
11
15
|
["runtime.release", "runtime.decisions"].includes(artifact),
|
|
12
16
|
),
|
|
13
|
-
...
|
|
17
|
+
...missingArtifacts.filter(
|
|
14
18
|
(artifact) => artifact === "runtime.release" || artifact === "runtime.decisions",
|
|
15
19
|
),
|
|
16
20
|
];
|
|
17
21
|
const runtimeBlockers = [
|
|
18
22
|
...runtimeSummary.invalidArtifacts.map((artifact) => `runtime artifact ${artifact} is invalid`),
|
|
19
|
-
...
|
|
23
|
+
...missingArtifacts.map((artifact) => `runtime artifact ${artifact} is missing`),
|
|
20
24
|
...(runtimeSummary.pendingMailboxCount > 0
|
|
21
25
|
? ["pending mailbox proposals require leader review"]
|
|
22
26
|
: []),
|
|
27
|
+
...(runtimeSummary.criticalPackageExposureCount > 0
|
|
28
|
+
? [
|
|
29
|
+
`critical package exposure findings require $vet remediation (${runtimeSummary.criticalPackageExposureCount} active)`,
|
|
30
|
+
]
|
|
31
|
+
: []),
|
|
32
|
+
...(runtimeSummary.mcpPolicyViolationCount > 0
|
|
33
|
+
? [
|
|
34
|
+
`MCP policy validation findings require $vet remediation (${runtimeSummary.mcpPolicyViolationCount} active)`,
|
|
35
|
+
]
|
|
36
|
+
: []),
|
|
37
|
+
...(enforceIssueGates && runtimeSummary.releaseIssueGateBlockerCount > 0
|
|
38
|
+
? [
|
|
39
|
+
`release issue gates require implementation proof (${runtimeSummary.releaseIssueGatePassed}/${runtimeSummary.releaseIssueGateTotal} passed)`,
|
|
40
|
+
]
|
|
41
|
+
: []),
|
|
23
42
|
];
|
|
24
43
|
const releaseBlockers = formatBuildBlockers(releaseEvaluation);
|
|
25
44
|
const nextTriggers =
|
|
26
45
|
releaseEvaluation.allowed && runtimeBlockers.length > 0
|
|
27
|
-
?
|
|
46
|
+
? runtimeSummary.criticalPackageExposureCount > 0 ||
|
|
47
|
+
runtimeSummary.mcpPolicyViolationCount > 0
|
|
48
|
+
? ["$vet"]
|
|
49
|
+
: enforceIssueGates && runtimeSummary.releaseIssueGateBlockerCount > 0
|
|
50
|
+
? ["implement release issue gates"]
|
|
51
|
+
: ["repair runtime artifacts"]
|
|
28
52
|
: formatNextAllowedTriggers(releaseEvaluation);
|
|
29
53
|
|
|
30
54
|
return {
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ensureDir, readJson, writeFileIfMissing } from "../fs-utils.js";
|
|
4
|
+
import { getRuntimeSubsystemPath } from "../paths.js";
|
|
5
|
+
|
|
6
|
+
export const codeGraphRehearseSchemaVersion = "0.1.0";
|
|
7
|
+
const defaultMaxSteps = 12;
|
|
8
|
+
|
|
9
|
+
export function getCodeGraphRehearsePath() {
|
|
10
|
+
return getRuntimeSubsystemPath("context", "code-graph-rehearse.json");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createDefaultCodeGraphRehearse() {
|
|
14
|
+
return {
|
|
15
|
+
schemaVersion: codeGraphRehearseSchemaVersion,
|
|
16
|
+
product: "Meta-Architect",
|
|
17
|
+
purpose:
|
|
18
|
+
"Provides a bounded read-only trajectory preview over likely code touchpoints before execution.",
|
|
19
|
+
max_steps: defaultMaxSteps,
|
|
20
|
+
mutation_policy: {
|
|
21
|
+
may_mutate_source: false,
|
|
22
|
+
may_mutate_release_state: false,
|
|
23
|
+
},
|
|
24
|
+
evidence_boundary: {
|
|
25
|
+
records_as: "rehearsal_trace",
|
|
26
|
+
never_records_as: "implementation_evidence",
|
|
27
|
+
does_not_unlock: ["source_mutation", "production_release"],
|
|
28
|
+
},
|
|
29
|
+
applies_to: ["$arch", "$flow", "$build", "executor_roles"],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function validateCodeGraphRehearse(value) {
|
|
34
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
35
|
+
throw new Error("code graph rehearse must be an object");
|
|
36
|
+
}
|
|
37
|
+
if (value.schemaVersion !== codeGraphRehearseSchemaVersion) {
|
|
38
|
+
throw new Error(`Unsupported code graph rehearse schemaVersion: ${value.schemaVersion}`);
|
|
39
|
+
}
|
|
40
|
+
if (!Number.isInteger(value.max_steps) || value.max_steps <= 0) {
|
|
41
|
+
throw new Error("code graph rehearse requires positive max_steps");
|
|
42
|
+
}
|
|
43
|
+
if (value.mutation_policy?.may_mutate_source !== false) {
|
|
44
|
+
throw new Error("code graph rehearse must not mutate source");
|
|
45
|
+
}
|
|
46
|
+
if (value.evidence_boundary?.records_as !== "rehearsal_trace") {
|
|
47
|
+
throw new Error("code graph rehearse must record as rehearsal_trace");
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function seedCodeGraphRehearseArtifacts() {
|
|
53
|
+
await ensureDir(getRuntimeSubsystemPath("context"));
|
|
54
|
+
await writeFileIfMissing(
|
|
55
|
+
getCodeGraphRehearsePath(),
|
|
56
|
+
`${JSON.stringify(createDefaultCodeGraphRehearse(), null, 2)}\n`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function loadCodeGraphRehearse() {
|
|
61
|
+
return validateCodeGraphRehearse(await readJson(getCodeGraphRehearsePath()));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function createCodeGraphTouchpoint(filePath, imports = []) {
|
|
65
|
+
return {
|
|
66
|
+
path: filePath,
|
|
67
|
+
extension: path.extname(filePath),
|
|
68
|
+
imports: imports.filter((entry) => typeof entry === "string" && entry.trim()),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function extractStaticImports(sourceText) {
|
|
73
|
+
const imports = new Set();
|
|
74
|
+
const patterns = [
|
|
75
|
+
/import\s+(?:[^'"]+\s+from\s+)?["']([^"']+)["']/g,
|
|
76
|
+
/export\s+[^'"]+\s+from\s+["']([^"']+)["']/g,
|
|
77
|
+
/await\s+import\(["']([^"']+)["']\)/g,
|
|
78
|
+
/import\(["']([^"']+)["']\)/g,
|
|
79
|
+
/require\(["']([^"']+)["']\)/g,
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
for (const pattern of patterns) {
|
|
83
|
+
for (const match of sourceText.matchAll(pattern)) {
|
|
84
|
+
if (match[1]) {
|
|
85
|
+
imports.add(match[1]);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return [...imports].sort();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function createCodeGraphTouchpointFromFile(filePath) {
|
|
94
|
+
const sourceText = await fs.readFile(filePath, "utf8");
|
|
95
|
+
return createCodeGraphTouchpoint(filePath, extractStaticImports(sourceText));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function createRehearsalTrace({ story, touchpoints = [], plannedSteps = [], maxSteps }) {
|
|
99
|
+
const limit = Number.isInteger(maxSteps) && maxSteps > 0 ? maxSteps : defaultMaxSteps;
|
|
100
|
+
const boundedSteps = plannedSteps.slice(0, limit);
|
|
101
|
+
return {
|
|
102
|
+
record_type: "rehearsal_trace",
|
|
103
|
+
story,
|
|
104
|
+
bounded: plannedSteps.length <= limit,
|
|
105
|
+
truncated: plannedSteps.length > limit,
|
|
106
|
+
max_steps: limit,
|
|
107
|
+
steps: boundedSteps,
|
|
108
|
+
touchpoints,
|
|
109
|
+
source_mutation_allowed: false,
|
|
110
|
+
production_evidence: false,
|
|
111
|
+
does_not_unlock: ["source_mutation", "production_release"],
|
|
112
|
+
};
|
|
113
|
+
}
|