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
|
# 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
|
1.0 on 2026-10-05 (lead decision 61). They approved version 1.1, the
|
||||||
Organization requirements, in decision 03130d08-ddce-480d-a601-e59f64744fc3
|
Organization requirements, in decision 03130d08-ddce-480d-a601-e59f64744fc3
|
||||||
on 2026-10-14. They approved version 1.2, the chief of staff, the
|
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
|
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
|
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
|
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
|
- 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
|
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
|
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. (Version 1.11; Q179, Q180, Q211. The 1.10 text ended "This is
|
||||||
post-v1.")
|
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
|
### Installer
|
||||||
|
|
||||||
Added in version 1.4 (decision 1ea053cc).
|
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).
|
- 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
|
REQ-INST-2 moves into v1 if Jason picks the bundled Pocket ID for
|
||||||
either instance.
|
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
|
## Risks and open questions
|
||||||
|
|
||||||
- In slice 1, agents run as Jason's OS user (round 3, 3A). They can
|
- On each v1 instance, agents run as that instance's OS user, without
|
||||||
write anything that user can write. Until seats run in a container,
|
sudo (Q181). They can write anything that user can write. Until seats
|
||||||
which comes next, the broker is a rule they follow, not a wall. What
|
run in a container, which comes after v1, the broker is a rule they
|
||||||
does hold in slice 1 is that agents never hold service tokens.
|
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
|
- Vikunja doesn't enforce `If-Match`. The broker compares before it
|
||||||
writes, and a person editing in the same moment can still be
|
writes, and a person editing in the same moment can still be
|
||||||
overwritten in an owned field (lead decision 51).
|
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 pm = agent('pm');
|
||||||
const list = call(b, pm, 'requirements');
|
const list = call(b, pm, 'requirements');
|
||||||
assert.deepEqual(list, loadRequirements());
|
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.deepEqual(call(b, agent('coder'), 'requirements'), list);
|
||||||
assert.throws(() => call(b, human, 'requirements'), /agent-required/);
|
assert.throws(() => call(b, human, 'requirements'), /agent-required/);
|
||||||
assert.throws(() => call(b, reader, 'requirements'), /read-only/);
|
assert.throws(() => call(b, reader, 'requirements'), /read-only/);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"prd": "docs/prd/mosaic-stack.md",
|
"prd": "docs/prd/mosaic-stack.md",
|
||||||
"version": "1.11",
|
"version": "1.12",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
{ "id": "REQ-ROLE-1", "title": "Each role is a reviewed roles/<name>.json: contract, authority map, credentials" },
|
{ "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 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-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-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-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-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-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-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-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-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-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-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-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" }
|
{ "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]);
|
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.
|
// 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, [...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.deepEqual(list.requirements.map((r) => r.id), ids);
|
||||||
assert.match(prd, new RegExp(`^- Status: approved, version ${list.version.replace('.', '\\.')}\\.`, 'm'));
|
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', () => {
|
test('the committed list loads frozen', () => {
|
||||||
@@ -74,7 +74,7 @@ test('the schema refuses any other shape', () => {
|
|||||||
const twice = raw();
|
const twice = raw();
|
||||||
twice.requirements.push(structuredClone(twice.requirements[0]));
|
twice.requirements.push(structuredClone(twice.requirements[0]));
|
||||||
writeFileSync(join(dir, 'twice.json'), JSON.stringify(twice));
|
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 {
|
} finally {
|
||||||
rmSync(dir, { recursive: true, force: true });
|
rmSync(dir, { recursive: true, force: true });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user