PRD 1.12: ids for the Q176 items from the approved designs (REQ-USER-3, REQ-USER-4, REQ-LIFE-1, REQ-KILL-1, REQ-LIB-1 to 7), the Risks line and the REQ-DEC-3 title (mos-1229, Vikunja 462)
This commit is contained in:
1 parent
73222011f2
commit
3576afffb3
4 files changed
+209
-12
No files matched your search
+192
-6
@@ -1,6 +1,6 @@
|
||||
# PRD: Mosaic Stack
|
||||
|
||||
- Status: approved, version 1.11. Jason approved draft 0.4 unchanged as
|
||||
- Status: approved, version 1.12. 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
|
||||
@@ -33,7 +33,16 @@
|
||||
goal. It updates the lines that the 10-27 rulings settle and adds
|
||||
REQ-INST-3. Mos's reading of Q211 sets the path: one seat drafts, a
|
||||
second seat reviews, and Sage lands it. So there is no in-Stack
|
||||
prd.approve for it.
|
||||
prd.approve for it. Version 1.12 adds requirement ids for the Q176
|
||||
items the PRD lacked, drafted from the approved designs, and updates
|
||||
two stale lines. It takes the same path as 1.11 (mos-1229,
|
||||
vikunja:19/462).
|
||||
- Version 1.12 source, Mos's answers to the 1.11 questions in mos-1229 on
|
||||
2026-10-21: "M2: agreed. 1.11 adds no ids for the Given list or Case 2
|
||||
items. You draft 1.12 from the approved #414 and #416 designs as soon as
|
||||
Della approves 1.11. Vikunja 462." and "M4: fold both items into 1.12,
|
||||
Vikunja 462." The two M4 items are the slice 1 Risks line and the
|
||||
REQ-DEC-3 title in `packages/tasks/requirements.json`.
|
||||
- Version 1.11 source, Jason's answer to Q23 in T3, relayed by Mos on
|
||||
2026-10-21 (DECISIONS Q211, mos-1227): "It appears that I have expanded
|
||||
the requirements for v1. My recent goal for the 10-27 release is the
|
||||
@@ -1012,6 +1021,130 @@ Added in version 1.1 (decision 03130d08).
|
||||
post-v1. (Version 1.11; Q179, Q180, Q211. The 1.10 text ended "This is
|
||||
post-v1.")
|
||||
|
||||
Added in version 1.12 (Q176, Q211). Each one names the approved design it
|
||||
is drafted from and the Q176 item it covers.
|
||||
|
||||
- **REQ-USER-3.** An organization can have more than one human. The
|
||||
organization file's human is the owner. The owner adds other humans as
|
||||
users and gives each a grant per project and instance, at one of two
|
||||
levels. A collaborator creates threads and sends in them. A viewer only
|
||||
reads threads shared with it. Only the owner adds or removes users,
|
||||
changes grants and restructures the organization. The bus takes a
|
||||
human's identity only from something it verifies, such as the Console's
|
||||
own OIDC sign-in, never from a process's own claim. (Row 193 design r5,
|
||||
e2d161e2e on `morgana/row193`, approved by Duckworth in duckworth-0018,
|
||||
sections 3 and 4. Q176 Given "RBAC enforcement"; Case 1 "Additional
|
||||
users can be configured for access".)
|
||||
- **REQ-USER-4.** A thread is private to the user who owns it unless that
|
||||
user shares it. A share is read-only, to a named user, to the
|
||||
organization's owner, or to everyone granted on the thread's project.
|
||||
REQ-USER-2 still holds for writes. A share never widens a grant: it
|
||||
counts only while the reader's grant still covers the thread. A revoke,
|
||||
an expiry or an unshare ends the reader's access on the next request. A
|
||||
user's messages stay private from the owner. What the thread's agent
|
||||
does with the owner's authority stays visible to the owner: its
|
||||
decisions, inbox entries, claims, tasks and project files. (Row 193
|
||||
design r5, sections 5.3, 5.6 and 5.7. Q176 Case 1 "Shared and private
|
||||
agent sessions available per user; RBAC".)
|
||||
- **REQ-LIFE-1.** The user creates, launches, terminates, regenerates and
|
||||
deletes agents whenever they choose, from the CLI and from the Console.
|
||||
Regenerate starts a fresh session with the same identity and role.
|
||||
Each verb is a human verb behind the human proof, and it acts on its
|
||||
own instance only. Every launch goes through the one launch path, so the
|
||||
agent limits and the kill switch (REQ-KILL-1) apply. Delete leaves run
|
||||
records write-once. Fire and delete revoke the agent's credentials
|
||||
first, and a failed revoke stops the verb and leaves the organization
|
||||
file unchanged. Create, delete, hire, fire and veto changes take effect
|
||||
without a bus restart. Until REQ-USER-3 is built, these verbs are
|
||||
owner-only. (Row 194 design r4, 7d0788236 on `honker/row194`, approved
|
||||
by Webby in e1e64ff01, sections D1, D3 and D4, and the brief's items 7
|
||||
and 8. Q176 Given "User and main agent (chief of staff, or other main)
|
||||
can create and spawn agents" and "User maintains ability to terminate,
|
||||
regenerate, or create agents via WebUI or CLI ad-hoc".)
|
||||
- **REQ-KILL-1.** One CLI command and one Console button stop all
|
||||
processing on an instance at once, and it stays stopped until a human
|
||||
clears it:
|
||||
- agent verbs that start or continue work refuse with a fixed code.
|
||||
Reads and the human's own verbs, the clear included, still work;
|
||||
- every running managed session and task run gets SIGTERM, then SIGKILL
|
||||
after a bounded wait, and each stop is an event;
|
||||
- Discord stops and can't restart;
|
||||
- every launch path refuses, the chief of staff's hires included.
|
||||
|
||||
The switch survives a bus restart and a reboot, and it stops one
|
||||
instance only. Only a human turns it on or clears it, through the human
|
||||
proof, and each act is one event with who and when. (Row 191 design r2,
|
||||
approved by Dewey in comment 29473, on the brief
|
||||
`docs/plans/2026-10-20_kill-switch.md`. Q176 Given "'Kill switch' is
|
||||
available to stop all processing immediately".)
|
||||
|
||||
### Creative library
|
||||
|
||||
Added in version 1.12 (Q176 Case 2, Q211). Drafted from the Case 2
|
||||
design r11, fb20a61b4 on `gosalyn/case2-design`, approved by Webby in
|
||||
82f50d127, with the rulings recorded after r11 up to 624212842. The
|
||||
library is the user's own writing repository.
|
||||
|
||||
- **REQ-LIB-1.** A library project maps the user's writing repository
|
||||
onto universes, books, entity types such as character and place, the
|
||||
manuscript, and playgrounds. The mapping sits in the organization file
|
||||
and fits the user's own folder layout. Only the human changes it, and
|
||||
an agent's organization write that changes it is refused. So
|
||||
`universe.book.{character,place,...}` reads as universe, book folder,
|
||||
type folder. (Design 1.1 and M9. Q176 Case 2 "Data is stored in
|
||||
little-endian organizational scheme".)
|
||||
- **REQ-LIB-2.** Playgrounds are never confused with canon. A file's scope
|
||||
comes from its path alone: a Markdown file under a playground prefix is
|
||||
playground, any other Markdown file in a book folder is canon, and
|
||||
everything else is unmapped and never returned. Lookups return canon
|
||||
unless the caller asks for playground. An agent can't cite a playground
|
||||
file as a fact, a finding or a correction. The Console shows each
|
||||
cite's scope. (Design 1.2, 5.2 and 7.4. Q176 Case 2, the playground
|
||||
items.)
|
||||
- **REQ-LIB-3.** Universes stay separate. Every lookup names one universe,
|
||||
and its results never leave it. A crossover is a hybrid universe that
|
||||
only a human creates, by editing the organization file. It names two or
|
||||
more source universes. Its lookups see its own files plus the sources'
|
||||
canon, minus the exclusions the human sets. Exclusions and pinned values
|
||||
are checked in code. The continuity agent reads the human's other
|
||||
constraints and cites them. (Design 1.4 and 3. Q176 Case 2, the
|
||||
crossover items.)
|
||||
- **REQ-LIB-4.** Git holds every change. The user commits and pushes with
|
||||
their own tools, today Obsidian with obsidian-git. The bus keeps a
|
||||
mirror of the remote, fetched with a read-only token every 60 seconds
|
||||
and before any lookup when the last fetch is older than that. It only
|
||||
fast-forwards. A force-push is held as `library-diverged` until a human
|
||||
accepts it. Agents read only the mirror's served commit and never hold
|
||||
a copy of their own, so they see the user's push within about a minute.
|
||||
Bus writes and pushes come in later rows (C2-02, C2-03b). (Design D5,
|
||||
D6, 7.1, 7.2 and 7.5. Q176 Case 2 "Git is used for all changes -- local
|
||||
and remote" and the sync items.)
|
||||
- **REQ-LIB-5.** Agents check the library through typed lookup tools:
|
||||
find, get, search, manuscript and universe. Each answer names the
|
||||
commit it read. Get returns a file's links out and links in, so the
|
||||
connections are visible to agents. The user sees them in Obsidian's
|
||||
graph and backlinks. (Design 3 and 7.1. Q176 Case 2 "The agents have
|
||||
tools to check character, place, and other data", the visualization
|
||||
item and "Connections are always visible".)
|
||||
- **REQ-LIB-6.** The creative roles are ideas, research, proofreader,
|
||||
fact-checker and continuity, plus a companion role that the user's own
|
||||
named agents run as. No creative agent can write to the user's
|
||||
repository. Its tools are the lookups and a message to the human, and
|
||||
research and companion also fetch web pages through the broker. Every
|
||||
message an agent sends the user is a short list of items. Each item
|
||||
cites a line of the repository at a commit, or a page the agent
|
||||
fetched, and the broker checks every cite before it stores the message.
|
||||
The user sees only stored messages, on every channel. (Design 4, 5.1,
|
||||
5.2 and 5.3; Q180 for Bean and Chet. Q176 Case 2, the agent list and
|
||||
"User sets strict guardrails for agent capabilities".)
|
||||
- **REQ-LIB-7.** The user talks to several creative agents in one chat. A
|
||||
room holds one thread per creative agent in a project. A message goes
|
||||
to every agent in the room, or only to the agents named by @tags at its
|
||||
start. An unknown tag is refused, and nothing is sent. The room shows
|
||||
the threads as one timeline, and each agent sees only its own thread.
|
||||
(Design D4 and 6, row C2-09b. Q176 Case 2 "converse with N agents in
|
||||
one chat session with @tagged messages".)
|
||||
|
||||
### Installer
|
||||
|
||||
Added in version 1.4 (decision 1ea053cc).
|
||||
@@ -1302,13 +1435,66 @@ latest-by date and a hard target (Q176).
|
||||
- Which OIDC provider the two v1 VMs use is open (vikunja:19/461).
|
||||
REQ-INST-2 moves into v1 if Jason picks the bundled Pocket ID for
|
||||
either instance.
|
||||
- Version 1.12:
|
||||
- The 1.11 Risks line was: "In slice 1, agents run as Jason's OS user
|
||||
(round 3, 3A). They can write anything that user can write. Until
|
||||
seats run in a container, which comes next, the broker is a rule they
|
||||
follow, not a wall. What does hold in slice 1 is that agents never
|
||||
hold service tokens."
|
||||
- The REQ-DEC-3 title in `packages/tasks/requirements.json` was
|
||||
"Authorized-human resolutions come only from a mosaic CLI session
|
||||
outside any agent run". It left out the Console session that 1.9
|
||||
added. 1.12 changes the title only. The requirement text is
|
||||
unchanged.
|
||||
- Q176 items the PRD already covered, so 1.12 adds no id for them:
|
||||
projects and threads (REQ-ORG-2, REQ-THREAD-1, REQ-THREAD-2);
|
||||
federation and shared access across instances (REQ-FED-1); custom and
|
||||
templated roles assigned to agents (REQ-ROLE-1, REQ-ROLE-3,
|
||||
REQ-TPL-1); the credential store (REQ-CRED-1 to REQ-CRED-4,
|
||||
REQ-GRANT-1 to REQ-GRANT-4); each agent's own git credentials
|
||||
(REQ-LAND-2, REQ-CRED-1); the chief of staff's hire and fire with
|
||||
the user's per-agent forbid, and restructuring (REQ-COS-3,
|
||||
REQ-ROLE-3, REQ-USER-3); the main user and the assistant
|
||||
(REQ-ASSIST-1).
|
||||
- Q176 items with no approved design, so 1.12 adds no id for them:
|
||||
several independent sessions per thread, a compaction count, and
|
||||
clearing an agent's context to start a new session. They are MVP
|
||||
plan T1 item 7, which has no queue row yet. Several sessions per
|
||||
thread differs from REQ-ROLE-2 and REQ-THREAD-2, where each thread is
|
||||
one assistant session. Row 194 refuses regenerate for a thread
|
||||
instance and leaves clearing its context to that item.
|
||||
- Writing in the WebUI: Q176 allows "WYSIWYG, Obsidian, or some other
|
||||
method". The Case 2 design keeps Obsidian (design 7.1). The WYSIWYG
|
||||
editor is the Q195 and Q196 add-on and doesn't gate 10-27.
|
||||
- The Case 2 design's playground prefixes all sit inside a book folder
|
||||
(design 1.1). Q176 also asks for universe-level playgrounds "where
|
||||
new universes can be created". The design doesn't state one, so
|
||||
REQ-LIB-2 doesn't name the level.
|
||||
- The design's 10-27 slice (design 9.2) leaves out rooms with @tags
|
||||
(C2-09b, C2-10c), hybrid universes (C2-15), bus writes and the
|
||||
Console editor (C2-02, C2-03b, C2-11a, C2-11b, C2-19). Q211 keeps
|
||||
every Q176 item in v1, and only Jason cuts one.
|
||||
- REQ-PROJ-1's "no remote" covers project record repositories. A
|
||||
library project is a separate kind with no record repository, and its
|
||||
mirror fetches from the remote (design 2.1, 7.2).
|
||||
- REQ-LIB-6 has a stated residual: an `idea` item carries free text,
|
||||
up to 5 items of 200 characters per reply, and code can't tell story
|
||||
text from advice (design 5.1). Accepting it is Jason's or Melanie's
|
||||
(design section 10, step 8).
|
||||
- Where each id is built: REQ-USER-3 and REQ-USER-4 are rows 193a to
|
||||
193d (#1691), with FED R1 to R6. REQ-LIFE-1 is row 194 (#1692) and
|
||||
its follow-up row 239. REQ-KILL-1 is row 191 (#1689). The REQ-LIB ids
|
||||
are the C2 rows in `docs/plans/2026-10-20_case2-rows.md` (#416). This
|
||||
amendment adds the requirements only.
|
||||
|
||||
## Risks and open questions
|
||||
|
||||
- In slice 1, agents run as Jason's OS user (round 3, 3A). They can
|
||||
write anything that user can write. Until seats run in a container,
|
||||
which comes next, the broker is a rule they follow, not a wall. What
|
||||
does hold in slice 1 is that agents never hold service tokens.
|
||||
- On each v1 instance, agents run as that instance's OS user, without
|
||||
sudo (Q181). They can write anything that user can write. Until seats
|
||||
run in a container, which comes after v1, the broker is a rule they
|
||||
follow, not a wall. What does hold is that agents never hold service
|
||||
tokens (REQ-CRED-1). On dragon-lin, dev agents run as Jason's OS user,
|
||||
and Jason accepts that risk (Q182). (Version 1.12.)
|
||||
- Vikunja doesn't enforce `If-Match`. The broker compares before it
|
||||
writes, and a person editing in the same moment can still be
|
||||
overwritten in an owned field (lead decision 51).
|
||||
|
||||
@@ -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, 71);
|
||||
assert.equal(list.requirements.length, 82);
|
||||
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.11",
|
||||
"version": "1.12",
|
||||
"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" },
|
||||
@@ -26,7 +26,7 @@
|
||||
{ "id": "REQ-GRANT-4", "title": "The user, the assistant in its organization or the tester on a dev instance revokes a grant at once" },
|
||||
{ "id": "REQ-DEC-1", "title": "Every decision is an append-only record: raiser, class, options, resolver, times" },
|
||||
{ "id": "REQ-DEC-2", "title": "Decisions route by class: logged, to the domain arbiter, or to the human" },
|
||||
{ "id": "REQ-DEC-3", "title": "Authorized-human resolutions come only from a mosaic CLI session outside any agent run" },
|
||||
{ "id": "REQ-DEC-3", "title": "Authorized-human resolutions come only from a mosaic CLI or signed-in Console session outside any agent run" },
|
||||
{ "id": "REQ-DEC-4", "title": "A blocking gated decision reaches an authorized human at once; the rest go in a daily digest" },
|
||||
{ "id": "REQ-DEC-5", "title": "An approval outlives its run, binds to the decision, instance and thread, and is consumed once" },
|
||||
{ "id": "REQ-DEC-6", "title": "A spec commit never reopens a settled decision" },
|
||||
@@ -70,6 +70,17 @@
|
||||
{ "id": "REQ-THREAD-2", "title": "The user creates projects and named threads; each thread is its own assistant session with kept history" },
|
||||
{ "id": "REQ-TPL-1", "title": "Templates for agent roles and for organization types" },
|
||||
{ "id": "REQ-FED-1", "title": "Federation between installs: person-to-person in v1, agent-to-agent post-v1" },
|
||||
{ "id": "REQ-USER-3", "title": "Several humans per organization: the owner, and users with collaborator or viewer grants per project and instance" },
|
||||
{ "id": "REQ-USER-4", "title": "A thread is private to its user unless shared read-only; a share never widens a grant and ends on revoke" },
|
||||
{ "id": "REQ-LIFE-1", "title": "The user creates, launches, terminates, regenerates and deletes agents from the CLI and the Console" },
|
||||
{ "id": "REQ-KILL-1", "title": "One human command or Console button stops all work, runs, Discord and launches on an instance until a human clears it" },
|
||||
{ "id": "REQ-LIB-1", "title": "A library maps the user's writing repository onto universes, books, types and playgrounds; only the human changes it" },
|
||||
{ "id": "REQ-LIB-2", "title": "Scope comes from the path; lookups default to canon and a playground file is never cited as canon" },
|
||||
{ "id": "REQ-LIB-3", "title": "Universes stay separate; a crossover is a hybrid universe only a human creates, reading its sources' canon" },
|
||||
{ "id": "REQ-LIB-4", "title": "Git holds every change; the bus fast-forwards a read-only mirror every 60 seconds and agents read only that" },
|
||||
{ "id": "REQ-LIB-5", "title": "Agents check the library through typed lookup tools that name the commit and show links out and in" },
|
||||
{ "id": "REQ-LIB-6", "title": "Creative agents can't write the repository; every message to the user is short cited items the broker checks" },
|
||||
{ "id": "REQ-LIB-7", "title": "One chat room with several creative agents, addressed by leading @tags; an unknown tag sends nothing" },
|
||||
{ "id": "REQ-INST-1", "title": "The installer offers optional components: pinned, health-checked, removable, switched on in config; first is SearXNG" },
|
||||
{ "id": "REQ-INST-2", "title": "With no OIDC provider to configure, the installer deploys a bundled Pocket ID, Q203 (post-v1)" },
|
||||
{ "id": "REQ-INST-3", "title": "One-command install of a named instance from a profile, and one-command upgrade with backup and rollback" }
|
||||
|
||||
@@ -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, 71);
|
||||
assert.equal(ids.length, 82);
|
||||
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.11']);
|
||||
assert.deepEqual([list.prd, list.version], ['docs/prd/mosaic-stack.md', '1.12']);
|
||||
});
|
||||
|
||||
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[71].id: REQ-ROLE-1 twice'));
|
||||
assert.throws(() => loadRequirements(join(dir, 'twice.json')), listError('requirements[82].id: REQ-ROLE-1 twice'));
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user