171 lines
9.3 KiB
Markdown
171 lines
9.3 KiB
Markdown
# Row 122 design — agent settings and organization writes (#1616)
|
|
|
|
Design first, for Sage to post before implementation. Rocko, GPT-6.1-Sol.
|
|
Brief: docs/plans/2026-10-14_prd-1.2-build.md, pinned 240d25518,
|
|
section Agent limits as settings, with the organization-file write path.
|
|
Requirements: REQ-ROLE-3, REQ-LIMIT-1, REQ-LAUNCH-1, REQ-WEB-1.
|
|
No live organization/configuration/secrets were read. No product code or
|
|
migration has run. Decision144 leaves Jason's file to Jason.
|
|
|
|
## Proposed schema
|
|
|
|
Keep businessVersion1, launch.by and launch.instances. Replace launch.max
|
|
with launch.models and launch.limits. Example defaults, with provider/model
|
|
values explicitly chosen by the operator rather than inferred:
|
|
|
|
```json
|
|
{
|
|
"launch": {
|
|
"by": "pm",
|
|
"instances": ["coder", "reviewer", "cto"],
|
|
"models": {
|
|
"opus": {"provider": "anthropic", "model": "claude-opus-5-5"},
|
|
"sonnet": {"provider": "anthropic", "model": "claude-sonnet-5-5"}
|
|
},
|
|
"limits": {
|
|
"models": {
|
|
"anthropic": {"claude-opus-5-5": 4, "claude-sonnet-5-5": 4}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Model-table keys are stable configuration ids; each entry requires a provider
|
|
and an exact external model string. Each role's vars.model selects a table
|
|
key, for example pm -> opus, coder/reviewer -> sonnet. Harness selection
|
|
stays where it is today; row65 later converts harnesses through the loader.
|
|
The table's provider/model override the provider/model used to launch that
|
|
instance, and are recorded in its manifest, running-session registry and
|
|
launch log. No provider allowlist or provider module is introduced here.
|
|
Unknown references fail closed; matching a family substring disappears.
|
|
|
|
limits has only these optional keys:
|
|
|
|
- total: count across all running sessions in the organization.
|
|
- providers: object mapping exact provider names to counts.
|
|
- models: object mapping provider names to objects mapping exact external
|
|
model names to counts.
|
|
|
|
An absent key means unlimited. Empty objects are valid, and an empty limits
|
|
object means no concurrency limits. null, fractions, negatives and strings
|
|
refuse; accepted counts are nonnegative safe integers, with no configured
|
|
upper bound beyond lossless JSON integer representation. 0 stops a new
|
|
launch in that scope. Four and four are editable starter/migration values,
|
|
not a validator ceiling or a value injected when a key is absent. Removing
|
|
an entry explicitly unsets that limit. Aliases for the same provider/model
|
|
share the same counter, so a second table key cannot bypass a model limit.
|
|
Provider/model limits need not have a currently selected role: they can be
|
|
configured before changing an instance's model.
|
|
|
|
## Migration and Jason's exact change
|
|
|
|
`mosaic limits migrate --business ID --models FILE` prints the converted
|
|
whole document by default. Only explicit --write by a verified human uses
|
|
the write path. FILE supplies the model table and the exact mapping from
|
|
old external model strings to table keys. No provider inference, substring
|
|
routing or automatic write on read/start. Unknown/ambiguous mappings refuse
|
|
with the unchanged input. Repeating on an already migrated valid document
|
|
is idempotent.
|
|
|
|
For old launch.max = {opus:4,sonnet:4}, map each family to one explicitly
|
|
supplied table key and translate those values to the two corresponding
|
|
provider/model limits. Preserve launch.by, launch.instances, harnesses,
|
|
credentials, role definitions and unrelated document values. Convert each
|
|
role's effective old model selection to its mapped table key; use explicit
|
|
instance overrides where a selection was inherited. Do not alter a shared
|
|
system execution setting. Require mappings for launch.by and every
|
|
launchable instance. Do not invent a total8 or provider8 limit: the old
|
|
shape had neither. Legacy family limits that require multiple exact models
|
|
per family cannot be faithfully split; refuse and require an operator's
|
|
explicit new limits rather than silently widening capacity.
|
|
|
|
The example above illustrates the exact shape, not a claim about Jason's
|
|
provider, ids or instances. The fixture migration produces the replacement
|
|
launch block plus per-instance vars.model changes. The build packet will
|
|
include that exact JSON patch and command for Jason, with provider/model
|
|
mapping explicitly supplied and reviewed through Sage/Mos. It will not
|
|
assert that anthropic is Jason's provider or execute a live migration. The
|
|
new validator refuses an unmigrated launch.max with a migration instruction.
|
|
Re-pin therefore follows Jason's applied migration and Mos's go; the old
|
|
host must not launch between schema migration and the coordinated re-pin.
|
|
|
|
## One write path, fail closed
|
|
|
|
A trusted host module owns writes to the resolved businessFilePath for a
|
|
validated organization id. It accepts an authenticated actor supplied by
|
|
the human channel, never an actor string from a browser/CLI payload.
|
|
Limits endpoints may change only launch limits/model-table entries and
|
|
role model selection. The shared internal module can validate a whole-file
|
|
replacement for row123's later chief-of-staff verb; this row grants no
|
|
chief-of-staff writer and exposes no unrestricted browser file write.
|
|
|
|
Serialize writes per organization with a filesystem lock shared by writers;
|
|
compare a submitted revision/hash against the current bytes to refuse lost
|
|
updates. Read the current regular file without following a symlink, validate
|
|
the entire proposed document using the existing role-aware validator, then
|
|
prepare same-directory temporary bytes. Preserve an immutable previous
|
|
version and an append-only actor/change record with field paths, old/new
|
|
values and before/after hashes. Fsync evidence and candidate before atomic
|
|
rename, then fsync the directory. Journal prepared/committed outcomes and
|
|
recover an interrupted transaction by hashes; an uncertain outcome refuses
|
|
new writes until reconciled. Invalid or stale proposals never replace the
|
|
old file. Success is reported only after the committed receipt. No secret
|
|
contents are logged: unrelated credential references remain references.
|
|
|
|
CLI and Settings use the same human-only read/update operation behind the
|
|
existing human proof. No direct CLI bypass. CLI stays out of transport.mjs;
|
|
Settings POST repeats the existing enabled-send, named-host, authenticated
|
|
header, exact Origin, same-origin Fetch Metadata, body-size and strict-key
|
|
checks. Both submit a revision and receive current normalized settings and
|
|
counts; no retry on unknown outcome. GET remains available through the
|
|
existing read path. Form inputs distinguish unset from0, show all three
|
|
limit kinds and every instance's table selection, and report refusals.
|
|
|
|
## Launch behavior and acceptance evidence
|
|
|
|
Within the launcher's existing serialized launch queue, re-read and validate
|
|
current limits and model selections for every attempt, including host-start
|
|
launches. A missing/invalid file refuses; never fall back to cached limits.
|
|
Check total, then provider, then exact provider/model counters, counting the
|
|
launcher itself and all still-running registry entries. A launch at the
|
|
limit refuses because it would exceed it; unset imposes no check. Lowering
|
|
a limit leaves existing sessions alive. Their recorded provider/model tuple
|
|
continues to count even after their instance is assigned a different model.
|
|
Each refusal logs the hit scope, configured value and running count; each
|
|
launch logs harness/provider/model. Existing authority/credential/sandbox
|
|
checks remain, and unrelated permission changes still follow their existing
|
|
reload/re-pin rules.
|
|
|
|
Builder tests cover whole-file validation, atomic publication, previous
|
|
bytes, actor/old/new receipts and crash/stale-write refusal; every limit
|
|
kind unset/0/at/over; live re-read and unchanged existing sessions; exact
|
|
model routing; fixture-only print/write migration; human-only CLI; form
|
|
send checks. One killed mutant per acceptance check, listed in the packet.
|
|
Targeted builder gate and mutants need Sage's slot. No product code starts
|
|
until Sage posts this design note on #1616. Landing public/ changes awaits
|
|
Mos (decision123); any live step still requires re-pin (decision109).
|
|
|
|
## Superseding migration ruling — decisions 145 and sage-0254
|
|
|
|
The earlier optional write/local helper description is superseded: migration
|
|
is print-only, has no --write and uses no organization writer or human proof.
|
|
Only broker-backed `mosaic limits` and Settings write. Jason installs the output
|
|
himself in Mos's window with the PM run idle and the re-pin in that same window.
|
|
Both exact Claude table entries use provider `anthropic`, per Mos via Sage
|
|
sage-0254. Map pm, cto and reviewer to opus; coder to sonnet. Keep exact model
|
|
limits four/four, no total or provider limit, and leave execution.provider alone.
|
|
|
|
## Round 2 rulings (Sage sage-0269; row 119 landed)
|
|
|
|
The post-119 launcher is chief, with assistant holder mos. The packet covers
|
|
both new instances and all four existing ones. For inherited models the
|
|
print-only command reads the existing system config through loadSystem and
|
|
systemVars, preserving both provider and exact model; invalid/missing config
|
|
refuses. Fully explicit input still needs no system-config read. Nothing writes
|
|
that config. Initial role entry, migration-output installation and re-pin happen
|
|
in one Mos window with the PM idle; Sage supplies the first-chief-session step.
|
|
Uncertain transaction evidence gates organization writes only. Startup, launch
|
|
and read paths validate the whole file on disk without consulting receipts;
|
|
write-time recovery still refuses uncertainty until reconciled.
|