From 92c10d56ebedb4e0be0f79abab764020746721f7 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Fri, 16 Oct 2026 12:49:22 -0500 Subject: [PATCH] docs: PRD version 1.5 under Q167 and the task 314 acceptance run (row 135, #1629) Version 1.5 records Jason's Q167 ruling and added text as its source block. It replaces REQ-DEC-2 routing: a gated decision citing the project's current spec commit goes to the domain arbiter, and only an uncited decision or a hard wait goes to the human. It adds the hard waits (REQ-WAIT-1 to 3, with data.delete, network.expose and account.create), projects and the spec file (REQ-PROJ-1 to 4), agent landing (REQ-LAND-1), approvals that outlive the run (REQ-DEC-5), settled decisions under a new spec (REQ-DEC-6), the four workflow roles and proactive contracts (REQ-ROLE-5, 6), staff requests (REQ-COS-2), assistant summaries (REQ-ASSIST-3) and name addressing (REQ-MSG-2). docs/acceptance/314.md is the run Jason does in the Stack once the rows are live. Co-Authored-By: Claude Opus 5.5 --- docs/acceptance/314.md | 152 +++++++++++++ docs/prd/mosaic-stack.md | 244 ++++++++++++++++++++- packages/bus/tests/requirements.test.mjs | 2 +- packages/tasks/requirements.json | 17 +- packages/tasks/tests/requirements.test.mjs | 6 +- 5 files changed, 412 insertions(+), 9 deletions(-) create mode 100644 docs/acceptance/314.md diff --git a/docs/acceptance/314.md b/docs/acceptance/314.md new file mode 100644 index 000000000..f4b665002 --- /dev/null +++ b/docs/acceptance/314.md @@ -0,0 +1,152 @@ +# Acceptance run for task 314 (Q167) + +Jason runs this inside the Stack once rows 135 to 143 and 147 to 149 are +live. It checks PRD version 1.5: one need goes from his spec to a landed +commit, and only hard waits reach his inbox. + +`` is the business the bus host runs. `` is the +project the need belongs to, `stack` for this run. Every command runs on +the host, as Jason. + +The need is a `mosaic version` command that prints the release and the +bus schema. + +## Before the run + +- `mosaic bus status` says the host is live. +- `mosaic inbox` shows no open decision. If one is open, resolve or + supersede it first, so step 6 starts from an empty inbox. +- The organization has security-reviewer and merge-gate instances, added + through the chief of staff's organization change with Mos's go, and + both are in `launch.instances`. +- `arbiters.technical` is `cto`, which step 5 assumes. + +## Steps + +1. Create the project repository, if it doesn't exist yet: + + ``` + mosaic project init + mosaic project check + ``` + + Pass: `check` reports the layout valid. The first commit's author is + Jason. (REQ-PROJ-1) + +2. Open the spec in the Console editor and write it: + + > North star: anyone can tell what is running in one command. + > Need: a `mosaic version` command that prints the release and the bus + > schema. + + Before saving, open the same file in a second Console tab. Save in the + first tab. Pass: the save makes one local commit with Jason as author, + and the editor shows the new commit. Then edit and save in the second + tab, which still holds the old commit: the save is refused and writes + nothing. (REQ-PROJ-2, REQ-PROJ-3) + +3. Tell the assistant about the need: + + ``` + mosaic talk assistant "New need: the mosaic version command in spec/north-star.md. Start it." + ``` + + Pass: `talk` prints only the assistant's reply to this message. + +4. Watch the work start: + + ``` + mosaic tasks + mosaic agents + mosaic trail + ``` + + Pass, all on the trail: + - pm makes the tasks and sends the chief of staff a staff request + naming the roles and counts (REQ-COS-2); + - the chief of staff launches a coder, a reviewer and a + security-reviewer through role.launch (REQ-ROLE-5); + - the coder pushes a work ref, and the reviewer and the + security-reviewer each approve it. + +5. Watch it land: + + ``` + mosaic trail + git -C log --oneline -3 main + ``` + + Pass: + - pm hands the approved candidate to merge-gate, and merge-gate + raises the `git.merge.protected` decision citing + `spec/north-star.md` at the commit from step 2; + - the CTO resolves it, not Jason (REQ-DEC-2); + - merge-gate lands it, the trail records the allowed action with the + landed commit, and the commit is on the working repository's `main` + (REQ-LAND-1). + +6. Check the inbox, then ask for one hard wait on purpose: + + ``` + mosaic inbox + mosaic talk assistant "Open a new account for the project on an outside service." + mosaic inbox + ``` + + Pass: the first `inbox` is empty, so nothing from steps 3 to 5 reached + Jason. After the request, the inbox holds one decision for + `account.create`. Resolve it with the reject option. (REQ-WAIT-1) + +7. Restart the host halfway through the next merge. Use a second small + change, for example "print the help when an option is unknown", and + restart once the CTO has resolved its merge decision and before + merge-gate lands it. Mos or Jason runs the restart: + + ``` + mosaic bus stop + mosaic bus start --pm + ``` + + Pass: the merge lands from a new run of the same merge-gate instance + with the approval from before the restart, and no new decision is + raised. + (REQ-DEC-5) + +8. Change the spec in the Console editor: also print the commit. Save. + + Pass: + - the save makes a new commit by Jason; + - `mosaic trail` shows no decision settled under the step 2 commit + reopened (REQ-DEC-6); + - `mosaic trail` shows new raises citing the new commit, and no + raise citing the step 2 commit accepted after the save; + - pm and the CTO each answer the spec commit with an accept + (REQ-PROJ-4). + +9. Change the spec in a way that breaks a settled decision, for example: + "the version command prints nothing and exits." Save. + + Pass: pm or the CTO answers with a BLOCK naming the conflict, the + commit stays, and the assistant tells Jason about the block in its own + words. The assistant's message doesn't quote the chief of staff's text. + (REQ-PROJ-4, REQ-ASSIST-3) Then revert the spec in the editor with a + new commit. + +10. Give the coder instance a name with the CLI command row 141 adds + (`docs/TOOLS.md` names it once that row lands), then send it a + message by that name: + + ``` + mosaic agents + mosaic talk "Reply with your role name." + ``` + + Pass: the reply comes from the instance with that name, and the trail + records both the name and the instance. (REQ-MSG-2) + +## Result + +The run passes when every step passes. Record the run with the date, the +release, the bus schema and the result of each step in Vikunja task 314. +A failed step names the requirement it checks, so the fix goes back to +that row. diff --git a/docs/prd/mosaic-stack.md b/docs/prd/mosaic-stack.md index bff092b56..bb4ddcd20 100644 --- a/docs/prd/mosaic-stack.md +++ b/docs/prd/mosaic-stack.md @@ -1,6 +1,6 @@ # PRD: Mosaic Stack -- Status: approved, version 1.4. Jason approved draft 0.4 unchanged as +- Status: approved, version 1.5. 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 @@ -10,8 +10,45 @@ decision 143). Mos reviewed the 1.3 text before it landed. Version 1.4 adds REQ-WEB-3 and REQ-INST-1, approved by Jason in decisions 021af0c8 (prd.approve, yes; request dfebf8ce) and 1ea053cc (prd.approve, - yes; request b28979c9). It is never edited in place. Changes are a new + yes; request b28979c9). Version 1.5 records Jason's Q167 ruling and + his added Q167 text, relayed by Mos on 2026-10-15. Under Q167 Jason's + confirmation of the text is the approval, so there is no in-Stack + prd.approve for it. It is never edited in place. Changes are a new version. +- Version 1.5 source, Jason's words relayed by Mos on 2026-10-15: + - Q167: "Me having to approve every decision within the Stack is not + working for me. I gave a directive, I want it to be done." and "Use + the T3 seats to make these updates and changes, so I can have a + functional system." + - Q167, added text: "All north star specs should be visible and + modifiable by the user within each given Project. I need to be able + to read and make the changes ad-hoc without an agent when desired. + This will allow review and revise to occur outside the chat. The + agent will be able to see the changes of course. Changes made should + use git (at least locally) to maintain the change history. + Organization of data in a Project is critical. We need a data + structure with json files and templates for everything. Markdown + files with a WYSIWYG editor for the north star/spec files. + Documentation within the project. Consistent storage of docs, reqs, + decisions, etc. should be kept in the project for reference as + needed. We will need to have these agents for a coding workflow: - + coder - code review - security review - merge gate. The appropriate + agent profile will be assigned to the agents. The roles and tools + allow agentic control of the needed workflow steps. Autonomy within + the rails is encouraged. Agents are proactive. The rest of your + reading is accurate." + - On the revised row list (task 314, comment 225): "Your decisions look + good. Proceed." + - Jason's waits list, as Mos gave it: spending money, deleting data, + anything irreversible, new internet exposure, new external accounts, + messages to people outside the fleet, and force-push or history + rewrite. Mos's reading, Q5: "Q167 covers shrinking GATED_ONLY and the + role grants through rows 135 and 139." Sage's plan for the rows adds + that any change to the list itself, and any grant of a listed action + to a role, also goes to Jason. + - Mos's reading, Q4: agents land into the business working + repository's protected branch through the host. This repository's + canonical `refactor` branch stays the lead's landing. - Version 1.3 source, Jason's words relayed by Mos: - Q153: "2. agreed. Make it modular though. We should be able to extend without code change on the core app." Mos's reading, which @@ -158,6 +195,30 @@ parent requirement is refused. assistant's name is set in the organization file. Jason's may be named Mos. +Added in version 1.5 (Q167): + +- **REQ-ROLE-5.** The coding workflow has four roles, each with its own + role file: + - coder, which writes the change; + - reviewer, which gives the code review verdict; + - security-reviewer, which reviews a candidate for security only and + approves or blocks with the reason. It has read-only tools and the + verdict, and no shell, no write tools and no push; + - merge-gate, which takes a candidate the reviewers approved, raises + the merge decision for it in the technical domain, so the CTO + decides, and lands it once the decision is resolved (REQ-LAND-1). + Otherwise it reports the refusal. Its one grant is + `git.merge.protected` as a cross-role action, which is what landing + checks. Raising a decision needs no grant. It has no write tools. + Because only the instance that raised an approval can consume it + (REQ-DEC-5), the role that lands is the role that raises. + + Instances of these roles are added through the chief of staff's + organization change verb (REQ-ROLE-3). +- **REQ-ROLE-6.** Agents are proactive. Every role contract says: within + your grants, act on what you see without waiting to be asked, and + raise a decision or send a message for anything outside them. + Added in version 1.2: - **REQ-COS-1.** The chief of staff runs the organization. It hires and @@ -166,6 +227,10 @@ Added in version 1.2: from the assistant and assigns it through the roles that do it. It never talks to the user. Gated decisions still reach the human through the inbox (REQ-DEC-2, REQ-DEC-4). +- **REQ-COS-2.** The PM asks the chief of staff for staff. A staff request + names the roles and how many of each. The chief of staff launches them + through role.launch, within the agent limits (REQ-LIMIT-1). (Version + 1.5.) - **REQ-ASSIST-1.** The assistant is the user's main agent. Each user has one assistant role per organization. It talks with the user, and it passes work for the organization to the chief of staff. It doesn't @@ -176,6 +241,9 @@ Added in version 1.2: chief of staff; - only the user and the chief of staff may send to the assistant; - every refused send is logged with its reason. +- **REQ-ASSIST-3.** The assistant tells the user what other roles sent it + in its own words. It summarizes and doesn't relay their text. (Version + 1.5.) ### Variables @@ -217,10 +285,21 @@ Added in version 1.2: - its timestamps. A correction is a new row. -- **REQ-DEC-2.** Routing follows the decision's class: +- **REQ-DEC-2.** Routing follows the decision's class and whether it + cites the project's spec (REQ-PROJ-2). Version 1.5 replaces the 1.0 + text, which sent every gated decision to the human: - routine and within-role decisions are logged; - cross-role decisions go to the business's arbiter for that domain; - - gated decisions go to the human. + - a gated decision whose raise cites the project's current spec commit + goes to the business's arbiter for its domain, technical or delivery, + and not to the human; + - a gated decision with no spec citation goes to the human; + - a hard wait (REQ-WAIT-1) goes to the human whether or not it cites + the spec. + + A raise that cites a spec commit other than the current one is + 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 through a broker. The broker stamps role and run from the launch record. @@ -229,6 +308,49 @@ Added in version 1.2: connector (#1509). Everything else goes into one daily digest at 08:00 Central. (Round 2, answers 2A and 3A; round 3, 4A and 5A.) +Added in version 1.5 (Q167): + +- **REQ-DEC-5.** An approval outlives the run that raised it. It binds to + the decision and to the role instance and thread that raised it. A + later run of the same instance, on the same thread, may consume it + once. The first consuming action is + recorded, a second consume is refused, and another instance can't + consume it. Superseding a decision follows the same rule. +- **REQ-DEC-6.** A new spec commit never reopens a settled decision. Each + decision records the spec path and commit its raise cited. A decision + settled under one commit stays settled when a later commit lands, and + new raises cite the new commit. + +### Hard waits + +Added in version 1.5 (Q167). + +- **REQ-WAIT-1.** These are the hard waits. Each always goes to the + human, and each maps to actions in the closed vocabulary: + + | Jason's wait | Actions | + | --- | --- | + | Spending money | `spend` | + | Deleting data | `data.delete`, new in 1.5 | + | Anything irreversible | `data.delete`, `git.push.protected` and REQ-WAIT-3 | + | New internet exposure | `network.expose`, new in 1.5: a listener, port, tunnel, DNS record or proxy route reachable from outside the host. `deploy` stays a hard wait too. | + | New external accounts | `account.create`, new in 1.5, and `credential.mint` | + | Messages to people outside the fleet | `message.external` | + | Force-push or history rewrite | `git.push.protected`, which covers a push to a protected branch and any force push or history rewrite on any branch | + + The always-gated lists in the broker and the business vocabulary hold + exactly these actions. `git.merge.protected`, `policy.change`, + `prd.approve` and `role.revoke` leave those lists and route by + REQ-DEC-2. REQ-ROLE-2 still requires a resolved decision for a revoke. +- **REQ-WAIT-2.** No role file may grant a hard-wait action, at any + class, and the validator refuses a file that does. A change to the + hard-waits list, or a grant of a hard-wait action to a role, is itself + a hard wait. The list changes only by a reviewed commit to the + vocabulary, under a new PRD version that Jason approves. +- **REQ-WAIT-3.** An action added to the vocabulary is a hard wait until a + PRD version says it isn't. The reviewed commit that adds it names which + it is. + ### Messages - **REQ-MSG-1.** Messages are addressed to a role. They are append-only @@ -237,6 +359,13 @@ Added in version 1.2: the assistant sends work to the chief of staff, the reply comes back to the same thread. T3 and Discord carry messages; the address is still the role. +- **REQ-MSG-2.** Messages can also be addressed by agent name. A role + instance may have a name, unique in its business, that equals no + instance key and no role name. A send takes a name or a role. A name + resolves to its instance, the message records both, and a role still + delivers as REQ-MSG-1 says. The human sets names through the CLI. The + chief of staff sets them once its role file grants that within-role. + (Version 1.5.) ### Tasks @@ -257,6 +386,70 @@ Added in version 1.2: - **REQ-TASK-4.** The queue keeps the agents' lock, review rounds and audit log. No field syncs in both directions. +### Projects + +Added in version 1.5 (Q167). + +- **REQ-PROJ-1.** Each project keeps its records in its own local git + repository, separate from its code checkout, with no remote. The + layout is fixed and versioned: `project.json`, `spec/north-star.md`, + `docs/`, `requirements/` and `decisions/` with one JSON file per + record, and `templates/` with a template for each kind. Each JSON kind + has a schema, and a record that fails it is refused. `mosaic project + init` creates the repository with its first commit as the business's + human. +- **REQ-PROJ-2.** The north-star spec is `spec/north-star.md` in the + project repository. Only the human commits to it. Agents read it and + never write it. The spec counts only when its last commit's author is + the business's human. Agents write docs, requirements and decisions as + agent-authored commits, through the layout's validators. +- **REQ-PROJ-3.** The Console has an editor for the spec and the + Markdown files in `docs/`. The user opens a file at its current commit, + edits its Markdown source beside a rendered preview, and saves it as + one local commit with the human as author. A save made from a commit + older than the file's last commit is refused and writes nothing. The + preview runs no script from the file and is built from code in this + repository. A WYSIWYG editor may replace the source view only with a + library that is vendored and pinned with a permissive license and a + recorded hash for each file, loads nothing at runtime, and needs no + change to the Console's content security policy. No library passed + that for 1.5. +- **REQ-PROJ-4.** Agents review the human's spec commits. Each human + commit to the spec saved through the Console editor (REQ-PROJ-3) sends + one notice to the PM and the CTO. A commit the human makes with git + outside the Console sends no notice yet. They check + the change against settled decisions and work in flight, and each + answers with an accept or a BLOCK that names the conflict. A BLOCK + doesn't revert the commit. It goes to the assistant through the chief + of staff (REQ-ASSIST-2), and the assistant tells the user (REQ-ASSIST-3). + +### Landing + +Added in version 1.5 (Q167, Mos's reading Q4). + +- **REQ-LAND-1.** Agents land approved merges into the business working + repository. The run that holds an approved `git.merge.protected` + decision asks the host to land the work ref the decision names into + the working repository's `main`. The host runs the landing checks and + the project's gate: + - the decision is resolved with the approval option; + - the ref is at the reviewed commit, and a verdict approves it; + - the decision isn't superseded; + - the base hasn't moved. + + A refusal is logged on the task's trail with its code, and a project + with no gate is refused. A landing is recorded as the allowed action + with the landed commit, and it consumes the decision (REQ-DEC-5). This + repository's canonical branch is never a target. + + Only a role whose role file grants `git.merge.protected` as a + cross-role action can land. A merge decision raised by a role without + that grant is gated, and its approval never lands, whether the arbiter + or the human gave it. So an arbiter's judgment can't move landing to a + role REQ-ROLE-5 didn't give it. The land operation refuses a gated + decision; the check ships with whichever of rows 137 and 139 lands + second. + ### Interface - **REQ-CLI-1.** `mosaic` is the front door. From it Jason can: @@ -486,6 +679,10 @@ itself from them, five pieces in a row. For each piece: (Round 1, answer A; the assistant and threads from version 1.2.) +Version 1.5 adds Jason's Q167 acceptance run, `docs/acceptance/314.md`. +It passes when one need goes from Jason's spec to a landed commit with +only hard waits in his inbox. + ## Technical considerations - Vikunja v2.7.0 is AGPL-3.0. Its API tokens can't create users or mint @@ -623,6 +820,45 @@ itself from them, five pieces in a row. For each piece: the requirement only. - REQ-WEB-2 is held for the Console decide buttons amendment (vikunja:19/266), so its id is not reused here. +- Version 1.5: + - The 1.0 text of REQ-DEC-2 was: "Routing follows the decision's + class: routine and within-role decisions are logged; cross-role + decisions go to the business's arbiter for that domain; gated + decisions go to the human." On 2026-10-15 the Stack routed 16 + decisions, and all 16 went to Jason. 9 of them were `policy.change` + or `prd.approve`, which no role file could grant. + - Before 1.5 the always-gated lists, `GATED` in + `packages/bus/src/broker.mjs` and `GATED_ONLY` in + `packages/business/src/vocabulary.mjs`, held nine actions: + `credential.mint`, `git.merge.protected`, `git.push.protected`, + `deploy`, `spend`, `message.external`, `policy.change`, + `prd.approve` and `role.revoke`. Row 139 (#1633) changes them to + REQ-WAIT-1's list and adds `data.delete`, `network.expose` and + `account.create`. + - The arbiters are the organization file's `arbiters.technical` and + `arbiters.delivery` (`packages/bus/src/broker.mjs`). + - Where each requirement is built, all under Vikunja P19 task 314: + REQ-DEC-5 is row 136 (#1630); REQ-PROJ-1 is row 147 (#1641); + REQ-PROJ-2 and REQ-DEC-6 are row 138 (#1632); REQ-COS-2 is row 140 + (#1634). Those are landed. REQ-LAND-1 is row 137 (#1631); + REQ-DEC-2 and REQ-WAIT-1 to REQ-WAIT-3 are row 139 (#1633); + REQ-MSG-2 is row 141 (#1635); REQ-PROJ-4 and REQ-ASSIST-3 are row 143 + (#1637); REQ-PROJ-3 is row 148 (#1642); REQ-ROLE-5 and REQ-ROLE-6 + are row 149. This amendment adds the requirements only. + - The spec counts as confirmed when its last commit's author name is + the business's `human` (`packages/project/src/read.mjs`). The broker + refuses a raise that cites another commit with `stale-spec`, and an + unconfirmed spec with `spec-unconfirmed`. Until `mosaic project + init` runs for a project, spec reads and record writes for it are + refused. + - `git.push.protected` covering force pushes on any branch is new in + 1.5. Today the host refuses a non-fast-forward push to the working + repository (`packages/seat/src/working.mjs`), so no role can force + push. REQ-WAIT-1 makes any future path to one a hard wait. + - REQ-PROJ-4 covers Console saves only (row 143). Noticing spec commits + made with git outside the Console is a later row. + - REQ-LAND-1's refusal of a gated merge decision is pinned in rows 137 + and 139. Row 139 carries it, or row 137 if 139 lands first. ## Risks and open questions diff --git a/packages/bus/tests/requirements.test.mjs b/packages/bus/tests/requirements.test.mjs index 0c1a104cf..d1334a71c 100644 --- a/packages/bus/tests/requirements.test.mjs +++ b/packages/bus/tests/requirements.test.mjs @@ -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, 43); + assert.equal(list.requirements.length, 58); assert.deepEqual(call(b, agent('coder'), 'requirements'), list); assert.throws(() => call(b, human, 'requirements'), /agent-required/); assert.throws(() => call(b, reader, 'requirements'), /read-only/); diff --git a/packages/tasks/requirements.json b/packages/tasks/requirements.json index 2d56cf395..f4d9f35c7 100644 --- a/packages/tasks/requirements.json +++ b/packages/tasks/requirements.json @@ -1,14 +1,18 @@ { "prd": "docs/prd/mosaic-stack.md", - "version": "1.4", + "version": "1.5", "requirements": [ { "id": "REQ-ROLE-1", "title": "Each role is a reviewed roles/.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-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" }, + { "id": "REQ-ROLE-6", "title": "Agents are proactive: each role contract says to act within its grants without waiting to be asked" }, { "id": "REQ-COS-1", "title": "The chief of staff runs the organization: hires, terminates, launches; never talks to the user" }, + { "id": "REQ-COS-2", "title": "The PM asks the chief of staff for staff; a staff request names the roles and how many of each" }, { "id": "REQ-ASSIST-1", "title": "The assistant is the user's main agent and passes organization work to the chief of staff" }, { "id": "REQ-ASSIST-2", "title": "The broker limits the assistant to the user and the chief of staff in both directions; refusals logged" }, + { "id": "REQ-ASSIST-3", "title": "The assistant tells the user what other roles sent it in its own words and does not relay their text" }, { "id": "REQ-VAR-1", "title": "Variables in four layers, declared in code; limits intersect; unknown keys refused" }, { "id": "REQ-VAR-2", "title": "One system config, never auto-written; secrets only as references the broker reads" }, { "id": "REQ-CRED-1", "title": "Each role instance has its own Gitea and Vikunja token, held by the broker" }, @@ -17,11 +21,22 @@ { "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-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" }, + { "id": "REQ-WAIT-1", "title": "Hard waits always go to the human: spend, delete, irreversible, exposure, accounts, external messages, protected push" }, + { "id": "REQ-WAIT-2", "title": "No role file grants a hard wait; changing the list or granting a listed action is itself a hard wait" }, + { "id": "REQ-WAIT-3", "title": "An action added to the vocabulary is a hard wait until a PRD version says it is not" }, { "id": "REQ-MSG-1", "title": "Messages are addressed to a role, append-only, delivered to the current holder; assistant messages name a thread" }, + { "id": "REQ-MSG-2", "title": "Messages can be addressed by an instance name unique in its business; the message records the name and the instance" }, { "id": "REQ-TASK-1", "title": "Tasks live in Vikunja, each citing a requirement id; the verbs enforce field writers" }, { "id": "REQ-TASK-2", "title": "Polling is the source of truth: a 30-second board poll and an hourly reconcile" }, { "id": "REQ-TASK-3", "title": "The installer points at an existing Vikunja or deploys the unmodified upstream image" }, { "id": "REQ-TASK-4", "title": "The queue keeps the agents' lock, review rounds and audit log; no two-way sync" }, + { "id": "REQ-PROJ-1", "title": "Each project keeps its records in its own local git repository, with no remote and a fixed, validated layout" }, + { "id": "REQ-PROJ-2", "title": "Only the human commits the north-star spec; it counts only when its last commit is by the business human" }, + { "id": "REQ-PROJ-3", "title": "The Console edits the spec and docs Markdown as source with a preview; a stale save is refused" }, + { "id": "REQ-PROJ-4", "title": "Each human spec commit saved in the Console sends one notice to the PM and the CTO for review" }, + { "id": "REQ-LAND-1", "title": "A resolved merge decision lands into the working repository main through the host, only for a granted role" }, { "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" }, diff --git a/packages/tasks/tests/requirements.test.mjs b/packages/tasks/tests/requirements.test.mjs index 472781b45..90409e131 100644 --- a/packages/tasks/tests/requirements.test.mjs +++ b/packages/tasks/tests/requirements.test.mjs @@ -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, 43); + assert.equal(ids.length, 58); 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.4']); + assert.deepEqual([list.prd, list.version], ['docs/prd/mosaic-stack.md', '1.5']); }); 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[43].id: REQ-ROLE-1 twice')); + assert.throws(() => loadRequirements(join(dir, 'twice.json')), listError('requirements[58].id: REQ-ROLE-1 twice')); } finally { rmSync(dir, { recursive: true, force: true }); }