@groundnuty/macf 0.2.7 → 0.2.9
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/dist/.build-info.json +2 -2
- package/dist/cli/commands/doctor.d.ts +86 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +140 -1
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/settings-writer.d.ts +34 -0
- package/dist/cli/settings-writer.d.ts.map +1 -1
- package/dist/cli/settings-writer.js +63 -0
- package/dist/cli/settings-writer.js.map +1 -1
- package/package.json +2 -2
- package/plugin/rules/coordination.md +20 -0
- package/plugin/rules/mention-routing-hygiene.md +25 -1
- package/plugin/rules/pr-discipline.md +95 -0
- package/plugin/rules/silent-fallback-hazards.md +290 -0
- package/scripts/check-mention-routing.sh +19 -3
package/dist/.build-info.json
CHANGED
|
@@ -64,6 +64,92 @@ export interface SandboxFdCheck {
|
|
|
64
64
|
* still needs to see what broke.
|
|
65
65
|
*/
|
|
66
66
|
export declare function checkSandboxFdAllowRead(workspaceDir: string): SandboxFdCheck;
|
|
67
|
+
/**
|
|
68
|
+
* Tools whose absence from `permissions.allow` blocks autonomous
|
|
69
|
+
* coordination — Claude Code prompts the operator on each first
|
|
70
|
+
* invocation, stalling agents that can't dismiss the prompt.
|
|
71
|
+
*
|
|
72
|
+
* Surfaced empirically during cv-e2e-test rehearsal #11b
|
|
73
|
+
* (2026-04-30): cv-architect on `groundnuty/academic-resume` blocked
|
|
74
|
+
* mid-test on a Write tool prompt because the workspace's
|
|
75
|
+
* `permissions.allow` lacked `Write`. Sister CV agent
|
|
76
|
+
* `cv-project-archaeologist` had the entry; this was operator-
|
|
77
|
+
* authored drift.
|
|
78
|
+
*/
|
|
79
|
+
export declare const AUTONOMY_REQUIRED_TOOLS: readonly string[];
|
|
80
|
+
/**
|
|
81
|
+
* Returns true if `allow` grants the named tool unrestricted use:
|
|
82
|
+
* - Bare tool name (`"Write"`) — Claude Code's "tool only" form
|
|
83
|
+
* - Glob form (`"Write(*)"`)
|
|
84
|
+
*
|
|
85
|
+
* Scoped patterns like `Write(/specific/path)` are NOT considered
|
|
86
|
+
* "fully present" — they cover only that path; calls to other paths
|
|
87
|
+
* still prompt. Conservative-by-design: an operator with scoped Write
|
|
88
|
+
* still gets a warning that surfaces the partial coverage.
|
|
89
|
+
*/
|
|
90
|
+
export declare function isToolFullyAllowed(allow: readonly string[], tool: string): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Returns true if `deny` has any entry referencing the named tool —
|
|
93
|
+
* either bare (`"Write"`) or scoped (`"Write(/path)"`). Used to
|
|
94
|
+
* contextualise an allow-list gap as deliberate (security-driven,
|
|
95
|
+
* common in operator-restricted workspaces) rather than accidental
|
|
96
|
+
* drift. Soft signal — doctor still warns, just with a different
|
|
97
|
+
* framing.
|
|
98
|
+
*/
|
|
99
|
+
export declare function hasToolDeny(deny: readonly string[], tool: string): boolean;
|
|
100
|
+
/**
|
|
101
|
+
* One per-tool finding from the permissions-allow check.
|
|
102
|
+
*
|
|
103
|
+
* `severity`:
|
|
104
|
+
* - `WARN` — tool absent but Bash fallback exists (Edit absent, OR
|
|
105
|
+
* Write absent + Bash present). Autonomous coordination still works
|
|
106
|
+
* for code paths that use Bash; tool-using paths prompt.
|
|
107
|
+
* - `INFO` — tool absent AND deny rule exists. Treated as deliberate
|
|
108
|
+
* operator decision (security posture) rather than drift. Surfaces
|
|
109
|
+
* the gap so it's visible, but doesn't recommend fix.
|
|
110
|
+
* - `BLOCK` — tool absent AND no fallback (Write + Edit + Bash all
|
|
111
|
+
* absent). Autonomous coordination fails entirely on first agentic
|
|
112
|
+
* file op.
|
|
113
|
+
*
|
|
114
|
+
* Doctor exit code is unchanged by this check (per #296 AC: warn-only,
|
|
115
|
+
* no error). Severity drives output formatting + remediation suggestion.
|
|
116
|
+
*/
|
|
117
|
+
export interface PermissionFinding {
|
|
118
|
+
readonly tool: string;
|
|
119
|
+
readonly severity: 'WARN' | 'INFO' | 'BLOCK';
|
|
120
|
+
readonly hasBashFallback: boolean;
|
|
121
|
+
readonly hasDenyRule: boolean;
|
|
122
|
+
readonly message: string;
|
|
123
|
+
readonly remediation: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Result of the permissions-allow check (macf#296). `findings` lists
|
|
127
|
+
* one entry per missing autonomy-required tool; `status` summarises
|
|
128
|
+
* across them — `PASS` if no findings, `WARN` if any non-INFO finding,
|
|
129
|
+
* `INFO` if all findings are deliberate-deny cases.
|
|
130
|
+
*/
|
|
131
|
+
export interface PermissionsAllowCheckResult {
|
|
132
|
+
readonly status: 'PASS' | 'WARN' | 'INFO';
|
|
133
|
+
readonly findings: readonly PermissionFinding[];
|
|
134
|
+
/** Set when the JSON was malformed; `findings` will be empty. */
|
|
135
|
+
readonly readError?: string;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Check that `permissions.allow` grants the autonomy-required tools
|
|
139
|
+
* (`Write`, `Edit`). For each absent tool, build a `PermissionFinding`
|
|
140
|
+
* with severity tuned to the failure mode (BLOCK if no Bash fallback,
|
|
141
|
+
* WARN if Bash works, INFO if a deny rule signals deliberate scope).
|
|
142
|
+
*
|
|
143
|
+
* Sister CV reference: cv-project-archaeologist's settings.json has
|
|
144
|
+
* Write+Edit; academic-resume drifted without them. Surfaces here at
|
|
145
|
+
* health-check time rather than mid-coordination block.
|
|
146
|
+
*
|
|
147
|
+
* Schema reference: Claude Code permissions.allow accepts both bare
|
|
148
|
+
* tool names ("Write") and patterned forms ("Write(*)", "Write(/path)").
|
|
149
|
+
* Verified against the canonical settings.json schema documented in
|
|
150
|
+
* Claude Code's update-config skill (stable form across recent versions).
|
|
151
|
+
*/
|
|
152
|
+
export declare function checkPermissionsAllow(workspaceDir: string): PermissionsAllowCheckResult;
|
|
67
153
|
/**
|
|
68
154
|
* Format a non-leaking error message when `gh token generate --jwt` returns
|
|
69
155
|
* output that doesn't look like a JWT. Shows only the first 6 characters
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { execFileSync } from 'node:child_process';
|
|
18
18
|
import { readAgentConfig, tokenSourceFromConfig } from '../config.js';
|
|
19
|
-
import { getSandboxAllowRead, SANDBOX_FD_READ_PATTERN } from '../settings-writer.js';
|
|
19
|
+
import { getPermissionsAllow, getPermissionsDeny, getSandboxAllowRead, SANDBOX_FD_READ_PATTERN, } from '../settings-writer.js';
|
|
20
20
|
/**
|
|
21
21
|
* DR-019 permission doctrine. Keep in sync with
|
|
22
22
|
* design/decisions/DR-019-app-permissions.md and
|
|
@@ -101,6 +101,124 @@ export function checkSandboxFdAllowRead(workspaceDir) {
|
|
|
101
101
|
detail: `allowRead does not contain ${SANDBOX_FD_READ_PATTERN} — run \`macf update\` to refresh`,
|
|
102
102
|
};
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Tools whose absence from `permissions.allow` blocks autonomous
|
|
106
|
+
* coordination — Claude Code prompts the operator on each first
|
|
107
|
+
* invocation, stalling agents that can't dismiss the prompt.
|
|
108
|
+
*
|
|
109
|
+
* Surfaced empirically during cv-e2e-test rehearsal #11b
|
|
110
|
+
* (2026-04-30): cv-architect on `groundnuty/academic-resume` blocked
|
|
111
|
+
* mid-test on a Write tool prompt because the workspace's
|
|
112
|
+
* `permissions.allow` lacked `Write`. Sister CV agent
|
|
113
|
+
* `cv-project-archaeologist` had the entry; this was operator-
|
|
114
|
+
* authored drift.
|
|
115
|
+
*/
|
|
116
|
+
export const AUTONOMY_REQUIRED_TOOLS = ['Write', 'Edit'];
|
|
117
|
+
/**
|
|
118
|
+
* Returns true if `allow` grants the named tool unrestricted use:
|
|
119
|
+
* - Bare tool name (`"Write"`) — Claude Code's "tool only" form
|
|
120
|
+
* - Glob form (`"Write(*)"`)
|
|
121
|
+
*
|
|
122
|
+
* Scoped patterns like `Write(/specific/path)` are NOT considered
|
|
123
|
+
* "fully present" — they cover only that path; calls to other paths
|
|
124
|
+
* still prompt. Conservative-by-design: an operator with scoped Write
|
|
125
|
+
* still gets a warning that surfaces the partial coverage.
|
|
126
|
+
*/
|
|
127
|
+
export function isToolFullyAllowed(allow, tool) {
|
|
128
|
+
return allow.includes(tool) || allow.includes(`${tool}(*)`);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Returns true if `deny` has any entry referencing the named tool —
|
|
132
|
+
* either bare (`"Write"`) or scoped (`"Write(/path)"`). Used to
|
|
133
|
+
* contextualise an allow-list gap as deliberate (security-driven,
|
|
134
|
+
* common in operator-restricted workspaces) rather than accidental
|
|
135
|
+
* drift. Soft signal — doctor still warns, just with a different
|
|
136
|
+
* framing.
|
|
137
|
+
*/
|
|
138
|
+
export function hasToolDeny(deny, tool) {
|
|
139
|
+
for (const entry of deny) {
|
|
140
|
+
if (entry === tool || entry.startsWith(`${tool}(`))
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Check that `permissions.allow` grants the autonomy-required tools
|
|
147
|
+
* (`Write`, `Edit`). For each absent tool, build a `PermissionFinding`
|
|
148
|
+
* with severity tuned to the failure mode (BLOCK if no Bash fallback,
|
|
149
|
+
* WARN if Bash works, INFO if a deny rule signals deliberate scope).
|
|
150
|
+
*
|
|
151
|
+
* Sister CV reference: cv-project-archaeologist's settings.json has
|
|
152
|
+
* Write+Edit; academic-resume drifted without them. Surfaces here at
|
|
153
|
+
* health-check time rather than mid-coordination block.
|
|
154
|
+
*
|
|
155
|
+
* Schema reference: Claude Code permissions.allow accepts both bare
|
|
156
|
+
* tool names ("Write") and patterned forms ("Write(*)", "Write(/path)").
|
|
157
|
+
* Verified against the canonical settings.json schema documented in
|
|
158
|
+
* Claude Code's update-config skill (stable form across recent versions).
|
|
159
|
+
*/
|
|
160
|
+
export function checkPermissionsAllow(workspaceDir) {
|
|
161
|
+
let allow;
|
|
162
|
+
let deny;
|
|
163
|
+
try {
|
|
164
|
+
allow = getPermissionsAllow(workspaceDir);
|
|
165
|
+
deny = getPermissionsDeny(workspaceDir);
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
return {
|
|
169
|
+
status: 'WARN',
|
|
170
|
+
findings: [],
|
|
171
|
+
readError: err instanceof Error ? err.message : String(err),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const hasBashFallback = isToolFullyAllowed(allow, 'Bash');
|
|
175
|
+
const findings = [];
|
|
176
|
+
for (const tool of AUTONOMY_REQUIRED_TOOLS) {
|
|
177
|
+
if (isToolFullyAllowed(allow, tool))
|
|
178
|
+
continue;
|
|
179
|
+
const hasDenyRule = hasToolDeny(deny, tool);
|
|
180
|
+
const isWrite = tool === 'Write';
|
|
181
|
+
let severity;
|
|
182
|
+
let message;
|
|
183
|
+
if (hasDenyRule) {
|
|
184
|
+
severity = 'INFO';
|
|
185
|
+
message =
|
|
186
|
+
`${tool} absent from permissions.allow; deny rule present — likely deliberate scope ` +
|
|
187
|
+
`(security posture). Autonomous file ops via ${tool} will prompt; agents can fall ` +
|
|
188
|
+
`back to Bash where allowed.`;
|
|
189
|
+
}
|
|
190
|
+
else if (isWrite && !hasBashFallback) {
|
|
191
|
+
severity = 'BLOCK';
|
|
192
|
+
message =
|
|
193
|
+
`Write absent AND Bash absent — autonomous file creation impossible. ` +
|
|
194
|
+
`Agents will block on every Write/Bash invocation waiting for operator click-through.`;
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
severity = 'WARN';
|
|
198
|
+
message =
|
|
199
|
+
`${tool} absent from permissions.allow — autonomous ${tool} tool calls fire interactive ` +
|
|
200
|
+
`permission prompts. Sister CV agent cv-project-archaeologist has this entry; if this ` +
|
|
201
|
+
`workspace is also a CV/coordination consumer, the gap is likely operator-authored drift ` +
|
|
202
|
+
`(empirical incident: cv-e2e-test rehearsal #11b 2026-04-30).` +
|
|
203
|
+
(isWrite ? ' Bash fallback is present, so file-write via shell still works (degraded autonomy).' : '');
|
|
204
|
+
}
|
|
205
|
+
const remediation = `Add to .claude/settings.json under permissions.allow: "${tool}" (bare; allows all paths) ` +
|
|
206
|
+
`OR "${tool}(*)" (glob form). For scoped use, prefer "${tool}(/path/*)" patterns + matching ` +
|
|
207
|
+
`deny rules for sensitive paths.`;
|
|
208
|
+
findings.push({
|
|
209
|
+
tool,
|
|
210
|
+
severity,
|
|
211
|
+
hasBashFallback,
|
|
212
|
+
hasDenyRule,
|
|
213
|
+
message,
|
|
214
|
+
remediation,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
if (findings.length === 0)
|
|
218
|
+
return { status: 'PASS', findings: [] };
|
|
219
|
+
const allInfo = findings.every((f) => f.severity === 'INFO');
|
|
220
|
+
return { status: allInfo ? 'INFO' : 'WARN', findings };
|
|
221
|
+
}
|
|
104
222
|
/**
|
|
105
223
|
* Format a non-leaking error message when `gh token generate --jwt` returns
|
|
106
224
|
* output that doesn't look like a JWT. Shows only the first 6 characters
|
|
@@ -228,6 +346,27 @@ export async function runDoctor(projectDir) {
|
|
|
228
346
|
if (sandboxCheck.detail)
|
|
229
347
|
console.log(` ${sandboxCheck.detail}`);
|
|
230
348
|
}
|
|
349
|
+
console.log('');
|
|
350
|
+
console.log('Workspace permissions (macf#296)');
|
|
351
|
+
console.log('──────────────────────────────────────────────────────────────');
|
|
352
|
+
const permsCheck = checkPermissionsAllow(projectDir);
|
|
353
|
+
if (permsCheck.readError) {
|
|
354
|
+
console.log(` ⚠ could not parse .claude/settings.json: ${permsCheck.readError}`);
|
|
355
|
+
}
|
|
356
|
+
else if (permsCheck.status === 'PASS') {
|
|
357
|
+
console.log(` ✓ permissions.allow grants Write + Edit (autonomous coordination unblocked) [PASS]`);
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
const summary = permsCheck.status === 'INFO'
|
|
361
|
+
? `ℹ ${permsCheck.findings.length} autonomy-required tool(s) absent (deny rules present — likely deliberate) [INFO]`
|
|
362
|
+
: `⚠ ${permsCheck.findings.length} autonomy-required tool(s) absent or scoped [WARN]`;
|
|
363
|
+
console.log(` ${summary}`);
|
|
364
|
+
for (const f of permsCheck.findings) {
|
|
365
|
+
const symbol = f.severity === 'BLOCK' ? '✗' : (f.severity === 'WARN' ? '⚠' : 'ℹ');
|
|
366
|
+
console.log(` ${symbol} ${f.tool}: ${f.message}`);
|
|
367
|
+
console.log(` Fix: ${f.remediation}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
231
370
|
const permissionsFailed = finding.missing.length > 0 || finding.insufficient.length > 0;
|
|
232
371
|
const sandboxFailed = sandboxCheck.status === 'FAIL';
|
|
233
372
|
return permissionsFailed || sandboxFailed ? 1 : 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAWrF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAkC;IACtE,EAAE,IAAI,EAAE,UAAU,EAAW,KAAK,EAAE,MAAM,EAAG,GAAG,EAAE,yCAAyC,EAAE;IAC7F,EAAE,IAAI,EAAE,UAAU,EAAW,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,uCAAuC,EAAE;IAC3F,EAAE,IAAI,EAAE,QAAQ,EAAa,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,4DAA4D,EAAE;IAChH,EAAE,IAAI,EAAE,eAAe,EAAM,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,kCAAkC,EAAE;IACtF,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,uEAAuE,EAAE;IAC3H,EAAE,IAAI,EAAE,WAAW,EAAU,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,0CAA0C,EAAE;IAC9F,EAAE,IAAI,EAAE,SAAS,EAAY,KAAK,EAAE,MAAM,EAAG,GAAG,EAAE,gDAAgD,EAAE;CACrG,CAAC;AAYF;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAwC;IACtE,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,MAAM,YAAY,GAAuD,EAAE,CAAC;IAC5E,KAAK,MAAM,GAAG,IAAI,yBAAyB,EAAE,CAAC;QAC5C,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClB,SAAS;QACX,CAAC;QACD,iEAAiE;QACjE,iEAAiE;QACjE,IAAI,GAAG,CAAC,KAAK,KAAK,OAAO,IAAI,WAAW,KAAK,MAAM,EAAE,CAAC;YACpD,YAAY,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAuB,EACvB,MAA0B;IAE1B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,KAAK,IAAI,aAAa,QAAQ,wBAAwB,GAAG,CAAC,GAAG,EAAE,CAAC;IACzE,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,GAAG,CAAC,KAAK,KAAK,OAAO,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QAC/C,OAAO,KAAK,IAAI,aAAa,QAAQ,WAAW,SAAS,0BAA0B,CAAC;IACtF,CAAC;IACD,OAAO,KAAK,IAAI,aAAa,QAAQ,WAAW,SAAS,EAAE,CAAC;AAC9D,CAAC;AAkBD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CAAC,YAAoB;IAC1D,IAAI,SAA4B,CAAC;IACjC,IAAI,CAAC;QACH,SAAS,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACtF,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;QAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACxC,CAAC;IACD,OAAO;QACL,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,8BAA8B,uBAAuB,mCAAmC;KACjG,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,OAAO,CACL,qDAAqD;QACrD,YAAY,UAAU,aAAa,GAAG,CAAC,MAAM,GAAG,CACjD,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,KAAa,EACb,SAAiB,EACjB,OAAe;IAEf,yEAAyE;IACzE,0EAA0E;IAC1E,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE;YACvB,OAAO,EAAE,UAAU;YACnB,UAAU,EAAE,KAAK;YACjB,OAAO,EAAE,OAAO;YAChB,OAAO;YACP,cAAc;SACf,EAAE;YACD,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,IAAI,KAAK,CACb,mCAAmC,GAAG,IAAI;YAC1C,0DAA0D,EAC1D,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,4CAA4C,SAAS,EAAE,EAAE;QACpF,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,GAAG,EAAE;YAC9B,MAAM,EAAE,6BAA6B;YACrC,sBAAsB,EAAE,YAAY;SACrC;KACF,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC;QAC5D,MAAM,IAAI,KAAK,CACb,0BAA0B,SAAS,aAAa,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CACzF,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA8B,CAAC;IACpE,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,MAAM,CAAC,WAAqC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,UAAkB;IAChD,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QAClE,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,MAAM,GAAG,qBAAqB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACzD,IAAI,WAAmC,CAAC;IACxC,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,4BAA4B,CAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAC/C,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5E,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,OAAO,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAE7C,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;IAC9E,KAAK,MAAM,GAAG,IAAI,yBAAyB,EAAE,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,mBAAmB,CAAC,GAAG,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,MAAM,aAAa,GAAG,yBAAyB,CAAC,MAAM,CAAC;IACvD,MAAM,SAAS,GAAG,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC;IACvF,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC;QAC9E,CAAC,CAAC,oCAAoC;QACtC,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,OAAO,aAAa,+CAA+C,CAAC;IACjI,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,KAAK,SAAS,IAAI,aAAa,aAAa,CAAC,CAAC;IAErE,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACxB,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,KAAK,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC7B,KAAK,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,OAAO,QAAQ,CAAC,IAAI,UAAU,MAAM,UAAU,QAAQ,CAAC,KAAK,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QAChG,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;QACrF,OAAO,CAAC,GAAG,CAAC,qFAAqF,CAAC,CAAC;QACnG,OAAO,CAAC,GAAG,CAAC,kFAAkF,CAAC,CAAC;IAClG,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;IAC9E,MAAM,YAAY,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC;IACzD,IAAI,YAAY,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,6CAA6C,uBAAuB,UAAU,CAAC,CAAC;IAC9F,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,4CAA4C,uBAAuB,wCAAwC,CAAC,CAAC;QACzH,IAAI,YAAY,CAAC,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,OAAO,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;IACxF,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,KAAK,MAAM,CAAC;IACrD,OAAO,iBAAiB,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC"}
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -84,6 +84,40 @@ export declare const SANDBOX_FD_READ_PATTERN = "/proc/self/fd";
|
|
|
84
84
|
* JSON-read + deep-narrow logic in two places.
|
|
85
85
|
*/
|
|
86
86
|
export declare function getSandboxAllowRead(workspaceDir: string): readonly string[];
|
|
87
|
+
/**
|
|
88
|
+
* Read the workspace-effective `permissions.allow` array — merge of
|
|
89
|
+
* `.claude/settings.json` + `.claude/settings.local.json` (macf#305).
|
|
90
|
+
*
|
|
91
|
+
* Per Claude Code's canonical settings semantics, `permissions.allow` /
|
|
92
|
+
* `deny` / `ask` arrays MERGE/concatenate across scopes (not replace —
|
|
93
|
+
* opposite to scalar settings which higher-priority scopes replace).
|
|
94
|
+
* The doctor's effective-permissions check therefore unions both
|
|
95
|
+
* scopes; an entry present in EITHER file counts as granted.
|
|
96
|
+
*
|
|
97
|
+
* Duplicates are removed. Empty array if neither file exists. Throws
|
|
98
|
+
* on malformed JSON in either file (the path is in the error message,
|
|
99
|
+
* surfacing which file failed to parse).
|
|
100
|
+
*
|
|
101
|
+
* Used by `macf doctor` (macf#296 / #298) to surface allow-list gaps
|
|
102
|
+
* that would block autonomous coordination — specifically Write/Edit
|
|
103
|
+
* absence causing interactive permission prompts mid-test. Pre-#305
|
|
104
|
+
* the helper read settings.json only; this caused false-positive WARNs
|
|
105
|
+
* on workspaces where operators canonically placed Write/Edit in
|
|
106
|
+
* settings.local.json (as cv-architect / cv-project-archaeologist did
|
|
107
|
+
* after the macf#302 substrate-side drift workaround).
|
|
108
|
+
*/
|
|
109
|
+
export declare function getPermissionsAllow(workspaceDir: string): readonly string[];
|
|
110
|
+
/**
|
|
111
|
+
* Read the workspace-effective `permissions.deny` array — sister to
|
|
112
|
+
* `getPermissionsAllow`. Same merge semantics: union of
|
|
113
|
+
* settings.json + settings.local.json deny arrays, deduped (macf#305).
|
|
114
|
+
*
|
|
115
|
+
* Used to detect operator-authored deny rules that contextualise an
|
|
116
|
+
* allow-list gap as deliberate (security-driven) rather than
|
|
117
|
+
* accidental drift. A deny rule in EITHER scope counts; the doctor's
|
|
118
|
+
* INFO-severity classification fires on the union.
|
|
119
|
+
*/
|
|
120
|
+
export declare function getPermissionsDeny(workspaceDir: string): readonly string[];
|
|
87
121
|
/**
|
|
88
122
|
* Install (or refresh) the `/proc/self/fd` entry in
|
|
89
123
|
* `.claude/settings.json`'s `sandbox.filesystem.allowRead` array.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-writer.d.ts","sourceRoot":"","sources":["../../src/cli/settings-writer.ts"],"names":[],"mappings":"AAuBA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,0DAA0D,CAAC;AAEzF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,iEAAiE,CAAC;AA6DxG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAKrD,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAS3E;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA+CpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EA0CtD,CAAC;AAWF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA8CzE;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAQlF;AASD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA+BxE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA0C7D"}
|
|
1
|
+
{"version":3,"file":"settings-writer.d.ts","sourceRoot":"","sources":["../../src/cli/settings-writer.ts"],"names":[],"mappings":"AAuBA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,0DAA0D,CAAC;AAEzF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,iEAAiE,CAAC;AA6DxG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAKrD,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAS3E;AAmBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAM3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAM1E;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA+CpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EA0CtD,CAAC;AAWF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA8CzE;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAQlF;AASD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA+BxE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA0C7D"}
|
|
@@ -157,6 +157,69 @@ export function getSandboxAllowRead(workspaceDir) {
|
|
|
157
157
|
return [];
|
|
158
158
|
return list.filter((v) => typeof v === 'string');
|
|
159
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Read `permissions.<key>` from a single settings file path. Returns an
|
|
162
|
+
* empty array if the file is absent, no `permissions` block, or the array
|
|
163
|
+
* isn't a string list. Throws on malformed JSON via `readSettings`.
|
|
164
|
+
*
|
|
165
|
+
* Internal helper — `getPermissionsAllow` / `getPermissionsDeny` use this
|
|
166
|
+
* to read each scope (settings.json + settings.local.json) before
|
|
167
|
+
* merging.
|
|
168
|
+
*/
|
|
169
|
+
function readPermissionsArray(filePath, key) {
|
|
170
|
+
const settings = readSettings(filePath);
|
|
171
|
+
const permissionsRaw = settings['permissions'] ?? {};
|
|
172
|
+
const list = permissionsRaw[key];
|
|
173
|
+
if (!Array.isArray(list))
|
|
174
|
+
return [];
|
|
175
|
+
return list.filter((v) => typeof v === 'string');
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Read the workspace-effective `permissions.allow` array — merge of
|
|
179
|
+
* `.claude/settings.json` + `.claude/settings.local.json` (macf#305).
|
|
180
|
+
*
|
|
181
|
+
* Per Claude Code's canonical settings semantics, `permissions.allow` /
|
|
182
|
+
* `deny` / `ask` arrays MERGE/concatenate across scopes (not replace —
|
|
183
|
+
* opposite to scalar settings which higher-priority scopes replace).
|
|
184
|
+
* The doctor's effective-permissions check therefore unions both
|
|
185
|
+
* scopes; an entry present in EITHER file counts as granted.
|
|
186
|
+
*
|
|
187
|
+
* Duplicates are removed. Empty array if neither file exists. Throws
|
|
188
|
+
* on malformed JSON in either file (the path is in the error message,
|
|
189
|
+
* surfacing which file failed to parse).
|
|
190
|
+
*
|
|
191
|
+
* Used by `macf doctor` (macf#296 / #298) to surface allow-list gaps
|
|
192
|
+
* that would block autonomous coordination — specifically Write/Edit
|
|
193
|
+
* absence causing interactive permission prompts mid-test. Pre-#305
|
|
194
|
+
* the helper read settings.json only; this caused false-positive WARNs
|
|
195
|
+
* on workspaces where operators canonically placed Write/Edit in
|
|
196
|
+
* settings.local.json (as cv-architect / cv-project-archaeologist did
|
|
197
|
+
* after the macf#302 substrate-side drift workaround).
|
|
198
|
+
*/
|
|
199
|
+
export function getPermissionsAllow(workspaceDir) {
|
|
200
|
+
const absDir = resolve(workspaceDir);
|
|
201
|
+
const claudeDir = join(absDir, '.claude');
|
|
202
|
+
const main = readPermissionsArray(join(claudeDir, 'settings.json'), 'allow');
|
|
203
|
+
const local = readPermissionsArray(join(claudeDir, 'settings.local.json'), 'allow');
|
|
204
|
+
return Array.from(new Set([...main, ...local]));
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Read the workspace-effective `permissions.deny` array — sister to
|
|
208
|
+
* `getPermissionsAllow`. Same merge semantics: union of
|
|
209
|
+
* settings.json + settings.local.json deny arrays, deduped (macf#305).
|
|
210
|
+
*
|
|
211
|
+
* Used to detect operator-authored deny rules that contextualise an
|
|
212
|
+
* allow-list gap as deliberate (security-driven) rather than
|
|
213
|
+
* accidental drift. A deny rule in EITHER scope counts; the doctor's
|
|
214
|
+
* INFO-severity classification fires on the union.
|
|
215
|
+
*/
|
|
216
|
+
export function getPermissionsDeny(workspaceDir) {
|
|
217
|
+
const absDir = resolve(workspaceDir);
|
|
218
|
+
const claudeDir = join(absDir, '.claude');
|
|
219
|
+
const main = readPermissionsArray(join(claudeDir, 'settings.json'), 'deny');
|
|
220
|
+
const local = readPermissionsArray(join(claudeDir, 'settings.local.json'), 'deny');
|
|
221
|
+
return Array.from(new Set([...main, ...local]));
|
|
222
|
+
}
|
|
160
223
|
/**
|
|
161
224
|
* Legacy MACF-managed patterns that earlier CLI versions wrote to
|
|
162
225
|
* `allowRead`. Dropped from the array before installing the current
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-writer.js","sourceRoot":"","sources":["../../src/cli/settings-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,uDAAuD,CAAC;AAEzF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,8DAA8D,CAAC;AAExG;;;;GAIG;AACH,MAAM,mBAAmB,GAAsB;IAC7C,mBAAmB;IACnB,0BAA0B;CAC3B,CAAC;AAEF;;;;;;GAMG;AACH,SAAS,oBAAoB,CAAC,OAAe;IAC3C,iEAAiE;IACjE,6EAA6E;IAC7E,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IACjE,OAAO,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAChD,CAAC;AAqBD,SAAS,YAAY,CAAC,IAAY;IAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAa,CAAC;IACrC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,4DAA4D,IAAI,KAAM,GAAa,CAAC,OAAO,IAAI;YAC7F,gDAAgD,EAClD,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAsB;IACzD,+BAA+B;IAC/B,+BAA+B;IAC/B,8BAA8B;IAC9B,6BAA6B;CAC9B,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,eAAe,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,YAAoB;IACtD,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,UAAU,GAAI,QAAQ,CAAC,SAAS,CAAyC,IAAI,EAAE,CAAC;IACtF,MAAM,aAAa,GAAI,UAAU,CAAC,YAAY,CAAyC,IAAI,EAAE,CAAC;IAC9F,MAAM,IAAI,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,uBAAuB,GAAsB;IACjD,kBAAkB;CACnB,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,yBAAyB,CAAC,YAAoB;IAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IACrD,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO;IAE5C,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAE9C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,iEAAiE;IACjE,kEAAkE;IAClE,MAAM,UAAU,GAAI,QAAQ,CAAC,SAAS,CAAyC,IAAI,EAAE,CAAC;IACtF,MAAM,aAAa,GAAI,UAAU,CAAC,YAAY,CAAyC,IAAI,EAAE,CAAC;IAC9F,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QAC7D,CAAC,CAAE,aAAa,CAAC,WAAW,CAAwB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QACtG,CAAC,CAAC,EAAE,CAAC;IAEP,iEAAiE;IACjE,kEAAkE;IAClE,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CACpC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,uBAAuB,CAAC,QAAQ,CAAC,KAAK,CAAC,CACpD,CAAC;IAEF,gEAAgE;IAChE,6DAA6D;IAC7D,IAAI,SAAS,CAAC,MAAM,KAAK,aAAa,CAAC,MAAM,IAAI,SAAS,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;QAC7F,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QAC3D,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,CAAC,GAAG,SAAS,EAAE,uBAAuB,CAAC,CAAC;IAE5C,MAAM,OAAO,GAAa;QACxB,GAAG,QAAQ;QACX,OAAO,EAAE;YACP,GAAG,UAAU;YACb,UAAU,EAAE;gBACV,GAAG,aAAa;gBAChB,SAAS;aACV;SACF;KACF,CAAC;IAEF,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAsB;IAC1D,0BAA0B;IAC1B,OAAO;IACP,OAAO;IACP,SAAS;IACT,UAAU;IACV,OAAO;IACP,OAAO;IACP,OAAO;IACP,aAAa;IACb,MAAM;IACN,OAAO;IACP,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,WAAW;IACX,uBAAuB;IACvB,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,MAAM;IACN,MAAM;IACN,QAAQ;IACR,OAAO;IACP,OAAO;IACP,QAAQ;IACR,SAAS;IACT,0DAA0D;IAC1D,qDAAqD;IACrD,QAAQ;IACR,MAAM;IACN,SAAS;IACT,yDAAyD;IACzD,2DAA2D;IAC3D,SAAS;IACT,MAAM;IACN,SAAS;CACV,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,6BAA6B,GAAsB,EAAE,CAAC;AAE5D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,8BAA8B,CAAC,YAAoB;IACjE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IAChE,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO;IAE5C,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAE9C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,mEAAmE;IACnE,yDAAyD;IACzD,MAAM,UAAU,GAAI,QAAQ,CAAC,SAAS,CAAyC,IAAI,EAAE,CAAC;IACtF,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;QAC5D,CAAC,CAAE,UAAU,CAAC,kBAAkB,CAAwB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QAC1G,CAAC,CAAC,EAAE,CAAC;IAEP,6DAA6D;IAC7D,gEAAgE;IAChE,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAC/B,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,6BAA6B,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC1D,CAAC;IAEF,4DAA4D;IAC5D,gEAAgE;IAChE,4CAA4C;IAC5C,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,yBAAyB,EAAE,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC;IAED,8DAA8D;IAC9D,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,CAAC;IACrD,MAAM,WAAW,GAAG,UAAU,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,IAAI,WAAW;QAAE,OAAO;IAExB,MAAM,OAAO,GAAa;QACxB,GAAG,QAAQ;QACX,OAAO,EAAE;YACP,GAAG,UAAU;YACb,gBAAgB,EAAE,MAAM;SACzB;KACF,CAAC;IAEF,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CAAC,YAAoB;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,UAAU,GAAI,QAAQ,CAAC,SAAS,CAAyC,IAAI,EAAE,CAAC;IACtF,MAAM,IAAI,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;AAChE,CAAC;AAED;;;;GAIG;AACH,MAAM,yBAAyB,GAAG,mBAAmB,CAAC;AAEtD;;;;;;;;GAQG;AACH,MAAM,UAAU,6BAA6B,CAAC,YAAoB;IAChE,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAE9C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAK,QAAQ,CAAC,aAAa,CAAyB,CAAC,OAAO,CAAC,CAAC;QACvH,CAAC,CAAC,CAAE,QAAQ,CAAC,aAAa,CAAkC,CAAC,KAAK,CAAC;QACnE,CAAC,CAAC,EAAE,CAAC;IAEP,+DAA+D;IAC/D,mEAAmE;IACnE,4DAA4D;IAC5D,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CACpC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,yBAAyB,CAAC,CACrF,CAAC;IAEF,MAAM,KAAK,GAAa,CAAC,GAAG,SAAS,EAAE,GAAG,wBAAwB,CAAC,CAAC;IAEpE,MAAM,mBAAmB,GAAI,QAAQ,CAAC,aAAa,CAAyC,IAAI,EAAE,CAAC;IACnG,MAAM,OAAO,GAAa;QACxB,GAAG,QAAQ;QACX,WAAW,EAAE;YACX,GAAG,mBAAmB;YACtB,KAAK;SACN;KACF,CAAC;IAEF,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,kBAAkB,CAAC,YAAoB;IACrD,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IAE9C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;IAE1C,wDAAwD;IACxD,uEAAuE;IACvE,qEAAqE;IACrE,2DAA2D;IAC3D,0DAA0D;IAC1D,oEAAoE;IACpE,sCAAsC;IACtC,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CACjC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CACrE,CAAC;IAEF,MAAM,WAAW,GAAyB;QACxC;YACE,OAAO,EAAE,MAAM;YACf,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;SACzD;QACD;YACE,OAAO,EAAE,MAAM;YACf,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC;SACjE;KACF,CAAC;IAEF,MAAM,OAAO,GAAa;QACxB,GAAG,QAAQ;QACX,KAAK,EAAE;YACL,GAAG,KAAK;YACR,UAAU,EAAE,CAAC,GAAG,SAAS,EAAE,GAAG,WAAW,CAAC;SAC3C;KACF,CAAC;IAEF,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC/D,CAAC"}
|
|
1
|
+
{"version":3,"file":"settings-writer.js","sourceRoot":"","sources":["../../src/cli/settings-writer.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@groundnuty/macf",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "Multi-Agent Coordination Framework CLI — coordinate Claude Code agents via GitHub. Installs as `macf` binary; use `macf init` to set up an agent workspace, `macf update` to refresh rules + version pins.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"test:watch": "vitest"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@groundnuty/macf-core": "0.2.
|
|
38
|
+
"@groundnuty/macf-core": "0.2.9",
|
|
39
39
|
"commander": "^14.0.3",
|
|
40
40
|
"reflect-metadata": "^0.2.2",
|
|
41
41
|
"zod": "^4.0.0"
|
|
@@ -36,6 +36,26 @@ The rules here are topology-agnostic: they work whether the project uses a scien
|
|
|
36
36
|
|
|
37
37
|
**Why this rule matters:** Reporter-owns-closure gives the reporter a chance to verify the fix matches their intent before the issue disappears from their queue. In a multi-agent workflow, the reporter often has context the implementer doesn't (why it was filed at that priority, what the acceptance criteria really meant, what adjacent work it blocks). Auto-close strips that context; reflexive handoff on self-filed issues wastes it.
|
|
38
38
|
|
|
39
|
+
**Inversion warning — closure direction is independent of who implemented the fix.** A common failure mode after PR-merge handoffs: the reporter mistakes the implementer for the closer because the implementer just finished the work. Rule 1A says **reporter** owns closure, NOT **fix-author**:
|
|
40
|
+
|
|
41
|
+
*(The 4 cases below assume merge-by-implementer per `pr-discipline.md` — `implementer == merger`. Different topologies expand the table accordingly.)*
|
|
42
|
+
|
|
43
|
+
- **You filed the issue + you implemented the PR + you merged it** → **you close** (you're both reporter AND implementer).
|
|
44
|
+
- **You filed the issue + a peer implemented the PR + the peer merged it** → **you still close** (you're the reporter; the peer is implementer-but-not-reporter; their action ends at "post handoff comment + stop" per failure mode A).
|
|
45
|
+
- **A peer filed the issue + you implemented + you merged the PR** → **the peer closes** (they're the reporter; you @mention them with `ready for you to close when verified` per failure mode A).
|
|
46
|
+
- **A peer filed the issue + a peer implemented + a peer merged the PR** → **reporter closes**; you're observer.
|
|
47
|
+
|
|
48
|
+
The trap is symmetric to failure mode A. Failure mode A is "I close someone else's issue because I implemented the fix" (forgetting that fix-author ≠ reporter); the inverse is "I tell the implementer to self-close my issue because they merged the fix" (same forgetting, opposite direction). Both are the same conceptual mistake — substituting fix-authorship for issue-reportership.
|
|
49
|
+
|
|
50
|
+
**Reinforced self-check after any PR-merge that addresses an issue:**
|
|
51
|
+
|
|
52
|
+
gh issue view <N> --json author --jq '.author.login'
|
|
53
|
+
|
|
54
|
+
- Output is YOUR login → **YOU close** with verification comment (regardless of who implemented). Run `gh issue close <N> --reason completed --comment "..."`.
|
|
55
|
+
- Output is the peer's login → **THEY close**. Post `@<author> PR #M merged, ready for you to close when verified.` and STOP. Don't try to delegate the closure mechanics back to yourself.
|
|
56
|
+
|
|
57
|
+
This check is one cheap shell command; the inversion is silent (the recipient may not catch it if they're not paying attention to attribution).
|
|
58
|
+
|
|
39
59
|
2. **Work through the queue without prompting.** When an issue is complete, check your assigned-label queue and pick up the next one immediately. Do NOT ask the reporter to ping you or reply "continue" before starting. Only wait when (a) your PR is in review, or (b) the queue is empty. If an issue is ambiguous, ask clarifying questions on that issue and move to the next queued one while waiting.
|
|
40
60
|
|
|
41
61
|
3. **Never remove your own agent label.** Status labels (`in-progress`, `in-review`, `blocked`) swap as work moves; assignment labels stay.
|
|
@@ -58,7 +58,9 @@ If a comment contains both describing and addressing references to the same agen
|
|
|
58
58
|
|
|
59
59
|
For any comment or PR body that contains agent handles, grep the draft:
|
|
60
60
|
|
|
61
|
-
grep -nE '@
|
|
61
|
+
grep -nE '@[a-zA-Z][a-zA-Z0-9_-]*\[bot\]' <draft-file>
|
|
62
|
+
|
|
63
|
+
(This pattern matches the broadened `HANDLE_PATTERN` documented in §7 — covers macf-* fleet, future CV fleet, and third-party bots like `dependabot[bot]` / `github-actions[bot]`.)
|
|
62
64
|
|
|
63
65
|
For each line returned: is this line an action ask (raw stays) or a content reference (backticks wrap)?
|
|
64
66
|
|
|
@@ -118,6 +120,28 @@ The hook is the same shape as `check-gh-token.sh` (#140 attribution-trap defense
|
|
|
118
120
|
- At line-start (after optional whitespace, blockquote `>`, or list-item markers `* ` / `- ` / `1. `) → allowed (canonical addressing form §3)
|
|
119
121
|
- Otherwise → BLOCK with stderr citing this rule + the offending line + the `MACF_SKIP_MENTION_CHECK=1` operator override
|
|
120
122
|
|
|
123
|
+
**Pattern scope (broadened per macf#276):** the hook's `HANDLE_PATTERN` matches ANY `@<handle>[bot]` shape — not just `@macf-*-agent[bot]`. Specifically:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
HANDLE_PATTERN='@[a-zA-Z][a-zA-Z0-9_-]*[[]bot[]]'
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Coverage:
|
|
130
|
+
|
|
131
|
+
- **macf-* fleet** (`macf-code-agent`, `macf-science-agent`, `macf-tester-N-agent`, `macf-devops-agent`) — original target.
|
|
132
|
+
- **Future CV fleet** (`cv-architect`, `academic-resume-author`, similar shapes) — naming convention may not follow `<prefix>-*-agent`; the broadened pattern accommodates whatever shapes consumer projects choose.
|
|
133
|
+
- **Future MACF-consumer fleets** — same logic; durable across naming conventions.
|
|
134
|
+
- **Third-party bots** (`dependabot`, `github-actions`) — these don't fire MACF routing (not in the agent registry, so the routing-Action workflow drops them silently), but blocking their describing-context use is consistent style. Operators can use `MACF_SKIP_MENTION_CHECK=1` for the rare legitimate describing-context use of a third-party bot handle.
|
|
135
|
+
|
|
136
|
+
The first-character-must-be-letter constraint excludes `@1bot[bot]` / `@_bot[bot]` / `@-bot[bot]` / `@[bot]` (no handle body) — none of which are valid GitHub handles anyway.
|
|
137
|
+
|
|
138
|
+
**Note on code blocks (clarification per macf#277):** The hook does NOT parse Markdown structure. Triple-backtick fences and 4-space-indent code blocks are both currently passed by the hook, but the *mechanism* differs:
|
|
139
|
+
|
|
140
|
+
- **Triple-backtick code blocks** — pass via the *adjacent-backtick check* in the heuristic (the `` ` `` characters bracketing the block satisfy the "already wrapped in backticks" predicate at the handle's character positions).
|
|
141
|
+
- **4-space-indented code blocks** — pass via the *line-start addressing allowance*, not via code-block recognition. The leading whitespace satisfies the line-start regex `^[[:space:]>]*([0-9]+\.[[:space:]]+|[-*][[:space:]]+)?` ahead of `@<bot>[bot]`, so the line is treated as addressing form (§3) and allowed. Same outcome as the triple-backtick case, different reasoning.
|
|
142
|
+
|
|
143
|
+
This is a heuristic side-effect, not an explicit code-block parser. If a future refinement tightens the line-start allowance (e.g., requires the FIRST non-whitespace character on the line to be `@`), 4-space-indented examples would need explicit backtick-wrapping or the `MACF_SKIP_MENTION_CHECK=1` override on the affected `gh ... comment` invocation. GitHub's renderer parses code blocks correctly regardless — the documented routing-firing risk (§2) is unaffected by the hook's heuristic.
|
|
144
|
+
|
|
121
145
|
**False-positive trade-off:** The heuristic leans toward false-positive over false-negative. Edge cases the heuristic flags:
|
|
122
146
|
|
|
123
147
|
- Single-line bodies with addressing form right after `--body "` (no preceding newline) — operator should typically put addressing on its own line in multi-line bodies
|
|
@@ -154,6 +154,101 @@ foreign-reporter, use `Refs` for all of them.
|
|
|
154
154
|
|
|
155
155
|
---
|
|
156
156
|
|
|
157
|
+
## How to submit LGTM — formal review, not comment
|
|
158
|
+
|
|
159
|
+
**LGTM and "request changes" decisions MUST be submitted as formal GitHub
|
|
160
|
+
reviews via `gh pr review --approve` or `gh pr review --request-changes`,
|
|
161
|
+
not as plain `gh pr comment` text.**
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# CORRECT — formal review submission
|
|
165
|
+
gh pr review <PR-number> --repo <owner>/<repo> --approve --body-file <review.md>
|
|
166
|
+
|
|
167
|
+
# CORRECT — formal request-changes submission
|
|
168
|
+
gh pr review <PR-number> --repo <owner>/<repo> --request-changes --body-file <review.md>
|
|
169
|
+
|
|
170
|
+
# WRONG — review communicated only via issue/PR comment
|
|
171
|
+
gh pr comment <PR-number> --repo <owner>/<repo> --body "LGTM, you can merge"
|
|
172
|
+
gh issue comment <issue-N> --repo <owner>/<repo> --body "@<author> LGTM on PR #M"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Why this matters structurally:**
|
|
176
|
+
|
|
177
|
+
Formal review submission fires GitHub's `pull_request_review` webhook
|
|
178
|
+
event with `state in {approved, changes_requested}`. The MACF routing
|
|
179
|
+
Action's `route-by-pr-review-state` job (macf-actions v3.3.0+, per
|
|
180
|
+
macf-actions#39) listens for this exact event and notifies the PR author's
|
|
181
|
+
channel-server directly — independent of whether the reviewer @mentioned
|
|
182
|
+
the author in the body. **This is the structural defense for the
|
|
183
|
+
LGTM→merge handoff: the state-change IS the wake signal.**
|
|
184
|
+
|
|
185
|
+
If the LGTM is communicated only as a plain `gh pr comment`,
|
|
186
|
+
`pull_request_review` never fires; routing falls back to `route-by-mention`
|
|
187
|
+
which depends on body parsing (and `mention-routing-hygiene.md §5`
|
|
188
|
+
backtick-suppression discipline can suppress what looks like an addressing
|
|
189
|
+
mention). Empirically observed: cv-e2e-test rehearsals #9, #10, #11b
|
|
190
|
+
(2026-04-29 and 2026-04-30) — agents merged PRs without firing
|
|
191
|
+
`pull_request_review` at all, leaving `route-by-pr-review-state` an
|
|
192
|
+
untested code path despite being shipped via macf-actions v3.3.0.
|
|
193
|
+
|
|
194
|
+
**Same shape as the silent-fallback hazard class (`silent-fallback-hazards.md`):
|
|
195
|
+
the comment-form succeeds at the API boundary (`gh pr comment` returns 0)
|
|
196
|
+
but the semantic outcome (wake recipient via routing-Action's structural
|
|
197
|
+
defense) silently doesn't happen. Pattern A defense at the discipline
|
|
198
|
+
layer: assert the LGTM uses a state-change-firing mechanism, not just
|
|
199
|
+
text-on-the-thread.**
|
|
200
|
+
|
|
201
|
+
**The body content of the formal review** is the same kind of content you'd
|
|
202
|
+
otherwise put in a comment — substantive review notes, what's strong, what
|
|
203
|
+
needs changes, dispositions on prior feedback. The `--body-file` path is
|
|
204
|
+
the canonical way to pass that body without shell-quoting issues (per the
|
|
205
|
+
backticks-in-comments hazard noted in `mention-routing-hygiene.md`).
|
|
206
|
+
|
|
207
|
+
**This rule complements `coordination.md §Communication 2`** ("discussion
|
|
208
|
+
in issue comments, not PR comments"). The two surfaces serve different
|
|
209
|
+
purposes:
|
|
210
|
+
|
|
211
|
+
- **State-change events** (LGTM, request-changes) fire on the PR via
|
|
212
|
+
formal review submission — engages the routing-Action structural
|
|
213
|
+
defense (`route-by-pr-review-state`).
|
|
214
|
+
- **Substantive discussion ABOUT the work** persists on the issue thread
|
|
215
|
+
— visible on the Projects board, persists after the PR is merged or
|
|
216
|
+
closed.
|
|
217
|
+
|
|
218
|
+
Both surfaces are load-bearing. Don't skip the formal review thinking
|
|
219
|
+
"the issue thread is the canonical place"; don't skip the issue-thread
|
|
220
|
+
discussion thinking "the formal review covers everything."
|
|
221
|
+
|
|
222
|
+
**Verifying your review actually landed as a state-change** (per
|
|
223
|
+
`verify-before-claim.md §2`):
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# After gh pr review, confirm a state-change review exists.
|
|
227
|
+
# Filter for APPROVED or CHANGES_REQUESTED specifically — `[-1]` alone
|
|
228
|
+
# can mistake a follow-up COMMENTED review for the missing state-change.
|
|
229
|
+
gh pr view <PR-number> --repo <owner>/<repo> --json reviews \
|
|
230
|
+
--jq '[.reviews[] | select(.state == "APPROVED" or .state == "CHANGES_REQUESTED")]
|
|
231
|
+
| last // "no state-change review"'
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
If the most recent state-change review is missing (output: `"no state-change
|
|
235
|
+
review"`) OR the most recent review overall has `state == "COMMENTED"` and
|
|
236
|
+
no prior state-change exists, the review was submitted as a comment-style
|
|
237
|
+
review and won't fire the `pull_request_review.submitted` event with an
|
|
238
|
+
actionable state — the routing won't engage. Re-submit with `--approve` or
|
|
239
|
+
`--request-changes`.
|
|
240
|
+
|
|
241
|
+
**When `--comment` (no state change) IS appropriate:**
|
|
242
|
+
|
|
243
|
+
- **Mid-review clarifying questions** — partial-review feedback before completing the read-through, asking the implementer to disambiguate before you decide
|
|
244
|
+
- **Partial-review notes** — observations on parts of the diff while the rest is in flight (e.g., "skimmed the `src/server.ts` changes; will read tests next pass")
|
|
245
|
+
- **Out-of-band observations** — comments on a PR that's not blocking your LGTM/changes decision (style nits, future-work suggestions, links to adjacent context)
|
|
246
|
+
- **Review-pickup acknowledgment** — comment like *"picking this up; will review tonight"* or *"queued behind X; ETA Y"* so the PR author knows when to expect feedback. Coordination-discipline (saves the implementer from polling) but isn't a state-change.
|
|
247
|
+
|
|
248
|
+
These don't fire structural routing; agents on both sides should treat them as informational, not as merge-gating signals.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
157
252
|
## Merge-by-implementer
|
|
158
253
|
|
|
159
254
|
**The implementer who wrote the PR merges it, not the reviewer.**
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# Silent-Fallback Hazards (canonical, shared)
|
|
2
|
+
|
|
3
|
+
**This file is the single source of truth for recognizing the silent-fallback hazard class — failure modes where tool/API operations succeed at the API boundary but produce semantically wrong outcomes that are invisible until something downstream breaks.** It is copied into each agent workspace's `.claude/rules/` by `macf init` and refreshed by `macf update` / `macf rules refresh`. Do not edit workspace copies directly — edit the canonical file at `groundnuty/macf:packages/macf/plugin/rules/silent-fallback-hazards.md` and re-run the distribution.
|
|
4
|
+
|
|
5
|
+
> **Workspaces without full `macf init`** (e.g. `groundnuty/macf` itself, or any Claude Code workspace operated by a bot that isn't a MACF-registered agent) can still get this canonical rule via `macf rules refresh --dir <workspace>`. Same copy, no App credentials or registry required.
|
|
6
|
+
|
|
7
|
+
This rule names the CLASS so agents recognize the shape on first encounter rather than re-discovering each instance from scratch. Eight specific instances are documented below as worked examples spanning different architectural layers (identity, parsing, TUI binding, observability routing, config substitution, multi-agent coordination protocol, metric-instrumentation lifecycle, observability-endpoint routing). Six of eight have structural defenses applied or in flight — the pattern of defense generalizes alongside the pattern of hazard.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## The hazard shape
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
API call → exit 0 / HTTP 200 / no error
|
|
15
|
+
→ semantic outcome: WRONG identity / scope / target
|
|
16
|
+
→ downstream consumer assumes API success implies semantic success
|
|
17
|
+
→ failure invisible until something breaks elsewhere
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The trap is that defensive programming targets exit codes, but exit-code success is satisfied by the silent-fallback path. Defenses must guard at the **result-invariant level** (what was actually written / posted / received), not at the **exit-code level**.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Eight known instances
|
|
25
|
+
|
|
26
|
+
### Instance 1 — gh-token attribution traps
|
|
27
|
+
|
|
28
|
+
**Surface:** `gh` operations + bot installation tokens
|
|
29
|
+
**Failure shape:** broken/missing `GH_TOKEN` → silent fallback to stored `gh auth login` user → ops succeed, content correct, but `actor` on the resource is the human-operator account, not the bot
|
|
30
|
+
**Recurrence:** 5+ confirmed instances across multiple agents
|
|
31
|
+
**Canonical defense:** `gh-token-attribution-traps.md` (sister canonical rule) — 6 specific failure modes + result-invariant defenses (`[[ "$GH_TOKEN" == ghs_* ]]` prefix check, `macf-whoami.sh` spot-check, PreToolUse hook intercepts `gh` and `git push` invocations)
|
|
32
|
+
|
|
33
|
+
### Instance 2 — GitHub auto-close negation-blindness
|
|
34
|
+
|
|
35
|
+
**Surface:** PR / issue body markdown parsing
|
|
36
|
+
**Failure shape:** `Closes #N` / `Fixes #N` / `Resolves #N` (and lowercase / past-tense variants — 9 forms total) trigger GitHub's auto-close on merge **regardless of surrounding context** — including inside negations ("will NOT close #N"), quotes, hypothetical examples, or AC checklists. Revert commits inherit the keyword via the default `Revert "..."` wrapping and fire auto-close a second time on the revert merge.
|
|
37
|
+
**Recurrence:** Multiple confirmed incidents; sub-failure-mode (revert-message-keyword-inheritance) confirmed 2026-04-29.
|
|
38
|
+
**Canonical defense:** `pr-discipline.md` + `coordination.md §Issue Lifecycle 1` — use `Refs #N` exclusively when issue was filed by someone else; never use any of the 9 auto-close keywords with `#N` regardless of intended context. When reverting, override the default revert message to strip the inherited keyword.
|
|
39
|
+
|
|
40
|
+
### Instance 3 — Remote Control IPC blocking tmux send-keys
|
|
41
|
+
|
|
42
|
+
**Surface:** Claude Code TUI sessions with "Remote Control active" status
|
|
43
|
+
**Failure shape:** `tmux send-keys` exits 0 + keystrokes are written to pane stdin, but Claude Code's input handler is bound to a different IPC channel (RC's SDK socket); routing-via-tmux silently bypasses the actual input path → recipient never sees the routed prompt.
|
|
44
|
+
**Recurrence:** Cross-agent triangulated; 2+ confirmed firings on real routes hours apart, same shape.
|
|
45
|
+
**Defense status:** Two-tier per fleet class:
|
|
46
|
+
- **Consumer fleet** (CV agents, tester agents, future macf-init'd consumers): structurally retired via Stage 3 channel-server primitive (HTTP POST bypasses tmux layer entirely). Operational as of DR-020 / macf-actions v3+.
|
|
47
|
+
- **Substrate fleet** (workspaces operated as the design surface, not registered MACF consumers): permanent operational reality — substrate workspaces don't run `macf init`. Defensive posture: rule-discipline + Pattern C fragility detector (`tmux display -p '#{session_activity}'` doesn't advance under RC-bound input).
|
|
48
|
+
|
|
49
|
+
The structural retirement applies to consumer fleet only; substrate fleet expects Instance 3 firings to recur on routes indefinitely; rule-discipline catches the failure at observation time, not pre-emptively.
|
|
50
|
+
|
|
51
|
+
### Instance 4 — Loki / ClickHouse-logs pipeline divergence (label-vs-structured-metadata)
|
|
52
|
+
|
|
53
|
+
**Surface:** OTLP logs pipeline routing through central Collector → Loki + ClickHouse-logs
|
|
54
|
+
**Failure shape:** Loki only indexes a small set of labels (`service_name`, `service_namespace`, `k8s_*`); other OTLP resource attrs land in structured metadata, NOT as indexed labels. Loki query selector `{gen_ai_agent_name=...}` returns 0 streams silently — same data is visible in ClickHouse via Map-key access. Snapshot scripts that query Loki by an unindexed key return zero results while the parallel ClickHouse query returns full rows. Silent split where the same pipeline produces inconsistent retrieval shape across consumers.
|
|
55
|
+
**Recurrence:** Surfaced during phase-1 verification on a multi-tester scenario.
|
|
56
|
+
**Structural defense:** observability-snapshot scripts use `service_name` indexed label for the common `gen_ai.agent.name` filter case + structured-metadata fallback (`{service_name=~".+"} | <key>="<value>"`) for other keys + manifest warnings array detecting Loki/CH divergence at >10× ratio with shape-aware diagnostic per failure mode.
|
|
57
|
+
|
|
58
|
+
### Instance 5 — Workflow secrets-misnamed (operator-renames vs workflow-expects)
|
|
59
|
+
|
|
60
|
+
**Surface:** GitHub Actions workflow consuming `secrets.X` / `vars.Y` references
|
|
61
|
+
**Failure shape:** When an expected secret is missing or renamed (e.g., workflow expects `TAILSCALE_OAUTH_CLIENT_ID` but the operator created `TS_OAUTH_CLIENT_ID`), `${{ secrets.TAILSCALE_OAUTH_CLIENT_ID }}` substitutes empty string at action invocation time. The downstream tool surfaces a misleading error (auth fail at the consumer step) rather than the actual root cause (missing secret).
|
|
62
|
+
**Recurrence:** Surfaced via 3 confirmed workflow runs of confusing errors before the precheck-step pattern was introduced.
|
|
63
|
+
**Structural defense:** Workflow precheck step (runs after `checkout`, before any tool that consumes the secrets) pulls all expected secrets + vars into env, empty-string-checks each, aggregates missing names into one `::error::` annotation per missing input + runbook reference, exits 1 on any missing. Aggregate-fail-loud over fail-on-first-miss so the operator sees ALL gaps in one workflow run.
|
|
64
|
+
|
|
65
|
+
### Instance 6 — Cross-agent notification loop (multi-agent coordination protocol layer)
|
|
66
|
+
|
|
67
|
+
**Surface:** `type: "mcp_tool"` Stop hook + `notify_peer` broadcast tool deployed end-to-end (DR-023 UC-1)
|
|
68
|
+
**Failure shape:** Each individual operation succeeds at the API boundary (HTTP 200 from `/notify`, MCP push completed, `tmux_wake_delivered` logged). But the protocol has no termination condition for "peer notification triggers fresh turn → fresh turn fires Stop hook → Stop hook notifies peer." The platform's same-agent recursion guard (`(server, tool, input)` deduplication) catches recursion inside a single agent's MCP context; cross-agent recursion bypasses dedup because each agent has its own dispatcher state. Empirical observation: 8 cycles in 50s before manual termination.
|
|
69
|
+
**Architectural origin:** design-assumption mismatch — peer notifications were intended as informational (no auto-action) but the receiver's `/notify` handler triggered tmux-wake-on-receipt, turning notifications into programmatic prompts.
|
|
70
|
+
**Structural defense:** Pattern E (type-discriminator at receiver) shipped in macf v0.2.4 — `server.ts` `onNotify` discriminates by payload type. `peer_notification` → MCP push only, tmux wake SKIPPED with explicit log entry. Other `NotifyType`s (`issue_routed`, `mention`, etc.) preserve current wake-on-receipt behavior. Verified via clean post-fix trace (single 3-span trace where the prior version had 8 alternating cross-agent spans).
|
|
71
|
+
|
|
72
|
+
### Instance 7 — OTel-counter cumulative-state assumption violated by short-lived process lifecycle
|
|
73
|
+
|
|
74
|
+
**Surface:** OTel cumulative-temporality counters in processes whose lifetime doesn't match the cumulative-counter contract (e.g., `macf-channel-server` runs as Claude Code's MCP subprocess; lifetime = Claude session lifetime; multiple sessions spawn fresh processes each starting counter at 0).
|
|
75
|
+
**Failure shape:** Counter increments emit fine via OTLP (HTTP 200 from Collector). Series identity (same labels: `macf_agent`, `macf_notify_type`, etc.) collides across short-lived process generations. Prometheus's cumulative-counter assumption sees the latest scrape value (often `1` per fresh process) rather than the true accumulated count (e.g., `5` events across a 5-iter sweep). `rate()` / `increase()` queries handle the resets correctly within scrape windows, but raw counter values become near-meaningless.
|
|
76
|
+
**Recurrence:** First observed instance, surfaced via T6 metrics runtime verification.
|
|
77
|
+
**Defense status:** Two-phase plan. **Phase 1** (immediate): document `sum(increase(metric[range])) by (labels)` as the canonical query pattern in operations runbook + add comment in `metrics.ts` explaining the per-session lifetime characteristic. **Phase 2** (in flight): configure OTel SDK delta temporality — `OTLPMetricExporter({ temporalityPreference: AggregationTemporality.DELTA })`. Each process exports its own deltas; OTel/Collector aggregates by series identity → cumulative count correct regardless of process topology. Verified robust to both "1-process-per-session-restart" and "N-parallel-processes-per-tester" topologies.
|
|
78
|
+
|
|
79
|
+
### Instance 8 — Telemetry-endpoint silent-drop on retired/wrong-port OTLP target
|
|
80
|
+
|
|
81
|
+
**Surface:** OTel exporter pointed at a retired or otherwise non-listening endpoint (e.g., a stale `:4318` after compose-stack retirement when the current cluster is on a different port).
|
|
82
|
+
**Failure shape:** `claude.sh` exports cleanly (no error). Claude Code's OTel exporter dispatches traces/metrics/logs to the configured endpoint → TCP connect refused → exporter silently retries-then-drops (no surfaced error in stderr; no log entry in operator-visible logs). Agents continue to function normally — coordination events fire, channel-server delivers notifications, GitHub artifacts get created. **The observability surface is empty** (no traces in Tempo, no metrics in Prometheus) but no failure signal at any layer.
|
|
83
|
+
**Recurrence:** First observed instance, surfaced via end-to-end smoke test (consumer agents ran for 34 minutes producing real coordination events but Tempo + Prometheus had zero traces and zero metric series for the test window).
|
|
84
|
+
**Defense status:** Five architectural surfaces (Layer 1 + Tiers 1-4) — paper-grade artifact for the methodology section.
|
|
85
|
+
- **Layer 1 (CLI release-discipline):** `macf update --help` documents always-on template-sync semantics; downstream tooling (e.g., e2e tests) pin the macf binary version with `npx -y @groundnuty/macf@<pin>` to prevent stale-CLI-binary clobbering of canonical templates.
|
|
86
|
+
- **Tier 1 (substrate testers):** env-override pattern — `OTEL_EXPORTER_OTLP_ENDPOINT=<correct-endpoint>` set before `claude.sh` runs.
|
|
87
|
+
- **Tier 2 (consumer canonical):** canonical `claude-sh.ts` produces a **two-layer override** form: template-time bake via `MACF_OTEL_ENDPOINT` + run-time override via `OTEL_EXPORTER_OTLP_ENDPOINT` + canonical default pointing to the current cluster.
|
|
88
|
+
- **Tier 3 (cluster-side compatibility port-map):** k3d serverlb persists host-port mappings for legacy ports, so any stale `claude.sh` predating the canonical-template fix routes correctly without re-bootstrap.
|
|
89
|
+
- **Tier 4 (agent-process exporter-state):** long-lived agent processes started during a connect-refused window have their bundled OTel SDK retry budget exhausted and don't auto-recover. Operator remediation: graceful relaunch (fresh OTel exporter state via fresh process). Detection: `doctor-otel.sh` queries each running claude process's `OTEL_SERVICE_NAME` from `/proc/<pid>/environ` against Tempo and reports stuck processes.
|
|
90
|
+
|
|
91
|
+
**Pattern A defense template:** result-invariant check at the observability boundary — assert "trace count > 0 in Tempo for the test window" before considering the run telemetered. Mirrors the gh-token-attribution Pattern B (pre-flight state validation) shape applied to the OTLP boundary instead. Two concrete script implementations form the complete result-invariant assertion surface for the OTLP-pipeline silent-fallback class:
|
|
92
|
+
- **Cluster-side:** `check-tempo-ingestion.sh` — compares `tempo_distributor_spans_received_total` delta to TraceQL search count over the same window; exits non-zero on ingestion-without-search-results signature. Detects Tiers 1/2/3 (config / endpoint / cluster-side) failures.
|
|
93
|
+
- **Agent-side:** `doctor-otel.sh` — for each running claude process with `OTEL_TRACES_EXPORTER=otlp` set, reads `OTEL_SERVICE_NAME` from `/proc/<pid>/environ` and queries Tempo for that service's recent traces. Reports stuck processes (Tier 4 firing condition).
|
|
94
|
+
|
|
95
|
+
Together the script-pair detects the entire OTLP-pipeline silent-fallback class regardless of which architectural surface broke. **Strongest empirical evidence yet that Pattern A is the load-bearing structural-defense template for the entire observability-pipeline-class.**
|
|
96
|
+
|
|
97
|
+
**TraceQL query-syntax note (Pattern A's adjacent gotcha):** when querying Tempo for traces by dotted resource attributes, **the dotted key must be quoted**. The unquoted form returns 0 silently (matches no traces; is NOT a parse error):
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# WRONG (returns 0 silently — looks like "no telemetry" when traces actually exist)
|
|
101
|
+
curl -G "$TEMPO/api/search" --data-urlencode 'q={resource.gen_ai.agent.name=~"cv-.*"}'
|
|
102
|
+
|
|
103
|
+
# RIGHT (matches; canonical form for dotted resource attrs)
|
|
104
|
+
curl -G "$TEMPO/api/search" --data-urlencode 'q={resource."gen_ai.agent.name"=~"cv-.*"}'
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
This is a **secondary Pattern A failure mode** — the assertion script CAN return zero-traces and look like a Tier-1/2/3/4 firing when actually it's a query-syntax issue. Defense: when investigating "Pattern A reports zero traces," cross-check with the alternative query `{resource.service.name=~"macf-agent.*"}` (uses the OTel-canonical service-name attribute which TraceQL handles natively, no dotted-key quoting needed). If that returns non-zero, the issue is query-syntax not silent-fallback.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## How to recognize the class on first encounter
|
|
112
|
+
|
|
113
|
+
When investigating a "the operation completed but the outcome is wrong" incident, suspect silent-fallback if ANY of:
|
|
114
|
+
|
|
115
|
+
1. **Exit code 0 / HTTP 200 with semantic mismatch** — operation reported success, downstream behavior shows it didn't actually work.
|
|
116
|
+
2. **Multiple paths share the same exit-code outcome** — the "good path" and the "fallback path" both produce success, but only the good path produces correct semantics.
|
|
117
|
+
3. **Detection requires invariant-checking, not error-checking** — to find the failure, you have to query the result and check it against expected shape (token prefix, actor login, recipient activity, downstream telemetry presence).
|
|
118
|
+
|
|
119
|
+
If you recognize the class on first encounter, file the new instance as a research-doc or insight in your workspace, then propose canonicalization via PR per the threshold in *"When to add a new instance to this rule"* below.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Defensive patterns
|
|
124
|
+
|
|
125
|
+
Apply the matching pattern when implementing tools that interact with these surfaces.
|
|
126
|
+
|
|
127
|
+
### Pattern A — Result-invariant assertion
|
|
128
|
+
|
|
129
|
+
After the operation, assert an invariant on the RESULT, not on the exit code:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Don't:
|
|
133
|
+
gh issue comment N --body "..." || exit 1 # exit 0 doesn't prove correct attribution
|
|
134
|
+
|
|
135
|
+
# Do:
|
|
136
|
+
gh issue comment N --body "..."
|
|
137
|
+
COMMENT_AUTHOR=$(gh issue view N --json comments --jq '.comments[-1].author.login')
|
|
138
|
+
[ "$COMMENT_AUTHOR" = "$EXPECTED_BOT" ] || { echo "FATAL: wrong author"; exit 1; }
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Pattern B — Pre-flight state validation
|
|
142
|
+
|
|
143
|
+
Before the operation, validate that the precondition for the good path holds:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# Token prefix check before gh ops
|
|
147
|
+
[[ "$GH_TOKEN" == ghs_* ]] || { echo "FATAL: bad token"; exit 1; }
|
|
148
|
+
gh ...
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Pattern C — Heartbeat / activity invariant
|
|
152
|
+
|
|
153
|
+
For routing-style operations, check that recipient state advanced post-delivery:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# tmux send-keys + check session_activity advanced (Remote Control IPC detector)
|
|
157
|
+
PRE=$(tmux display -p -t $SESSION '#{session_activity}')
|
|
158
|
+
tmux send-keys -t $SESSION "..." Enter
|
|
159
|
+
sleep 2
|
|
160
|
+
POST=$(tmux display -p -t $SESSION '#{session_activity}')
|
|
161
|
+
[ "$POST" -gt "$PRE" ] || { echo "WARNING: tmux activity didn't advance — RC-bound?"; }
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Pattern D — Precheck step at workflow / process entrypoint
|
|
165
|
+
|
|
166
|
+
For long-running workflows where a missing/misnamed configuration input renders as empty-string and causes a downstream tool to surface a misleading error: add a fail-fast precheck early in the execution that asserts the configuration shape is correct, aggregating ALL missing items into one error message rather than failing on the first miss.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# GitHub Actions workflow precheck (runs after checkout, before any tool that consumes the secrets)
|
|
170
|
+
# Aggregate-fail-loud over fail-on-first-miss — operator sees ALL gaps in one fire.
|
|
171
|
+
set -euo pipefail
|
|
172
|
+
missing=()
|
|
173
|
+
[ -z "${TAILSCALE_OAUTH_CLIENT_ID:-}" ] && missing+=("TAILSCALE_OAUTH_CLIENT_ID (secret)")
|
|
174
|
+
[ -z "${TAILSCALE_OAUTH_SECRET:-}" ] && missing+=("TAILSCALE_OAUTH_SECRET (secret)")
|
|
175
|
+
# ... etc per expected secret/var
|
|
176
|
+
if [ ${#missing[@]} -gt 0 ]; then
|
|
177
|
+
echo "::error::Missing required workflow inputs:"
|
|
178
|
+
for m in "${missing[@]}"; do echo "::error:: - $m"; done
|
|
179
|
+
echo "::error::See docs/<runbook>.md for the runbook."
|
|
180
|
+
exit 1
|
|
181
|
+
fi
|
|
182
|
+
echo "✓ All expected secrets + variables present"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Key elements:
|
|
186
|
+
- `${VAR:-}` defaulting required (without it, `set -u` fails BEFORE the precheck can collect the missing names). Note: `${VAR:-}` returns empty string when unset, AND empty string is the actual signal — GitHub Actions substitutes empty for missing secrets/vars (not "undefined"). The precheck detects "missing OR explicitly-empty" uniformly, which is correct: an operator setting a secret to empty string IS a misconfiguration worth blocking.
|
|
187
|
+
- Distinguish "(secret)" vs "(variable)" annotation — saves the operator a settings-page click
|
|
188
|
+
- Aggregate via `missing=()` array + `${#missing[@]}` length check
|
|
189
|
+
- One `::error::` annotation per missing item (GitHub UI renders red error annotations)
|
|
190
|
+
- Runbook cross-reference embedded in the error message
|
|
191
|
+
|
|
192
|
+
Generalizes beyond GitHub Actions: any process that consumes configuration from external sources benefits from a precheck-at-entrypoint pattern. The hazard is that empty-config typically causes a misleading downstream error rather than failing at the configuration boundary; the defense is asserting at the boundary itself.
|
|
193
|
+
|
|
194
|
+
### Pattern E — Type-discriminator at the receiver
|
|
195
|
+
|
|
196
|
+
For multi-agent protocols where notifications can drive recipient behavior: discriminate by message type at the receiver and restrict action-triggering paths to types that intentionally drive action. Informational types (peer notifications, status updates, FYI) flow through MCP push or equivalent observability surfaces but do NOT auto-trigger fresh turns / Stop hooks / response side-effects.
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
// Receiver's notification handler
|
|
200
|
+
async function onNotify(payload: NotifyPayload, ...) {
|
|
201
|
+
// Always: deposit into observable state (MCP push, log, metrics)
|
|
202
|
+
await pushToMcpChannel(payload);
|
|
203
|
+
|
|
204
|
+
// Conditional: discriminate by type for action-triggering side effects
|
|
205
|
+
if (payload.type === 'peer_notification') {
|
|
206
|
+
// Observational only — no fresh turn fires; recipient's LLM SEES the
|
|
207
|
+
// notification via MCP channel state but doesn't auto-respond.
|
|
208
|
+
// Cross-agent loop class structurally retired.
|
|
209
|
+
logger.info('action_path_skipped', {
|
|
210
|
+
reason: 'type_discriminator',
|
|
211
|
+
type: payload.type,
|
|
212
|
+
});
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Action-triggering types preserve current behavior
|
|
217
|
+
if (config.tmuxWakeAvailable) {
|
|
218
|
+
await wakeViaTmux(formatNotifyContent(payload));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Key elements:
|
|
224
|
+
- **Always** deposit into observable state (preserves visibility / paper-trail)
|
|
225
|
+
- **Conditional** action-triggering (preserves termination by restricting which messages drive emergent behavior)
|
|
226
|
+
- **Explicit log** when the action path is skipped (surfaces the discrimination decision in operational logs; debuggable)
|
|
227
|
+
|
|
228
|
+
Pattern E specifically addresses the **multi-agent coordination protocol** layer where Patterns A-D don't apply — the issue isn't single-step semantic mismatch (Patterns A/B/C catch those) or config-substitution failure (Pattern D), but emergent multi-step behavior driven by misaligned action-triggering semantics. Pattern E restores the design assumption ("informational notifications don't drive turn-taking") at the implementation layer.
|
|
229
|
+
|
|
230
|
+
Generalizes to any multi-agent protocol with mixed informational + actionable notifications: the discriminator IS the contract, encoded at the receiver where it can't drift away from the implementation.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Why this class matters at the architectural level
|
|
235
|
+
|
|
236
|
+
Silent-fallback hazards are **architectural**, not implementation bugs. They emerge from:
|
|
237
|
+
|
|
238
|
+
- Layered abstractions where a lower layer's "success" doesn't guarantee the upper layer's semantic correctness (tool API vs intent)
|
|
239
|
+
- Default-fallback paths designed for resilience that produce wrong-but-successful outcomes when the primary path fails
|
|
240
|
+
- Detection-via-invariant rather than detection-via-error-code
|
|
241
|
+
|
|
242
|
+
For coordination-system safety analysis: this is a class of hazards multi-agent systems must explicitly defend against. Each new instance teaches the same lesson; the class-name is what makes the lesson transferable across agents.
|
|
243
|
+
|
|
244
|
+
### Defense-pattern emergence (6-of-8 known instances have structural defense applied or shipped)
|
|
245
|
+
|
|
246
|
+
| Instance | Surface | Structural defense | Pattern |
|
|
247
|
+
|---|---|---|---|
|
|
248
|
+
| 1 — gh-token attribution traps | `gh` ops + bot tokens | PreToolUse hook + helper-with-fail-loud-prefix-check | Pattern B |
|
|
249
|
+
| 2 — GitHub auto-close negation-blindness | PR/issue body markdown | Pattern B candidate; structural defense via PreToolUse hook on body content per #275 precedent — not yet shipped | Pattern B (latent) |
|
|
250
|
+
| 3 — Remote Control IPC blocking tmux send-keys | Claude Code TUI input | Two-tier: consumer fleet structurally retired via channel-server primitive (DR-020 mTLS HTTPS POST); substrate fleet permanent operational reality — defense = rule-discipline + Pattern C fragility detector | Pattern C deployable as fragility detector |
|
|
251
|
+
| 4 — Loki/CH-logs pipeline divergence | OTLP logs routing | manifest warnings + shape-aware diagnostic | Pattern A |
|
|
252
|
+
| 5 — Workflow secrets-misnamed | GitHub Actions workflow inputs | Workflow precheck step | Pattern D |
|
|
253
|
+
| 6 — Cross-agent notification loop | Multi-agent coordination protocol | macf v0.2.4: type-discriminator in receiver's `/notify` handler — `peer_notification` skips tmux wake (observational-only); other `NotifyType`s preserve wake-on-receipt | Pattern E |
|
|
254
|
+
| 7 — OTel-counter cumulative-state vs short-lived-process lifecycle | Metric-instrumentation lifecycle | Two-phase: doc workaround `sum(increase(...))` + OTel SDK delta temporality | Pattern A |
|
|
255
|
+
| 8 — OTLP endpoint silent-drop | Observability-endpoint routing | Five-surface defense: CLI release-discipline + substrate testers env-override + canonical template `:14318` default + cluster-side compat port-map + agent-process `doctor-otel.sh` Pattern A | Pattern A (composite — first multi-architectural-layer case in this rule; instances 1-7 have single-pattern defenses) |
|
|
256
|
+
|
|
257
|
+
Six of eight instances have structural defense applied or shipped. Defense patterns (A, B, C, D, E) generalize across instances — they're reusable defense templates, not case-specific fixes. **Pattern A (result-invariant assertion at the boundary) bears the most weight** — it's the structural defense for instances 4, 7, AND 8 (3 of 8), each at a different architectural boundary (logs pipeline, metric counter, observability endpoint). Instance 8's five-surface defense topology (consumer canonical + cluster-side compat port-map + concrete Pattern A impl) demonstrates that structural defense at the observability-pipeline-class can compose across architectural layers — the canonical-distribution layer + the cluster-infrastructure layer + the assertion-script layer all reinforce each other rather than substituting for each other.
|
|
258
|
+
|
|
259
|
+
The breadth of layers spanned by 5 different defense patterns (identity, parsing, TUI binding, observability routing, config substitution, multi-agent coordination protocol, metric-instrumentation lifecycle, observability-endpoint routing) is independent evidence that the hazard CLASS is real. If silent-fallback was a single-instance accident, no defense pattern would emerge. **Pattern A's recurrence across 3 different observability boundaries (logs / metrics / endpoint) is the strongest signal that result-invariant assertion is the load-bearing structural-defense template for the entire observability-pipeline-class** of silent fallback.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## When to add a new instance to this rule
|
|
264
|
+
|
|
265
|
+
Add when ALL of the following hold:
|
|
266
|
+
|
|
267
|
+
- A new failure mode of the same shape is observed (success at API boundary, semantic failure invisible)
|
|
268
|
+
- The instance has been verified (not just suspected) — minimum 1 incident with a concrete trace
|
|
269
|
+
- The defense pattern is identified (otherwise the instance is a TODO, not a documented hazard)
|
|
270
|
+
|
|
271
|
+
The class-name is what makes the lesson transferable, not multi-agent witness. A single-agent-confirmed instance with a concrete trace + identified defense pattern is sufficient for canonicalization (instances 4, 5, 7, 8 are all single-agent-confirmed). Cross-agent triangulation strengthens the framing but isn't a precondition.
|
|
272
|
+
|
|
273
|
+
Add as a new numbered section under "Eight known instances" (will become "Nine known instances" etc.) with the same fields: Surface / Failure shape / Recurrence / Defense status.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## When to read vs modify this rule
|
|
278
|
+
|
|
279
|
+
- **Read:** every session start. This rule is broadly applicable across coordination, observability, and tool-integration work.
|
|
280
|
+
- **Modify:** never directly in workspace copies. Edit the canonical file at `groundnuty/macf:packages/macf/plugin/rules/silent-fallback-hazards.md` and re-run `macf update`.
|
|
281
|
+
- **Disagree with a rule?** Open an issue on `groundnuty/macf` proposing the change, with rationale + the incident that showed the rule was wrong. Peer review applies.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Cross-references
|
|
286
|
+
|
|
287
|
+
- `gh-token-attribution-traps.md` (canonical) — Instance 1 detail
|
|
288
|
+
- `pr-discipline.md` + `coordination.md §Issue Lifecycle 1` (canonical) — Instance 2 detail
|
|
289
|
+
- DR-020 (Stage 3 mTLS routing) — Instance 3 consumer-fleet structural retirement
|
|
290
|
+
- DR-022 / DR-023 (channel-server + MCP-tool architecture) — Instance 6 Pattern E shipping vehicle
|
|
@@ -85,9 +85,25 @@ fi
|
|
|
85
85
|
# inside prose, not at line-start. Operator discipline catches the residual.
|
|
86
86
|
# awk regex: `[[]` and `[]]` express literal `[` and `]` in a char class
|
|
87
87
|
# context (awk's `\[` escape would either warn-and-strip or be ambiguous
|
|
88
|
-
# across awk variants).
|
|
89
|
-
#
|
|
90
|
-
|
|
88
|
+
# across awk variants).
|
|
89
|
+
#
|
|
90
|
+
# Pattern scope (broadened per macf#276): matches ANY `@<handle>[bot]`
|
|
91
|
+
# rather than only `@macf-*-agent[bot]`. First char must be a letter
|
|
92
|
+
# (excludes leading digit/underscore/hyphen forms which aren't valid
|
|
93
|
+
# GitHub handles anyway); body accepts alphanumeric / underscore /
|
|
94
|
+
# hyphen so digit-suffixed and multi-segment handles match.
|
|
95
|
+
#
|
|
96
|
+
# Covers: macf-* fleet (`macf-code-agent`, `macf-science-agent`,
|
|
97
|
+
# `macf-tester-N-agent`, `macf-devops-agent`); future CV fleet
|
|
98
|
+
# (`cv-architect`, `academic-resume-author`, similar shapes); future
|
|
99
|
+
# MACF-consumer fleets that may not follow the `macf-*-agent` naming
|
|
100
|
+
# convention; AND third-party bots (`dependabot`, `github-actions`).
|
|
101
|
+
# Third-party bots don't fire MACF routing (not in agent registry),
|
|
102
|
+
# but blocking their describing-context use is consistent style — and
|
|
103
|
+
# operators can use `MACF_SKIP_MENTION_CHECK=1` for the rare legitimate
|
|
104
|
+
# describing reference. The cost of generalization is small; the
|
|
105
|
+
# benefit (fleet-agnostic protection) is durable.
|
|
106
|
+
HANDLE_PATTERN='@[a-zA-Z][a-zA-Z0-9_-]*[[]bot[]]'
|
|
91
107
|
|
|
92
108
|
OFFENDING="$(awk -v pat="$HANDLE_PATTERN" '
|
|
93
109
|
{
|