PASS A1 example refuses as shipped :: mosaic-stack.json roles.pm.tracker.botId must be a positive integer (got 0)
PASS A2 bot ids fixed, dates still placeholders: refuses :: mosaic-stack.json roles.pm.credentials.gitea.rotateBy must be a date YYYY-MM-DD (got "YYYY-MM-DD")
PASS A3 dates fixed, bot ids 0: refuses :: mosaic-stack.json roles.pm.tracker.botId must be a positive integer (got 0)
PASS A4 both fixed: document validates (shape only; token files are a CLI check)
PASS B1 replace: project roles.<i> beats project beats business :: 20 from project:stack:roles.coder
PASS B2 limits.tools intersects business ∩ project ∩ agent ∩ ceiling :: ["read","write","bash"]
PASS B3 limits.network open can't widen role api-only :: api-only
PASS B4 no project: business value :: 60
PASS B5 default kept when unset
PASS B6 unknown key at business refuses :: ~/filbert-scratch/r36b/probe/work/b-r1Zh8W/config/businesses/acme.json vars: unknown variable "tracker.pollseconds"
PASS B7 agent-only key (harness) at business refuses :: ~/filbert-scratch/r36b/probe/work/b-iKw1uQ/config/businesses/acme.json vars: variable harness can't be set at the business layer (allowed: agent)
PASS B8 business-only key at agent refuses :: ~/filbert-scratch/r36b/probe/work/b-HcYwsQ/config/businesses/acme.json roles.coder.vars: variable tracker.baseUrl can't be set at the agent layer (allowed: business)
PASS B9 system key at business refuses :: ~/filbert-scratch/r36b/probe/work/b-juFiiI/config/businesses/acme.json vars: variable dataRoot can't be set at the business layer (allowed: system)
PASS B10 __proto__ key refuses :: ~/filbert-scratch/r36b/probe/work/b-DKVQBq/config/businesses/acme.json vars: unknown variable "__proto__"
PASS B11 limits.network outside vocabulary refuses :: variable limits.network must be one of: none, api-only, open (got "lan")
PASS B12 limits.authority unknown action refuses :: variable limits.authority entry names an unknown action: "task.delete"
PASS B13 project file: agent key (model) at project vars refuses :: ~/filbert-scratch/r36b/probe/work/b-eL0D1t/project/.mosaic/project.json vars: variable model can't be set at the project layer (allowed: agent)
PASS B14 project roles.<i>: agent key refuses (project layer) :: ~/filbert-scratch/r36b/probe/work/b-Fn7lVd/project/.mosaic/project.json roles.coder.vars: variable harness can't be set at the project layer (allowed: agent)
PASS B15 project roles names undeclared instance refuses :: project stack sets vars for role instance ghost, which business acme doesn't declare
PASS B16 project roles.constructor refuses :: project stack sets vars for role instance constructor, which business acme doesn't declare
PASS B17 instance constructor refuses :: business acme declares no role instance "constructor"
PASS B17 instance toString refuses :: business acme declares no role instance "toString"
PASS B17 instance __proto__ refuses :: business acme declares no role instance "__proto__"
PASS C1 pm within = definition ∩ business ∩ agent :: {"withinRole":["task.create","role.launch"],"crossRole":["task.scope.change"]}
PASS C2 pm cross keeps scope.change, drops priority.change
PASS C3 classify: dropped action is gated
PASS C4 classify: gated-only action is gated
PASS C5 limits can't grant an action outside the definition (review.verdict for pm)
PASS C6 reviewer keeps only listed actions :: ["review.verdict","message.send"]
PASS C7 classify unknown action refuses :: unknown action: "task.delete"
PASS C8 pm with launch.by=pm: role.launch within
PASS C9 no launch block: pm role.launch gated
PASS C10 launch.by=cto (no role.launch in cto definition) refuses, exit 2 :: ~/filbert-scratch/r36b/probe/work/b-I8HG87/config/businesses/acme.json launch.by names cto, whose role cto doesn't hold role.launch within-role
PASS C11 agent limits.authority drops role.launch for launch.by: launch null, gated :: launch=null classify=gated
PASS C12 business limits.authority drops role.launch: pm launch null, gated
PASS C13 a definition with role.launch only cross-role can't be launch.by :: ~/filbert-scratch/r36b/probe/work/b-dit59X/config/businesses/acme.json launch.by names cto, whose role cto doesn't hold role.launch within-role
PASS C14 a definition with role.launch within-role can be launch.by :: cto=within pm=gated
PASS C15 two pm instances: only launch.by keeps role.launch
PASS C16 sweep: launch !== null exactly when classify(role.launch) is within :: checked=29 configs=7 bad=[]
PASS D1 checkCredentialRef on 9 token files: 0 opens :: refs=9 opens=[] problems=0
PASS D2 token reached through a symlinked parent inside a forbidden root refuses :: ["gitea file ~/filbert-scratch/r36b/probe/work/b-WKi0wx/outside/t.token: inside ~/filbert-scratch/r36b/probe/work/b-WKi0wx/fakerepo; token files live outside the repository and dataRoot"]
PASS D3 mode 640 refuses :: ["vikunja file ~/filbert-scratch/r36b/probe/work/b-WKi0wx/fakerepo/sec/t.token: mode 640 gives group or other access; use 600"]
PASS D4 expired vikunja refuses
PASS D5 gitea rotateBy past only warns; env unset only warns :: ["gitea env GITEA_TOKEN: not set in this environment; the launcher must provide it","gitea env GITEA_TOKEN: rotation was due on 2000-01-01"]
PASS D0 hook sees the business file read :: 10
PASS E1 business load: one open of the path, reads by descriptor :: ["<root>/config/businesses/acme.json","fd:21","<repo>/roles/pm.json","fd:21","<repo>/roles/cto.json","fd:21","<repo>/roles/coder.json","fd:21","<repo>/roles/reviewer.json","fd:21"]
PASS E2 business file is a symlink: exit 4 :: business file must be a regular, non-symbolic-link file: ~/filbert-scratch/r36b/probe/work/b-l791eV/config/businesses/acme.json
PASS E3 business file mode 000 (EACCES at open): refuses :: exit=4 business file must be a regular, non-symbolic-link file: ~/filbert-scratch/r36b/probe/work/b-NERwev/config/businesses/acme.json
PASS E4 businesses/ itself a symlink (parent, not the file): loads, as in round 1
PASS E5 role definition is a symlink: exit 4 :: role file must be a regular, non-symbolic-link file: ~/filbert-scratch/r36b/probe/work/b-Yw9PhA/roles/pm.json
PASS E6 project file is a symlink: exit 4 :: project file must be a regular, non-symbolic-link file: ~/filbert-scratch/r36b/probe/work/b-oDByB5/project/.mosaic/project.json
PASS E7 other-readable but not writable (604) loads
PASS E8 other-writable (602) refuses, exit 2 :: business file must not be writable by group or other (mode 602): ~/filbert-scratch/r36b/probe/work/b-cZe15L/config/businesses/acme.json
