PRD 1.9: REQ-WEB-2, Console decide buttons for a human the Console signed in, and the REQ-DEC-3 amendment (mos-1202)
Jason approved the buttons in decision 00ed58e2 (vikunja:19/266) and chose O6 in Q203 (OIDC-only), relayed by Mos in mos-1202 with "Land PRD 1.9 with REQ-WEB-2 as written". The wording is sage-2067's draft. requirements.json goes to 1.9 with 69 ids; tasks suite 97/0 and bus requirements.test.mjs 3/0 on Sage's slot.
This commit is contained in:
1 parent
0de97f429d
commit
f48725cfc1
4 files changed
+48
-8
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# PRD: Mosaic Stack
|
||||
|
||||
- Status: approved, version 1.8. Jason approved draft 0.4 unchanged as
|
||||
- Status: approved, version 1.9. Jason approved draft 0.4 unchanged as
|
||||
1.0 on 2026-10-05 (lead decision 61). They approved version 1.1, the
|
||||
Organization requirements, in decision 03130d08-ddce-480d-a601-e59f64744fc3
|
||||
on 2026-10-14. They approved version 1.2, the chief of staff, the
|
||||
@@ -23,7 +23,19 @@
|
||||
guardrails by default, a manual mode for per-use raises, and grants the
|
||||
chief of staff requests and the user approves. Jason approved it in T3,
|
||||
relayed by Mos on 2026-10-21 (DECISIONS Q192), so there is no in-Stack
|
||||
prd.approve for it.
|
||||
prd.approve for it. Version 1.9 adds REQ-WEB-2 and amends REQ-DEC-3:
|
||||
the Console decide buttons Jason approved in decision 00ed58e2
|
||||
(vikunja:19/266), signed in as his Q175 ruling set, and OIDC-only as he
|
||||
chose in Q203, relayed by Mos on 2026-10-21 (mos-1202).
|
||||
- Version 1.9 source, Jason's answer to Q203 in T3, relayed by Mos on
|
||||
2026-10-21 (DECISIONS Q203, mos-1202): "Let's use O6. If a user does
|
||||
not have an OIDC provider to configure, we will need to use a bundled
|
||||
Pocket ID instances to handle this traffic." O6, as Mos put it to him:
|
||||
"keep the REQ-WEB-2 wording OIDC-only. Identity is the (issuer,
|
||||
subject) pair from the Console's own verified OIDC sign-in. Local
|
||||
accounts come from a provider, and the Console never holds passwords."
|
||||
The second sentence is not part of 1.9. It becomes its own requirement
|
||||
in a later version (vikunja:19/458).
|
||||
- Version 1.8 source, Jason's approval in T3, relayed by Mos on 2026-10-21
|
||||
(DECISIONS Q192): "PRD 1.8: I am preemptively approving it. Do not
|
||||
surface in the Mosaic Stack board. Just proceed."
|
||||
@@ -511,7 +523,8 @@ Added in version 1.8 (Q188):
|
||||
refused, and so is a raise citing a spec whose last commit isn't the
|
||||
human's.
|
||||
- **REQ-DEC-3.** A human resolution, by an authorized human, comes only from a `mosaic` CLI session
|
||||
started outside any agent run. Agents reach the decision store only
|
||||
or a Console session signed in under REQ-WEB-2, both started outside
|
||||
any agent run. Agents reach the decision store only
|
||||
through a broker. The broker stamps role and run from the launch record.
|
||||
- **REQ-DEC-4.** A gated decision that blocks work reaches an authorized human
|
||||
right away: in the CLI inbox, plus a Discord DM sent through the existing
|
||||
@@ -744,6 +757,18 @@ Added in version 1.7:
|
||||
view shows every agent limit, the usage counted against each, and the
|
||||
model each role instance runs, and lets the user change them
|
||||
(REQ-LIMIT-1 to REQ-LIMIT-3).
|
||||
- **REQ-WEB-2.** The Console resolves an open decision with one button
|
||||
per option, only for a human it signed in itself, recorded via=console.
|
||||
(Version 1.9, decision 00ed58e2, Q175 and Q203.)
|
||||
- Identity is the (iss, sub) pair the Console verified from its own
|
||||
OIDC session after `--sso` sign-in (Q175), and that pair must map to
|
||||
an authorized human. The Console takes no identity from a proxy
|
||||
header and none from a shared secret.
|
||||
- A request that carries an agent session or a seat credential is
|
||||
refused.
|
||||
- The decision event records via=console and the (iss, sub) pair.
|
||||
- Without a signed-in session, the Console resolves nothing and shows
|
||||
the `mosaic decide` line instead.
|
||||
- **REQ-WEB-3.** The Console has controls to restart the bus and to
|
||||
reload the organization file. Each control is a gated, trailed action.
|
||||
A reload applies `launch.instances` changes to running sessions without
|
||||
@@ -1155,6 +1180,20 @@ only hard waits in his inbox.
|
||||
Until row 155 lands, the assistant's runs hold thread claims that
|
||||
the end and revoke paths don't read, so neither can stop one. The
|
||||
human stops one with `mosaic stop <run>`.
|
||||
- Version 1.9:
|
||||
- The 1.8 text of REQ-DEC-3 began: "A human resolution, by an
|
||||
authorized human, comes only from a `mosaic` CLI session started
|
||||
outside any agent run."
|
||||
- The first text on vikunja:19/266 had the Console trust the
|
||||
`X-authentik-uid` header. Q175 replaced that: the Console runs its
|
||||
own OIDC sign-in and takes no identity from a proxy header. Q203 (O6)
|
||||
keeps the requirement OIDC-only, so the Console holds no passwords.
|
||||
- The requirement covers every open decision. The first build, row
|
||||
252 (#1753), covers grant requests only (Q188). It resolves through
|
||||
the human boundary row 196 (#1694) builds.
|
||||
- The live Console runs without `--sso` and without `--send`, so it
|
||||
resolves nothing until the Q175 phase 2 window turns both on and a
|
||||
re-pin carries row 252. This amendment adds the requirement only.
|
||||
|
||||
## Risks and open questions
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ test('requirements returns the committed list to a holding role session, and no
|
||||
const pm = agent('pm');
|
||||
const list = call(b, pm, 'requirements');
|
||||
assert.deepEqual(list, loadRequirements());
|
||||
assert.equal(list.requirements.length, 68);
|
||||
assert.equal(list.requirements.length, 69);
|
||||
assert.deepEqual(call(b, agent('coder'), 'requirements'), list);
|
||||
assert.throws(() => call(b, human, 'requirements'), /agent-required/);
|
||||
assert.throws(() => call(b, reader, 'requirements'), /read-only/);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"prd": "docs/prd/mosaic-stack.md",
|
||||
"version": "1.8",
|
||||
"version": "1.9",
|
||||
"requirements": [
|
||||
{ "id": "REQ-ROLE-1", "title": "Each role is a reviewed roles/<name>.json: contract, authority map, credentials" },
|
||||
{ "id": "REQ-ROLE-2", "title": "One holder per role instance, one per thread for the assistant; the chief of staff may end a run, others need a decision" },
|
||||
@@ -50,6 +50,7 @@
|
||||
{ "id": "REQ-CLI-1", "title": "mosaic is the front door: talk to the assistant in a thread, the inbox, tasks, agents and trails" },
|
||||
{ "id": "REQ-CLI-2", "title": "The assistant session mosaic talks to is launched and owned by the stack, not T3" },
|
||||
{ "id": "REQ-WEB-1", "title": "The WebUI shows the CLI's data, a chat area of projects and threads, and Settings for agent limits" },
|
||||
{ "id": "REQ-WEB-2", "title": "The Console resolves an open decision with one button per option, only for a human it signed in itself (OIDC)" },
|
||||
{ "id": "REQ-WEB-3", "title": "The Console restarts the bus and reloads the organization file, gated and trailed; reload applies launch.instances live" },
|
||||
{ "id": "REQ-LAUNCH-1", "title": "The chief of staff launches role sessions within the agent limits, logged and revocable; threads start on demand" },
|
||||
{ "id": "REQ-LIMIT-1", "title": "Agent limits have no code ceiling and are set from WebUI Settings and mosaic: total, per provider, per model" },
|
||||
|
||||
@@ -18,10 +18,10 @@ test("the list holds the PRD's requirement ids, in its order, at its version", (
|
||||
const ids = [...prd.matchAll(/^- \*\*(REQ-[A-Z]+-[0-9]+)\.\*\*/gm)].map((m) => m[1]);
|
||||
// Any other mention of a bold id would be a bullet this pattern missed.
|
||||
assert.equal(ids.length, [...prd.matchAll(/\*\*REQ-/g)].length);
|
||||
assert.equal(ids.length, 68);
|
||||
assert.equal(ids.length, 69);
|
||||
assert.deepEqual(list.requirements.map((r) => r.id), ids);
|
||||
assert.match(prd, new RegExp(`^- Status: approved, version ${list.version.replace('.', '\\.')}\\.`, 'm'));
|
||||
assert.deepEqual([list.prd, list.version], ['docs/prd/mosaic-stack.md', '1.8']);
|
||||
assert.deepEqual([list.prd, list.version], ['docs/prd/mosaic-stack.md', '1.9']);
|
||||
});
|
||||
|
||||
test('the committed list loads frozen', () => {
|
||||
@@ -74,7 +74,7 @@ test('the schema refuses any other shape', () => {
|
||||
const twice = raw();
|
||||
twice.requirements.push(structuredClone(twice.requirements[0]));
|
||||
writeFileSync(join(dir, 'twice.json'), JSON.stringify(twice));
|
||||
assert.throws(() => loadRequirements(join(dir, 'twice.json')), listError('requirements[68].id: REQ-ROLE-1 twice'));
|
||||
assert.throws(() => loadRequirements(join(dir, 'twice.json')), listError('requirements[69].id: REQ-ROLE-1 twice'));
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user