Compare commits
2
Commits
sp7
...
ludwig/prd-1.13
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd1f7d0b12 | ||
|
|
e38e755e39 |
No files matched your search
+114
-10
@@ -1,6 +1,6 @@
|
||||
# PRD: Mosaic Stack
|
||||
|
||||
- Status: approved, version 1.12. Jason approved draft 0.4 unchanged as
|
||||
- Status: approved, version 1.13. 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
|
||||
@@ -36,7 +36,19 @@
|
||||
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).
|
||||
vikunja:19/462). Version 1.13 adds the session requirements from the
|
||||
approved T1 item 7 design and replaces REQ-ROLE-2 and REQ-THREAD-2. It
|
||||
takes the same path as 1.11 (mos-1231, vikunja:19/463).
|
||||
- Version 1.13 source, Mos's ruling Q1 in mos-1231 on 2026-10-21: "T1
|
||||
item 7 is v1." It quotes Jason's Q176 lines, TARGET.md:57 "Agents can
|
||||
have multiple independent sessions within a given project (thread)",
|
||||
:104 "User must be able to see the number of compactions that have
|
||||
occurred for a session" and :105 "User must be able to easily clear the
|
||||
context for the agent to trigger a new session". Mos's reading of Q211:
|
||||
"where REQ-ROLE-2 and REQ-THREAD-2 differ from line 57, line 57 wins."
|
||||
And: "The ids and the REQ-ROLE-2 and REQ-THREAD-2 changes come in 1.13
|
||||
from the approved design." Mos's further readings, mos-1235 and
|
||||
mos-1236, are in the Version 1.13 technical note.
|
||||
- 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
|
||||
@@ -297,9 +309,13 @@ parent requirement is refused.
|
||||
|
||||
Any action the file doesn't list is gated.
|
||||
- **REQ-ROLE-2.** Each role instance has one holder at a time. The
|
||||
assistant is the exception: it has one holder per thread at a time. A
|
||||
claim takes a lock and logs it, and releasing the role or ending the run
|
||||
frees it. The chief of staff may end another role's run, and that act is
|
||||
assistant is the exception: within a thread it can have several
|
||||
independent sessions, each with one holder at a time. No other role
|
||||
holds a thread session. A claim takes a lock and logs it. An assistant
|
||||
claim names the organization, thread, instance and session. Releasing
|
||||
the role or ending the run frees only that holder. Creating or clearing
|
||||
a session grants no role authority, and a pending approval never moves
|
||||
to another session. (Version 1.13.) The chief of staff may end another role's run, and that act is
|
||||
logged with its reason. Anyone else who revokes a stuck holder needs a
|
||||
resolved decision, and the revoke cites it. The assistant is the
|
||||
exception here too (version 1.6, Q169): the chief of staff is the only
|
||||
@@ -1007,11 +1023,17 @@ Added in version 1.1 (decision 03130d08).
|
||||
area. Added in version 1.2.
|
||||
- **REQ-THREAD-1.** Threads live under projects.
|
||||
- **REQ-THREAD-2.** The user creates projects and names threads inside
|
||||
them, from the CLI or the WebUI. Each thread is a separate assistant
|
||||
session. A thread's messages are kept. When the user comes back to a
|
||||
thread, after an idle stop or a restart, the assistant picks up where
|
||||
it left off with that history. One thread's conversation never appears
|
||||
in another's. Added in version 1.2.
|
||||
them, from the CLI or the WebUI. A thread holds one or more independent
|
||||
sessions of its assistant, on pi or Claude Code. Each session has its
|
||||
own messages, native context, workspace and compaction count, and only
|
||||
one run writes its workspace at a time. A thread's messages are kept.
|
||||
When the user comes back to a session, after an idle stop or a restart,
|
||||
the assistant picks up where that session left off, never in another
|
||||
session. A client that names only the thread uses that thread's saved
|
||||
default session. One session's conversation never appears in another
|
||||
session, thread or organization, under REQ-USER-2, REQ-USER-3 and
|
||||
REQ-USER-4. Added in version 1.2. (Version 1.13: sessions, from the
|
||||
design `docs/plans/2026-10-21_t1-sessions.md`, 2c843d190 on `huey/t1-sessions-design`, approved by Scrooge in scrooge-0007 and scrooge-0008, D1 to D3 and D9.)
|
||||
- **REQ-TPL-1.** Templates exist for agent roles and for organization
|
||||
types.
|
||||
- **REQ-FED-1.** Installs can federate with each other. Person-to-person
|
||||
@@ -1085,6 +1107,46 @@ is drafted from and the Q176 item it covers.
|
||||
switch, and protected mode can clear itself but never a human kill
|
||||
(`docs/plans/2026-10-21_q198-system-manager.md` D13 and section 5).
|
||||
|
||||
Added in version 1.13 (Q176, Q211, mos-1231). Drafted from the
|
||||
design `docs/plans/2026-10-21_t1-sessions.md`, 2c843d190 on `huey/t1-sessions-design`, approved by Scrooge in scrooge-0007 and scrooge-0008. They cover MVP plan T1 item 7.
|
||||
|
||||
- **REQ-SESS-1.** The user sees how many compactions each session has
|
||||
completed over its life, on pi and Claude Code. Starts, failed
|
||||
compactions, branch summaries and repeated reads don't count. An idle
|
||||
stop or a restart leaves the count as it is. A new session and a clear
|
||||
successor start at zero, and a retired session keeps its count. When
|
||||
the count can't be proven, it shows unknown with the reason, never
|
||||
zero. Anyone who can read the thread sees the count. The organization's
|
||||
owner can see a count and status, with opaque ids only, for another
|
||||
user's thread it can't read, but no names, messages or summaries.
|
||||
(Design D4 and D6, tests T3 and T5. Q176 TARGET.md:104.)
|
||||
- **REQ-SESS-2.** Clear context ends one session and starts a fresh
|
||||
successor for the same assistant. Two humans can create or clear a
|
||||
session: the organization's owner on its own thread, subject to the
|
||||
instance's policy, and a collaborator who owns the thread, while a
|
||||
write grant still covers it. The organization's owner on another
|
||||
user's thread, a viewer, a share recipient and an agent can't. Clear waits until the session stops at a turn boundary
|
||||
with no child running, and shows that it is clearing until then. It
|
||||
never force-stops a busy session. The old session's messages, results
|
||||
and run evidence stay as they are. Its workspace stays at its path with
|
||||
any unpushed work, and nothing writes there again. The successor gets
|
||||
new native stores and a fresh checkout of the approved revision. It
|
||||
gets nothing of the old context: no history, summary, prompt or pending
|
||||
input. Undelivered old input is cancelled with a receipt, never
|
||||
replayed. A repeated clear returns the same operation, and one clear
|
||||
makes at most one successor. (Design D4, D5 and D7, tests T4 and T5.
|
||||
Q176 TARGET.md:105.)
|
||||
- **REQ-SESS-3.** Every start of a session goes through the same checks
|
||||
as any launch: an open, a first send, a restart, an idle wake and a
|
||||
clear successor. The checks are the human's current authority, the
|
||||
configured role and harness, launch revocation, the kill switch
|
||||
(REQ-KILL-1), the agent limits and admission. The claim is checked
|
||||
again just before the spawn. A session never picks its own route or
|
||||
priority. An admission service that is switched on but unavailable
|
||||
refuses. While the kill switch is on, a clear or a new start refuses
|
||||
with `processing-halted` and changes nothing. A clear never sets or
|
||||
clears the kill switch. (Design D8, test T6.)
|
||||
|
||||
### Creative library
|
||||
|
||||
Added in version 1.12 (Q176 Case 2, Q211). Drafted from the Case 2
|
||||
@@ -1509,6 +1571,48 @@ latest-by date and a hard target (Q176).
|
||||
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.
|
||||
- Version 1.13:
|
||||
- The 1.12 text of REQ-ROLE-2 began: "Each role instance has one holder
|
||||
at a time. The assistant is the exception: it has one holder per
|
||||
thread at a time. A claim takes a lock and logs it, and releasing the
|
||||
role or ending the run frees it." The rest, from "The chief of staff
|
||||
may end another role's run", is unchanged. Who may end or revoke the
|
||||
assistant is unchanged.
|
||||
- The 1.12 text of REQ-THREAD-2 was: "The user creates projects and
|
||||
names threads inside them, from the CLI or the WebUI. Each thread is a
|
||||
separate assistant session. A thread's messages are kept. When the
|
||||
user comes back to a thread, after an idle stop or a restart, the
|
||||
assistant picks up where it left off with that history. One thread's
|
||||
conversation never appears in another's. Added in version 1.2."
|
||||
- The titles of REQ-ROLE-2 and REQ-THREAD-2 in
|
||||
`packages/tasks/requirements.json` change with their text.
|
||||
- Mos's readings, which the design records in section 8 (mos-1235).
|
||||
They are reported to Jason after this version lands and don't go to
|
||||
him as questions:
|
||||
- Q1: the count is for the session's whole life. A clear successor is
|
||||
a new session under TARGET.md:105 and starts at zero.
|
||||
- Q2: clear waits for a proven safe stop and shows that it is
|
||||
pending. It adds no force-stop, and the kill switch stays separate.
|
||||
- Q3: the organization's owner doesn't clear another user's session
|
||||
without that user's write authority, because "A user's messages
|
||||
stay private from the owner" (REQ-USER-4).
|
||||
- Mos's ruling mos-1236: sessions are for the assistant (the
|
||||
`THREAD_DEFINITION` instance) only. Letting other roles hold thread
|
||||
sessions would change launch policy and is outside Vikunja 463.
|
||||
- Build dependency (design N2, vikunja:19/466): Claude Code's format
|
||||
for a completed compaction has to be pinned offline, and a reader for
|
||||
the managed session stores added. Today's reader covers pi only.
|
||||
REQ-SESS-1 can't pass its acceptance test until both exist, and the
|
||||
count isn't shipped for either harness until then.
|
||||
- Until Q198's admission step is built, REQ-SESS-3 uses the existing
|
||||
launcher and limit checks, plus row 191's kill checks once they land
|
||||
(design D8).
|
||||
- Moving existing threads keeps their history: each becomes one
|
||||
default session, bound to its existing native store, with nothing
|
||||
rewritten. The old shared instance workspace is drained and kept as
|
||||
history (design D9).
|
||||
- The build row is Sage's to file under Vikunja 463. This amendment
|
||||
adds the requirements 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, 82);
|
||||
assert.equal(list.requirements.length, 85);
|
||||
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,9 +1,9 @@
|
||||
{
|
||||
"prd": "docs/prd/mosaic-stack.md",
|
||||
"version": "1.12",
|
||||
"version": "1.13",
|
||||
"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" },
|
||||
{ "id": "REQ-ROLE-2", "title": "One holder per role instance, one per assistant session; the chief of staff may end a run, others need a decision" },
|
||||
{ "id": "REQ-ROLE-3", "title": "The user and the chief of staff write the organization file; the chief of staff's writes go through a logged broker verb" },
|
||||
{ "id": "REQ-ROLE-4", "title": "The first organization is Mosaic Stack: chief of staff, assistant, PM, CTO, coder and reviewer" },
|
||||
{ "id": "REQ-ROLE-5", "title": "Q167 adds security-reviewer and merge-gate; merge-gate raises the merge in the technical domain and lands it" },
|
||||
@@ -67,13 +67,16 @@
|
||||
{ "id": "REQ-USER-1", "title": "Users and RBAC at install and organization level; an agent reaches only its allowed projects and threads" },
|
||||
{ "id": "REQ-USER-2", "title": "Only a thread's owning user, their assistant and the chief of staff's replies reach the thread" },
|
||||
{ "id": "REQ-THREAD-1", "title": "Threads live under projects" },
|
||||
{ "id": "REQ-THREAD-2", "title": "The user creates projects and named threads; each thread is its own assistant session with kept history" },
|
||||
{ "id": "REQ-THREAD-2", "title": "The user creates projects and named threads; a thread holds independent assistant sessions, each 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-SESS-1", "title": "Each session shows its lifetime count of completed compactions on pi and Claude Code; an unproven count shows unknown" },
|
||||
{ "id": "REQ-SESS-2", "title": "Clear context retires a session after a safe stop and starts a fresh successor with none of the old context" },
|
||||
{ "id": "REQ-SESS-3", "title": "Every session start passes the launch checks: authority, route, revocation, kill switch, limits and admission" },
|
||||
{ "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" },
|
||||
|
||||
@@ -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, 82);
|
||||
assert.equal(ids.length, 85);
|
||||
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.12']);
|
||||
assert.deepEqual([list.prd, list.version], ['docs/prd/mosaic-stack.md', '1.13']);
|
||||
});
|
||||
|
||||
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[82].id: REQ-ROLE-1 twice'));
|
||||
assert.throws(() => loadRequirements(join(dir, 'twice.json')), listError('requirements[85].id: REQ-ROLE-1 twice'));
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user