feat(agent): fail-closed seat resolution under MOSAIC_AGENTS_DIR override (#46)
Owner decision after live verification of M18: an explicit agents-dir override that cannot resolve the named seat now refuses the launch (exit 4, names the seat and dir) instead of launching seatless and unbounded. Unsetting the override keeps the M13 plain governed TUI. MOSAIC_ROLES_DIR needs no symmetric change - the M18 gate already refuses unresolvable role contracts. Task suite 88 -> 90 (refusal + refusal-names-the-seat). TOOLS.md Agent section documents the refusal. Suites 24/90/14/17 + verify green.
This commit is contained in:
@@ -499,3 +499,26 @@ tools/ tree; suites green at every gate.
|
||||
Seat roles are ceilings, not labels: the M15 role field now resolves to a
|
||||
versioned contract that seats cannot escalate past. Suites 24/88/14/17 +
|
||||
verify green.
|
||||
|
||||
## Phase 23 follow-up: fail-closed seat resolution under override (#46)
|
||||
|
||||
- Owner live-verified M18 (2026-09-03): ceiling narrowing note with the
|
||||
correct narrowed set, missing-contract refusal message, clean researcher
|
||||
launch, validator positives and negatives, tool-free note — all as
|
||||
expected.
|
||||
- The verification surfaced a governance gap: an explicit
|
||||
MOSAIC_AGENTS_DIR override that cannot resolve the named seat still
|
||||
launched — seatless, unbounded, no role ceiling to bind.
|
||||
- Owner decision: fail closed. agent.sh now refuses (exit 4, names the
|
||||
seat and the dir) when the override is set and no seat definition
|
||||
resolves; unsetting the override keeps the M13 plain governed TUI.
|
||||
MOSAIC_ROLES_DIR needs no symmetric change — the M18 gate already
|
||||
refuses unresolvable contracts.
|
||||
- Task suite 88 → 90 (refusal + refusal-names-the-seat); TOOLS.md Agent
|
||||
section documents the refusal.
|
||||
|
||||
## Result
|
||||
|
||||
Suites 24/90/14/17 + verify green. Seat resolution is now fail closed in
|
||||
every direction: unknown seat under override, declared role without
|
||||
contract, invalid contract, empty ceiling intersection.
|
||||
|
||||
@@ -12,3 +12,4 @@ are never rewritten or removed; corrections are new entries.
|
||||
| 2026-09-03 | assistant (conductor) + ms-test collaborator (worker, glm-5.3-flash) | Conductor-loop calibration (#43): decompose → dispatch via agent-send.sh → receipt → line-by-line diff review (claims verified vs tool source) → suite-gated integration; CURRENT.md staleness corrected (M16/M17 late-logged, next action → M18) | docs/TOOLS.md tools/ section + suite-count fix; issue #43 closed; suites 24/74/14/17 + verify green |
|
||||
| 2026-09-03 | owner + assistant (conductor) + ms-test collaborator | Skill revisions adjudicated (#44): ms-communications integrated as-authored (owner preamble restructure + collaborator delivery-discipline hunks); ms-conductor collaborator redraft integrated with conductor remediation (step 3 refusal-vs-outage distinction; preserves owner's outage-dispatch intent inside fail-closed canon); TOOLS.md gains release.sh ensure row | skills/ms-communications/SKILL.md, skills/ms-conductor/SKILL.md, docs/TOOLS.md; suites 24/74/14/17 + verify green; unslop clean ×3 |
|
||||
| 2026-09-03 | assistant (conductor) | M18 seat-role progressive capability restriction (#45): roles/<role>.json contracts (strict schema, name-filename binding, network declared), mosaic-task.mjs resolve-role, agent.sh ceiling intersection with fail-closed refusals, roles/researcher.json shipped, 14 suite cases (task 74 → 88) | scripts/mosaic-task.mjs, scripts/agent.sh, scripts/test-task.sh, roles/researcher.json, docs; suites 24/88/14/17 + verify green |
|
||||
| 2026-09-03 | owner (decision + live verification) + assistant (conductor) | M18 live verification + follow-up (#46): owner confirmed narrowing/refusal/tool-free live; seatless launch under AGENTS_DIR override discovered and made fail-closed (exit 4); task suite 88 → 90 | scripts/agent.sh, scripts/test-task.sh, docs/TOOLS.md; suites 24/90/14/17 + verify green |
|
||||
|
||||
+4
-2
@@ -52,7 +52,9 @@ persistent named session, optional workspace. Exit with `/quit`.
|
||||
A seat role (`agent.json` `role`) binds to `roles/<role>.json` (M18): the
|
||||
contract's tools are a ceiling the seat definition or `--tools` may narrow,
|
||||
never escalate past. Missing/invalid contract refuses the launch; empty
|
||||
intersection = loud tool-free seat.
|
||||
intersection = loud tool-free seat. An explicit `MOSAIC_AGENTS_DIR` override
|
||||
that cannot resolve the named seat also refuses (#46) — unset the override
|
||||
for the M13 plain governed TUI.
|
||||
|
||||
## Release
|
||||
|
||||
@@ -81,7 +83,7 @@ Push is never automatic.
|
||||
|---|---|---|
|
||||
| `scripts/reset.sh` | Delete the data root | Triple-safety-checked (path, symlink, ownership marker) |
|
||||
| `scripts/test-config.sh` | Config selftests (no Docker) | 24 cases |
|
||||
| `scripts/test-task.sh` | Task selftests + live cases | 88 cases |
|
||||
| `scripts/test-task.sh` | Task selftests + live cases | 90 cases |
|
||||
| `scripts/test-release.sh` | Release selftests | 14 cases |
|
||||
| `scripts/test-conductor.sh` | Auto-apply selftests (sandboxed) | 17 cases |
|
||||
| `scripts/gitea-api.sh <METHOD> <path> [body]` | Gitea API helper | Token never on argv/stdout |
|
||||
|
||||
@@ -51,3 +51,4 @@ git history + Gitea issues.
|
||||
- 2026-09-03 — conductor-loop calibration with live collaborator (#43): dispatch via agent-send.sh → receipt → line-by-line diff review → suite-gated integration; docs/TOOLS.md gains Tools (host-side) section + corrected suite counts
|
||||
- 2026-09-03 — skill revisions adjudicated (#44): ms-communications integrated as-authored; ms-conductor redraft + conductor remediation (refusal vs outage); TOOLS.md release.sh ensure row
|
||||
- 2026-09-03 — M18 seat-role progressive capability restriction (#45; roles resolve to contracts, ceiling ∩ seat grant, fail-closed refusals, roles/researcher.json); task suite 74 → 88
|
||||
- 2026-09-03 — M18 follow-up: fail-closed seat resolution under MOSAIC_AGENTS_DIR override (#46, owner decision after live verification); task suite 88 → 90; next action M19
|
||||
|
||||
@@ -57,6 +57,14 @@ fi
|
||||
# The seat's SOUL.md overrides the contract persona; governance contracts
|
||||
# are never overridden.
|
||||
AGENTS_DIR="${MOSAIC_AGENTS_DIR:-agents}"
|
||||
# Fail closed (owner decision, #46): an explicit agents-dir override that
|
||||
# cannot resolve the named seat refuses the launch - a seatless launch has
|
||||
# no identity, no SOUL, and no role ceiling to bind. Unset the override for
|
||||
# the M13 plain governed TUI.
|
||||
if [ -n "${MOSAIC_AGENTS_DIR:-}" ] && [ ! -f "$AGENTS_DIR/$NAME/agent.json" ]; then
|
||||
echo "agent: no seat definition for '$NAME' in overridden agents dir: $AGENTS_DIR (unset MOSAIC_AGENTS_DIR for a plain governed TUI)" >&2
|
||||
exit 4
|
||||
fi
|
||||
ROLE=""
|
||||
DEFCAPS=""
|
||||
AGENT_DEF_SKILLS=""
|
||||
|
||||
@@ -299,6 +299,20 @@ EOF
|
||||
grep -q "nothing in common -> tool-free seat" "$SANDBOX/roleseat-stderr.txt" 2>/dev/null \
|
||||
&& check "tool-free outcome recorded loudly" 0 || check "tool-free outcome recorded loudly" 1
|
||||
|
||||
# fail-closed seat resolution (#46, owner decision): an explicit
|
||||
# agents-dir override that cannot resolve the named seat refuses.
|
||||
env MOSAIC_CONFIG="$SANDBOX/mock-config.json" MOSAIC_AGENTS_DIR="$SANDBOX/agents" \
|
||||
scripts/agent.sh nobody </dev/null >"$SANDBOX/nobody-stdout.txt" 2>"$SANDBOX/nobody-stderr.txt"
|
||||
RC=$?
|
||||
if [ "$RC" -eq 4 ]; then
|
||||
PASS=$((PASS+1)); echo "${C_OK}OK${C_RESET} overridden agents dir without seat definition refuses (exit 4)"
|
||||
else
|
||||
FAIL=$((FAIL+1)); echo "${C_FAIL}FAIL${C_RESET} overridden agents dir without seat definition refuses (exit $RC)" >&2
|
||||
echo "NOBODY stderr:" >&2; cat "$SANDBOX/nobody-stderr.txt" >&2
|
||||
fi
|
||||
grep -q "no seat definition for 'nobody'" "$SANDBOX/nobody-stderr.txt" 2>/dev/null \
|
||||
&& check "seat-resolution refusal names the seat" 0 || check "seat-resolution refusal names the seat" 1
|
||||
|
||||
# capability policy (M9): least-privilege intersection
|
||||
POL="$SANDBOX/data/workspaces"; mkdir -p "$POL"
|
||||
pol_run() { # missionTools(ABSENT|json) taskTools(ABSENT|json) -> stderr MOSAIC_TOOLS value
|
||||
|
||||
@@ -27,3 +27,4 @@ Agent operation cycles: launch, work, verify, persist, hand off.
|
||||
overridden.
|
||||
- If a capability you need is missing, say so. Do not improvise a capability
|
||||
you were not granted.
|
||||
- End your turn with a timestamp.
|
||||
|
||||
Reference in New Issue
Block a user