honker: PRD 1.7 and 1.8 (sage-1637, mos-1154, DECISIONS Q192): 1.7 from PRD-1.7-DRAFT.md sha256 e896746d (decision d52febb5), 1.8 from r7 82df17347 sha256 de079281; status approved, version 1.8; requirements.json 1.8 with 10 new ids (68); tasks and bus pins
This commit is contained in:
+265
-2
@@ -1,6 +1,6 @@
|
||||
# PRD: Mosaic Stack
|
||||
|
||||
- Status: approved, version 1.6. Jason approved draft 0.4 unchanged as
|
||||
- Status: approved, version 1.8. 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
|
||||
@@ -15,7 +15,64 @@
|
||||
confirmation of the text is the approval, so there is no in-Stack
|
||||
prd.approve for it. Version 1.6 records Jason's ruling Q169 of
|
||||
2026-10-16, on who removes and who configures the assistant. It is
|
||||
never edited in place. Changes are a new version.
|
||||
never edited in place. Changes are a new version. Version 1.7 routes the
|
||||
chief of staff's hire and fire actions and the coder's push to its own
|
||||
fork, and adds agent host access through the credential store, approved
|
||||
by Jason in decision d52febb5 (prd.approve, yes). Version 1.8 records
|
||||
Jason's ruling Q188 of 2026-10-20: trusted actions within role
|
||||
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.
|
||||
- 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."
|
||||
- Version 1.8 source, Jason's ruling Q188 (DECISIONS, 2026-10-20), his
|
||||
answers to Q8 and Q10, in part. Q8: "I would rather grant the grant
|
||||
right to an agent that runs with strict guardrails. That agent presents
|
||||
the final authorization for the user. Upon approval, the grant is
|
||||
created programmatically. I see this as: User configures their PATs, API
|
||||
tokens, authorizations within the WebUI. The agent presents the request
|
||||
for grant with X rights for another agent. The user reviews, then clicks
|
||||
Approve/Deny. Click of Approve fires off protected mechanical methods to
|
||||
handle the grants on Github, Gitea, .... services as needed. The tooling
|
||||
would need to exist and must be guarded." And "Disallowing the agents to
|
||||
create grants autonomously is a necessary evil for better security.
|
||||
Requiring the user to manually perform the steps is a no-fly." Q10:
|
||||
"Agents should have tools and command access based on roles. Those roles
|
||||
dictate the allowed tools and commands. The use of a tool or command
|
||||
should not be raised to the user unless the system is configured with a
|
||||
manual mode that requires user interaction. By default I want to have
|
||||
the agents capable of running commands and tools at will within their
|
||||
sandbox/guardrails. This allows autonomous actions by agents within
|
||||
their lanes. Perhaps a "Trusted actions within approved guardrails"
|
||||
methodology." And "The main agent or chief of staff would be responsible
|
||||
for surfacing the request to the user's inbox for approval. Not all
|
||||
agents are capable or authorized to request directly. It must follow the
|
||||
chain of command properly." He agreed with Mos's Q10 points 3 to 6:
|
||||
protected stack code does every step on Approve, his tokens are entered
|
||||
in the WebUI and agents never see them, a command on the approved list
|
||||
runs without a click and any other is refused, and he, Mos or the tester
|
||||
can revoke a grant at once.
|
||||
- Version 1.8 source, Jason's ruling Q190 (DECISIONS, 2026-10-20), his
|
||||
answer "Q12: O1": each agent seat gets its own account on his Gitea,
|
||||
created through the Q188 approval path once the Gitea grants exist.
|
||||
- Version 1.8 source, Jason's ruling Q191 (DECISIONS, through Mos in
|
||||
mos-1149), that the assistant and the chief of staff are separate roles,
|
||||
and only the chief raises a grant request: "Q13: that looks better".
|
||||
- Version 1.7 source, TARGET.md line 66: "Chief of staff agent has
|
||||
hire/fire authority for agents as needed; unless user forbids per
|
||||
agent". And Jason through Mos (mos-1067), DECISIONS Q183, in part: "I
|
||||
will still want to allow infra agent(s) on my .53 instance to access
|
||||
other servers, etc. However, not all agents will need to have that
|
||||
access. I envision a credential store within Mosaic Stack that works as
|
||||
some sort of variable for the agent to call. The system will enforce
|
||||
access to the credentials to keep the agents sandboxed with proper
|
||||
security. I need to be able to trust my agents with assisting me. This
|
||||
will require sudo access to several systems. If we can utilize the
|
||||
credential store in Mosaic Stack and allow agents to perform their jobs
|
||||
with NOPASSWD sudo on various machines, I am a happy man." DECISIONS
|
||||
Q184, on whether that is in place by 10-27: "Q5: by 10.27"
|
||||
- Version 1.6 source, Jason's ruling Q169 (DECISIONS, brain repo,
|
||||
2026-10-16): "The only agent that should be able to remove the
|
||||
assistant role is the chief of staff. The COS and the user should have
|
||||
@@ -262,6 +319,39 @@ Added in version 1.2:
|
||||
in its own words. It summarizes and doesn't relay their text. (Version
|
||||
1.5.)
|
||||
|
||||
Added in version 1.7:
|
||||
|
||||
- **REQ-COS-3.** The chief of staff hires and fires role instances without
|
||||
a decision each time. Hiring adds a role instance to the organization
|
||||
file and lists it for launch. Firing ends the instance's runs and
|
||||
removes it from the launch list. It stays in the organization file. Only
|
||||
the user deletes an instance. These actions are `role.hire` and
|
||||
`role.fire`. They leave the hard waits and route under this requirement,
|
||||
within these bounds:
|
||||
- The chief acts only in its own organization.
|
||||
- The chief hires only role definitions that need no credentials, until
|
||||
a later version adds credentialed roles.
|
||||
- The chief hires only the role kinds its role file lists. Changing that
|
||||
list is a reviewed commit.
|
||||
- The chief hires only a role whose every action is on a fixed list of
|
||||
plain work actions: sending messages, writing records, asking for
|
||||
review, updating its assigned tasks, and the scope and working-push
|
||||
actions of an assigned task. A role holding any other action, such as
|
||||
launch, end, organization, naming, hire, review verdict or merge
|
||||
authority, or any action added later, is never hired. So the chief
|
||||
never hires a chief, never picks its own reviewers or merge gate, and
|
||||
the author is never the reviewer. This holds whatever the role file's
|
||||
list says. Adding to that list is a PRD change.
|
||||
- The chief may set a hired instance's model and narrow its limits, and
|
||||
nothing else about it.
|
||||
- The user can forbid per agent. The user marks an instance so the chief
|
||||
can't fire it, end its runs or change its model, and marks role kinds
|
||||
the chief can't hire. Only the user changes these marks, through the
|
||||
WebUI or the CLI.
|
||||
- The kill switch stops every hire and fire while it is on.
|
||||
- Every hire and fire is logged with the chief's instance, its run and
|
||||
the reason.
|
||||
|
||||
### Variables
|
||||
|
||||
- **REQ-VAR-1.** Variables come in four layers: system, business, project
|
||||
@@ -289,8 +379,111 @@ Added in version 1.2:
|
||||
- in Vikunja, a `bot-<business>-<role>` user per role, plus one
|
||||
read-only `bot-<business>-sync` that does all polling (lead
|
||||
decisions 52 and 58).
|
||||
|
||||
Since version 1.8, a token or key for a grant is made by the grant code
|
||||
on the user's Approve (REQ-GRANT-2), not by hand. Tokens that exist stay
|
||||
as they are.
|
||||
- **REQ-CRED-2.** A session that finds only founder credentials stops.
|
||||
|
||||
Added in version 1.7:
|
||||
|
||||
- **REQ-CRED-3.** An agent with a grant can run commands with sudo on
|
||||
another host. The agent asks for the host credential by name. The stack
|
||||
checks that a grant exists for that agent and that host before the
|
||||
credential is used. The agent never sees the key or any other secret
|
||||
value (REQ-CRED-1, REQ-VAR-2). An agent without a grant for that host is
|
||||
refused. Not every agent gets a grant. Who grants a host credential, and
|
||||
how, is set by the #424 design, which Jason approves.
|
||||
|
||||
Added in version 1.8 (Q188):
|
||||
|
||||
- **REQ-CRED-4.** An action a role definition lists within-role, and that
|
||||
uses a grant, runs without a decision for each use only when all of
|
||||
these hold:
|
||||
- the definition declares the credential kind the action uses;
|
||||
- a grant names that agent, and that host or service;
|
||||
- for a command, the command matches the grant's allowlist. A grant
|
||||
lists exact argv prefixes. A wildcard grant is refused;
|
||||
- the agent's key or token for that grant is issued and not revoked.
|
||||
|
||||
A command off the allowlist is refused, and adding one takes a new grant
|
||||
request (REQ-GRANT-1). An action whose definition doesn't list it
|
||||
within-role still needs a decision for each use. Only a reviewed role
|
||||
change adds an action to a definition. `host.sudo` routes under this
|
||||
requirement.
|
||||
- **REQ-GRANT-1.** No agent creates or writes a grant. A grant request
|
||||
follows the chain of command, and only the chief of staff raises it to
|
||||
the user's inbox. Any other role that needs a grant for itself or for an
|
||||
agent it directs asks the chief of staff, through its chain: a worker
|
||||
role through its PM, the PM and the CTO directly. The assistant passes
|
||||
the user's own request to the chief of staff (REQ-ASSIST-1). The request
|
||||
names the agent, the grant method and its target, the exact rights, and
|
||||
a rotate-by or expiry date. The chief raises one only for an agent whose
|
||||
reviewed role definition allows that kind of credential, and the broker
|
||||
refuses any other. A grant can't name a wildcard, a shell or an empty
|
||||
command. The request is a decision with the action `credential.mint`, so
|
||||
it goes to the user as a hard wait (REQ-WAIT-1). A grant whose method
|
||||
makes an account, such as a seat's own Gitea user (Q190), is the same
|
||||
one decision: the method in the grant says it makes an account, the
|
||||
request names the account, and the inbox shows the account name before
|
||||
Approve. The user's one resolution covers the account and its
|
||||
credential, so the hard-waits list doesn't change. An `account.create`
|
||||
raise isn't a grant request and routes as version 1.7 has it. The broker
|
||||
checks only that the chief of staff raised the request. The chain of
|
||||
command before that is in the messaging lists and the role contracts,
|
||||
not a broker check. The assistant and the chief of staff are separate
|
||||
roles. No agent holds both, and the broker refuses a claim that would.
|
||||
- **REQ-GRANT-2.** The user approves or denies each grant request in the
|
||||
inbox. Approve is the only thing that creates a grant, and the code uses
|
||||
a grant only when it has a matching Approve record. No agent creates a
|
||||
grant. A grant written into the business file by hand makes nothing. Row
|
||||
210's hand-written grants stay a test path until Vikunja #436a moves
|
||||
`host.run` to grants made by Approve. On Approve, protected stack code
|
||||
does every step, not an agent and not the user: it records the grant,
|
||||
makes the key or token, installs it on the machine or creates it on the
|
||||
service, and logs each step. On Deny nothing is made, and the denial is
|
||||
logged. The grant methods are:
|
||||
- machine key: a key for one agent on one enrolled host, with the
|
||||
command allowlist of REQ-CRED-4. A host's identity comes from the host
|
||||
side when the user approves its enrollment, never from a first
|
||||
connection. A host user with sudo receives a grant only after the user
|
||||
approved that user by name;
|
||||
- Gitea: a token for one agent, and for an agent seat its own Gitea user
|
||||
(Q190), with an expiry. The all scope and the admin scope are never
|
||||
granted;
|
||||
- GitHub: a grant for one agent.
|
||||
|
||||
The Gitea and GitHub rights units come in a later design that Jason
|
||||
approves.
|
||||
|
||||
The approval binds the exact rights the user saw and the target or its
|
||||
enrolled identity. A change to the agent, its definition, the target,
|
||||
the target's identity or the rights after the raise voids it. An
|
||||
approval is used once. A grant the code couldn't finish is undone at
|
||||
once on the stack's side, so it is never used. What it left on the host
|
||||
or service stays visible as pending until it is removed, as for a revoke
|
||||
(REQ-GRANT-4). A new grant needs a new approval, never an automatic
|
||||
retry. The grant code runs only on a request the user resolved. A
|
||||
request resolved by an arbiter, the tester or any agent makes nothing. A
|
||||
`credential.mint` decision raised before version 1.8, or without the
|
||||
fields of REQ-GRANT-1, makes nothing when it is approved. Until the
|
||||
Console knows the signed-in human (Vikunja #412), Approve is
|
||||
`mosaic decide` in the CLI (REQ-DEC-3).
|
||||
- **REQ-GRANT-3.** The user enters their own personal access tokens and
|
||||
API tokens in the WebUI, or the CLI. Only the grant code reads them, to
|
||||
make grants. No agent ever sees a token value or a key's private half.
|
||||
Values appear in no event, log, message, prompt or agent file, and no
|
||||
agent can read them back (REQ-VAR-2). Until the Console knows the
|
||||
signed-in human, they are entered through the CLI.
|
||||
- **REQ-GRANT-4.** A grant can be revoked at once by the user, by the
|
||||
assistant for a grant in its own organization, or by the tester on a dev
|
||||
instance (Q173). A revoke needs no decision and no new trust. It takes
|
||||
effect at once on the stack's side, without waiting on the network, so
|
||||
the next use is refused. Removing the key or token at the host or
|
||||
service follows. Until that removal is done it stays visible as pending.
|
||||
A revoke while the grant is being made stops it, and nothing it made
|
||||
stays usable. Every revoke is logged with who made it.
|
||||
|
||||
### Decisions
|
||||
|
||||
- **REQ-DEC-1.** Every decision is a record in an append-only SQLite
|
||||
@@ -338,6 +531,31 @@ Added in version 1.5 (Q167):
|
||||
settled under one commit stays settled when a later commit lands, and
|
||||
new raises cite the new commit.
|
||||
|
||||
### Trusted actions
|
||||
|
||||
Added in version 1.8 (Q188).
|
||||
|
||||
- **REQ-TRUST-1.** Agents act within their role guardrails without asking.
|
||||
The default mode is "trusted actions within approved guardrails". An
|
||||
action a role file grants within-role is done at will, inside the
|
||||
agent's sandbox, its tool limit and its grants, and is logged. It raises
|
||||
nothing to the user. An action the file doesn't grant within-role still
|
||||
routes by REQ-DEC-2, and a hard wait still goes to the user
|
||||
(REQ-WAIT-1). Only a reviewed role change adds an action to a role file,
|
||||
and REQ-WAIT-2 still keeps every hard wait out of every role file.
|
||||
- **REQ-TRUST-2.** The user can put chosen actions in manual mode. The
|
||||
organization file holds the list of actions in manual mode, empty by
|
||||
default. While an action is on the list, every use of it by any role
|
||||
becomes a decision for that use, raised to the user, and the action
|
||||
waits until the user resolves it. A decision denied, or not resolved,
|
||||
refuses the action. Each decision is used once. For a command on another
|
||||
host, the decision names the host, the command and its input. Actions
|
||||
not on the list are unchanged. Only the user changes the list, through
|
||||
the WebUI or the CLI. The chief of staff's organization writes
|
||||
(REQ-ROLE-3) can't change it, and no agent can. Every change is logged
|
||||
with who made it. A change applies to the next use, and a run already in
|
||||
progress keeps no exemption.
|
||||
|
||||
### Hard waits
|
||||
|
||||
Added in version 1.5 (Q167).
|
||||
@@ -371,6 +589,13 @@ Added in version 1.5 (Q167).
|
||||
PRD version says it isn't. The reviewed commit that adds it names which
|
||||
it is.
|
||||
|
||||
`role.hire` and `role.fire` were added as hard waits and route under
|
||||
REQ-COS-3 since version 1.7. `git.push.remote` was added as a hard wait
|
||||
and routes under REQ-LAND-2 since version 1.7.
|
||||
|
||||
`host.sudo` was added as a hard wait and routes under REQ-CRED-4 since
|
||||
version 1.8.
|
||||
|
||||
### Messages
|
||||
|
||||
- **REQ-MSG-1.** Messages are addressed to a role. They are append-only
|
||||
@@ -470,6 +695,37 @@ Added in version 1.5 (Q167, Mos's reading Q4).
|
||||
decision; the check ships with whichever of rows 137 and 139 lands
|
||||
second.
|
||||
|
||||
Added in version 1.7:
|
||||
|
||||
- **REQ-LAND-2.** A coder pushes its own work to its own fork. The action
|
||||
is `git.push.remote`.
|
||||
- What it pushes: one commit, by its oid, never a ref name. That commit
|
||||
is the latest work commit the bus recorded for the coder's task, and
|
||||
the coder made that push. A decision that authorizes a push names that
|
||||
commit, and it doesn't authorize any other.
|
||||
- Where it lands: only the branch
|
||||
`refs/heads/<its Gitea user>/<branch>`. The host builds that name, the
|
||||
agent never does. A push never forces.
|
||||
- Which remote: the agent's own fork of the project's upstream. The
|
||||
business file names the upstream, and the host never contacts it. For
|
||||
each push the host builds the fork's address over https from the
|
||||
upstream's host, port and repository name and the agent's own Gitea
|
||||
user. The history check, the push and the credential match all use
|
||||
that address. So the agent's own user owns the receiving repository on
|
||||
every push, and the agent never names it.
|
||||
- The host refuses an upstream on a host or port other than the agent's
|
||||
Gitea, and an upstream the agent's own user owns. It refuses a fork
|
||||
that is missing, empty or doesn't share the project's history. Gitea's
|
||||
push-to-create stays off, so a push never creates a repository.
|
||||
- Who may: the action routes under REQ-DEC-2 and is granted within-role
|
||||
to the coder role only. No other role file grants it.
|
||||
- Before version 1.7 the action was a hard wait under REQ-WAIT-3, so
|
||||
each push needed a decision the human resolved, and that decision
|
||||
named the commit.
|
||||
|
||||
Every push is logged with the remote, the ref, the commit and, when one
|
||||
was given, the decision.
|
||||
|
||||
### Interface
|
||||
|
||||
- **REQ-CLI-1.** `mosaic` is the front door. From it Jason can:
|
||||
@@ -925,6 +1181,13 @@ only hard waits in his inbox.
|
||||
file only picks among modules already in the tree. The reviewed commit
|
||||
that adds a module is the only check on what it does, which is why
|
||||
modules from outside the repository wait for Jason (REQ-PLUG-1).
|
||||
- Trusted mode lets an agent run its allowed commands at will. On another
|
||||
host, an allowed command that writes a file as root or starts a shell
|
||||
can plant a key, and the seat sandbox doesn't confine the network, so
|
||||
root can outlive the grant and a revoke. The allowlist narrows this. A
|
||||
seat sandbox with its own network namespace closes it. Until then the
|
||||
host's own audit log is the check after the fact (row 210 design section
|
||||
6).
|
||||
|
||||
## Milestones
|
||||
|
||||
|
||||
@@ -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, 58);
|
||||
assert.equal(list.requirements.length, 68);
|
||||
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.6",
|
||||
"version": "1.8",
|
||||
"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" },
|
||||
@@ -13,16 +13,25 @@
|
||||
{ "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-COS-3", "title": "The chief of staff hires and fires role instances without a decision, within fixed bounds; the user forbids per agent" },
|
||||
{ "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" },
|
||||
{ "id": "REQ-CRED-2", "title": "A session that finds only founder credentials stops" },
|
||||
{ "id": "REQ-CRED-3", "title": "An agent with a grant runs sudo commands on another host through the credential store and never sees the secret" },
|
||||
{ "id": "REQ-CRED-4", "title": "A within-role grant action needs no decision only with its kind declared, a grant, an allowlisted command and a live key" },
|
||||
{ "id": "REQ-GRANT-1", "title": "No agent creates a grant; only the chief of staff raises a grant request, as a credential.mint hard wait" },
|
||||
{ "id": "REQ-GRANT-2", "title": "Only the user's Approve creates a grant; protected stack code does every step, bound to the exact rights" },
|
||||
{ "id": "REQ-GRANT-3", "title": "The user enters their own tokens in the WebUI or the CLI; only the grant code reads them and no agent sees a value" },
|
||||
{ "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-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-TRUST-1", "title": "Agents act within their role guardrails without asking; a within-role action is done at will and logged" },
|
||||
{ "id": "REQ-TRUST-2", "title": "The user puts chosen actions in manual mode, so each use becomes a decision the user resolves" },
|
||||
{ "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" },
|
||||
@@ -37,6 +46,7 @@
|
||||
{ "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-LAND-2", "title": "A coder pushes one recorded work commit by oid to its own fork, on a host-built branch, never forced" },
|
||||
{ "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" },
|
||||
|
||||
@@ -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, 58);
|
||||
assert.equal(ids.length, 68);
|
||||
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.6']);
|
||||
assert.deepEqual([list.prd, list.version], ['docs/prd/mosaic-stack.md', '1.8']);
|
||||
});
|
||||
|
||||
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[58].id: REQ-ROLE-1 twice'));
|
||||
assert.throws(() => loadRequirements(join(dir, 'twice.json')), listError('requirements[68].id: REQ-ROLE-1 twice'));
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user