row 285: a chief-of-staff or creative instance that names publish refuses at load, keeping today's N10 refusal; instance-settings :289 follows the companion's gitea (#1790, mos-1332)
The fence sits near business.mjs:166, clear of row 287's :283-291. Its message starts with the N10 text. An assistant-instance test keeps the no-gitea branch covered, and a creative-instance test covers the fence. Nothing here has run.
This commit is contained in:
1 parent
8c529fb4d2
commit
5f81d0da02
5 files changed
+54
-24
No files matched your search
@@ -8,7 +8,7 @@ Base: 94c33a43c on branch `scrooge/row285`.
|
||||
|
||||
- The code, tests, fixtures and docs are written locally. No test has run. Sage's order puts row 252 first at the next CLEAR, and nothing runs during another seat's slot.
|
||||
- The Results section is empty until that run. Nothing below claims a pass.
|
||||
- Three mos-1272 points are open with Mos (scrooge-285-oldtests-mos-1, 18:51Z). See "Old tests" below.
|
||||
- Mos ruled the mos-1272 points in mos-1332 (18:55Z). See "Old tests" below.
|
||||
|
||||
## What changes
|
||||
|
||||
@@ -22,6 +22,7 @@ Base: 94c33a43c on branch `scrooge/row285`.
|
||||
- `vocabulary.mjs` drops CREATIVE_KINDS and adds CREATIVE_ACTIONS (`message.send`, `library.write`) and CREATIVE_SERVICE (`gitea`).
|
||||
- `role.mjs` checkCreative refuses a creative role that holds any withinRole action outside CREATIVE_ACTIONS, any crossRole action, or any credential service other than gitea.
|
||||
- `broker.mjs` #giteaRole (:2138) also refuses the chief of staff with `gitea-not-declared` (sage-2921).
|
||||
- `business.mjs` (near :166, clear of :283-291, which row 287 owns): a chief-of-staff or creative instance that names `publish` refuses at load (mos-1332 item 3).
|
||||
|
||||
## Rulings
|
||||
|
||||
@@ -41,6 +42,9 @@ Base: 94c33a43c on branch `scrooge/row285`.
|
||||
- **mos-1330:**
|
||||
- Item 1: the fixture change gets its own commit. Only fixture data changes, and named tests cover a missing gitea ref.
|
||||
- Item 2: option A is approved. The live chief gets one gitea ref. Every repo business writer gets the ref.
|
||||
- **sage-2937:** if Mos rules (b), business.mjs joins the files owned, scoped to the refusal near :166 and clear of :283-291 (row 287, Megavolt).
|
||||
- **webby-0174:** each changed expected value carries Mos's ruling key. The load fence needs a design line, its own test, a mutant and a grep of the tests for the N10 text.
|
||||
- **mos-1332:** the mos-1272 rulings, items 1-5, cited under "Old tests". The ROUTED commit and the landing still wait on Jason's yes on PRD 1.16 (Q32, Vikunja 546). The build, the gate and Webby's review go ahead.
|
||||
|
||||
## Scopes rule evidence (sage-2915 q2)
|
||||
|
||||
@@ -100,29 +104,34 @@ Data only, with one named exception listed under "Old tests".
|
||||
New named tests (mos-1330 item 1):
|
||||
|
||||
- business.test "row 285: a chief or creative instance without credentials.gitea refuses at load". Each case refuses with the checkCredentialMap "(gitea; got none)" message, and a positive control loads.
|
||||
- business.test "row 285: a creative instance with identity and publish loads".
|
||||
- business.test "row 285: a creative instance with gitea, identity and publish refuses at load" (mos-1332 item 3). Identity alone loads, and publish refuses with the fence message.
|
||||
- agent-identity.test "row 285: an instance whose definition has no gitea refuses publish with the N10 text" (mos-1332 item 3). An assistant instance with identity and publish refuses with the plain N10 message, anchored at the end so the fence message doesn't match. This keeps the "no gitea definition" branch covered.
|
||||
|
||||
## Old tests (mos-1272, open with Mos)
|
||||
## Old tests (mos-1272, ruled in mos-1332)
|
||||
|
||||
Webby (webby-0174) passes each item below only with Mos's explicit mos-1272 ruling key next to it. Each key reads "pending" until Mos rules (asked in scrooge-285-oldtests-mos-1).
|
||||
Webby (webby-0174) passes each item only with Mos's ruling key next to it.
|
||||
|
||||
|
||||
1. **`packages/business/tests/chief-of-staff.test.mjs`** (ruling: pending). Two expected values follow the role file:
|
||||
- APPROVED.credentials (:24) is now `[{service: "gitea", scopes: ["read:repository", "read:user"]}]`.
|
||||
- The resolved-record test (:90) expects `{gitea: {service: "gitea", file: <root>/secrets/chief-of-staff-gitea.token, rotateBy: FAR_DATE}}` where it expected `{}`.
|
||||
- :155 was "the instance takes no credential references and no tracker", expecting "(none; got gitea)". It is now "the instance takes only the gitea credential reference and no tracker", adding a vikunja ref and expecting "(gitea; got gitea, vikunja)". The tracker refusal is unchanged.
|
||||
2. **`packages/business/tests/agent-identity.test.mjs:49-50` (N10)** (ruling: pending) is expected red. A chief with identity and publish now loads, because its definition declares gitea. Options sent to Mos:
|
||||
- (a) Switch the case to an instance whose definition has no gitea.
|
||||
- (b), recommended: business.mjs:166 also refuses publish for a chief-of-staff definition, and the test stays unchanged.
|
||||
- Sage (sage-2937) put business.mjs in 285's files owned, scoped to this refusal near :166 and kept out of :283-291, which row 287 (Megavolt) owns.
|
||||
- Webby (webby-0174) treats it as a product change. It needs a design line, its own test, a grep of packages/*/tests for the old N10 text, a mutant, and a BUILD.md line citing Mos's ruling.
|
||||
- Design line, if Mos rules (b): a chief-of-staff instance that names `publish` refuses at load with the N10 message. Its gitea is a read grant only (sage-2915), so it never publishes. This fences the same case #giteaRole refuses at raise, one step earlier.
|
||||
3. **`packages/business/tests/instance-settings.test.mjs:289`** (ruling: pending) is expected red. Old: `{ services: [], accepted: true }`. New: `{ services: ["gitea"], accepted: true }`. In short, `view.definitions.companion` becomes `{services: ["gitea"], accepted: true}`. The listing at :298 is checked at the run.
|
||||
1. **`packages/business/tests/chief-of-staff.test.mjs`** (mos-1332 item 1, accepted as pushed). Expected values follow the role file:
|
||||
- APPROVED.credentials (:24). Old: `[]`. New: `[{service: "gitea", scopes: ["read:repository", "read:user"]}]`.
|
||||
- The resolved-record test (:90). Old: `{}`. New: `{gitea: {service: "gitea", file: <root>/secrets/chief-of-staff-gitea.token, rotateBy: FAR_DATE}}`.
|
||||
- :155. Old name: "the instance takes no credential references and no tracker", expecting "(none; got gitea)". New name: "the instance takes only the gitea credential reference and no tracker", adding a vikunja ref and expecting "(gitea; got gitea, vikunja)". The tracker refusal is unchanged.
|
||||
2. **`packages/business/tests/role.test.mjs`** (mos-1332 item 2, accepted).
|
||||
- The six-creative-roles load test now pins withinRole `[message.send, library.write]` and credentials `[{gitea, [read:user, write:repository]}]` exactly. Old: `[message.send]` and `[]`.
|
||||
- The M1 block checked record.write and one crossRole case. It now loops over every routed action outside CREATIVE_ACTIONS, keeps the crossRole refusal, and adds the vikunja and host credential refusals. The refusal text changes from "may hold only withinRole message.send" to "may hold only withinRole message.send and library.write".
|
||||
3. **`packages/business/tests/agent-identity.test.mjs:49-50` (N10)** (mos-1332 item 3, option (b) widened to the creative definitions). N10 is unchanged.
|
||||
- Fence in business.mjs near :166: a chief-of-staff or CREATIVE_DEFINITIONS instance with `publish` refuses with `<at>.publish needs identity and a gitea definition (<definition> never publishes)`.
|
||||
- Wording: the message starts with the N10 text, so the :50 regex still matches, and the reason follows in parentheses.
|
||||
- Design line: on refactor today, a chief or creative instance with identity and publish refuses at load because neither definition declares gitea. After 285 both declare gitea for the library alone, so the fence keeps today's refusal and adds no new policy. #giteaRole refuses both at raise (mos-1163 for the creative ones, sage-2921 for the chief).
|
||||
- Grep of `packages/*/tests/*` for "needs identity and a gitea definition": only agent-identity.test :47, :48 and :50, plus the two new tests. No other reader.
|
||||
- New tests: see the named tests above. Mutants M7-M9 below.
|
||||
4. **`packages/business/tests/instance-settings.test.mjs:289`** (mos-1332 item 4, accepted). Old: `{ services: [], accepted: true }`. New: `{ services: ["gitea"], accepted: true }`. If the :298 listing changes at the run, the exact new value goes here and Webby hears about it. Anything that removes or weakens a check goes back to Mos.
|
||||
5. **Other fixture edits** (mos-1332 item 5): data only, no ruling needed.
|
||||
|
||||
## Commit plan
|
||||
|
||||
1. Role files, contracts, vocabulary, role.mjs, broker #giteaRole, gitea-grant.test and role.test, plus this file.
|
||||
2. The fixture commit (mos-1330): helpers.mjs, chief-of-staff.test, business.test (fixture refs and the two new named tests), the loader fixtures above, the example json and README. It doesn't land until Mos rules the old-test points.
|
||||
2a. The mos-1332 commit: the business.mjs publish fence, its two tests, instance-settings.test:289 and this file.
|
||||
2. The fixture commit (mos-1330): helpers.mjs, chief-of-staff.test, business.test (fixture refs and the two new named tests), the loader fixtures above, the example json and README. Mos ruled the old-test points in mos-1332.
|
||||
3. The 1.16 commit: `library.write` in ACTIONS and ROUTED in both `business/src/vocabulary.mjs` and `bus/src/broker.mjs`, citing the PRD 1.16 paragraph (row #1796), with a hard-waits test that it is routed. It's held until Jason's yes and 1.16 lands.
|
||||
|
||||
Until commit 3, every creative role file refuses at load (REQ-WAIT-2: a GATED_ONLY action in a role file). The branch is green only with all three commits.
|
||||
@@ -139,6 +148,9 @@ Kill rules are written before the runs. Each mutant is one edit, then a restore,
|
||||
| M4 | drop the crossRole check | role.mjs checkCreative | role.test M1 crossRole refusals |
|
||||
| M5 | creative role file without library.write | roles/companion.json | role.test creative-load test |
|
||||
| M6 | chief scopes widened with write:repository | roles/chief-of-staff.json | chief-of-staff.test "the shipped file is exactly the approved list" |
|
||||
| M7 | drop `entry.definition === "chief-of-staff"` from the publish fence | business.mjs | agent-identity.test N10 :50 (the chief then loads) |
|
||||
| M8 | drop `CREATIVE_DEFINITIONS.includes(entry.definition)` from the fence | business.mjs | business.test "row 285: a creative instance with gitea, identity and publish refuses at load" |
|
||||
| M9 | drop `\|\| !services.includes("gitea")` from the N10 check | business.mjs | agent-identity.test "row 285: an instance whose definition has no gitea refuses publish with the N10 text" |
|
||||
|
||||
## Manifest
|
||||
|
||||
@@ -146,6 +158,7 @@ Source and roles:
|
||||
- packages/business/src/vocabulary.mjs
|
||||
- packages/business/src/role.mjs
|
||||
- packages/bus/src/broker.mjs (#giteaRole only, sage-2921)
|
||||
- packages/business/src/business.mjs (the publish fence near :166 only, sage-2937, mos-1332 item 3)
|
||||
- roles/{companion,ideas,research,proofreader,fact-checker,continuity}.{json,md}
|
||||
- roles/chief-of-staff.{json,md}
|
||||
|
||||
@@ -161,7 +174,7 @@ Tests:
|
||||
- packages/business/tests/resolve.test.mjs
|
||||
- packages/bus/tests/creative.test.mjs
|
||||
- packages/cli/tests/launcher.test.mjs
|
||||
- packages/business/tests/agent-identity.test.mjs, only if Mos takes (a)
|
||||
- packages/business/tests/agent-identity.test.mjs (one test appended, mos-1332 item 3)
|
||||
|
||||
Docs:
|
||||
- packages/business/examples/mosaic-stack.example.json
|
||||
|
||||
@@ -162,6 +162,12 @@ function checkRoles(roles, file, rolesDir, business) {
|
||||
// names are checked against projects once those are read.
|
||||
if (entry.identity !== undefined) out[instance].identity = checkIdentity(entry.identity, `${at}.identity`);
|
||||
if (entry.publish !== undefined) {
|
||||
// Row 285 (#1790, mos-1332 item 3): the chief of staff and the creative roles declare gitea for
|
||||
// the library alone, so publish refuses at load as it did before they declared it. #giteaRole
|
||||
// refuses both at raise (mos-1163, sage-2921).
|
||||
if (CREATIVE_DEFINITIONS.includes(entry.definition) || entry.definition === "chief-of-staff") {
|
||||
refuse(`${at}.publish needs identity and a gitea definition (${entry.definition} never publishes)`);
|
||||
}
|
||||
// N10: one message for both, naming the grant.
|
||||
if (!out[instance].identity || !services.includes("gitea")) refuse(`${at}.publish needs identity and a gitea definition`);
|
||||
out[instance].publish = requireDistinctList(entry.publish, `${at}.publish`, (p) => requireId(p, `${at}.publish entry`), { nonEmpty: true });
|
||||
|
||||
@@ -50,6 +50,13 @@ test("N10: publish needs identity and a gitea definition, and the error names th
|
||||
/roles\.chief\.publish needs identity and a gitea definition/);
|
||||
});
|
||||
|
||||
// Row 285 (mos-1332 item 3): the chief now declares gitea and refuses at the row 285 fence, so this
|
||||
// case is the one that reaches N10's "no gitea definition" branch.
|
||||
test("row 285: an instance whose definition has no gitea refuses publish with the N10 text", () => {
|
||||
refuses(() => check((d) => { d.roles.helper = { definition: "assistant", holder: "mos", identity: structuredClone(IDENTITY), publish: ["stack"] }; }),
|
||||
/roles\.helper\.publish needs identity and a gitea definition$/);
|
||||
});
|
||||
|
||||
test("publish names declared projects that have a remote, each once", () => {
|
||||
refuses(() => check((d) => { d.roles.coder.publish = ["books"]; }), /publish names books, which the business file doesn't declare/);
|
||||
refuses(() => check((d) => { delete d.projects.stack.remote; }), /publish names stack, which has no "remote"/);
|
||||
|
||||
@@ -310,14 +310,17 @@ test("row 285: a chief or creative instance without credentials.gitea refuses at
|
||||
|
||||
// Row 285 (C2-08b, brief): a creative instance may carry identity and publish, under the rules at
|
||||
// business.mjs:155-166, which the grant path reads. The grant itself still refuses it (#giteaRole).
|
||||
test("row 285: a creative instance with identity and publish loads", () => {
|
||||
// Row 285 (mos-1332 item 3): a creative instance holds gitea and may hold an identity, but publish
|
||||
// still refuses at load with the N10 text, as before its definition declared gitea.
|
||||
test("row 285: a creative instance with gitea, identity and publish refuses at load", () => {
|
||||
const identity = { name: "Bean", email: "[email protected]", gitea: { url: "https://git.example", user: "acme-bean" } };
|
||||
const business = check((d) => {
|
||||
const bean = (extra) => (d) => {
|
||||
d.projects.stack.remote = "https://git.example/acme/stack";
|
||||
d.roles.bean = { definition: "companion", credentials: CREATIVE_GITEA, identity, publish: ["stack"] };
|
||||
});
|
||||
d.roles.bean = { definition: "companion", credentials: CREATIVE_GITEA, identity, ...extra };
|
||||
};
|
||||
const business = check(bean({}));
|
||||
assert.deepEqual({ ...business.roles.bean.identity, gitea: { ...business.roles.bean.identity.gitea } }, identity);
|
||||
assert.deepEqual([...business.roles.bean.publish], ["stack"]);
|
||||
refuses(() => check(bean({ publish: ["stack"] })), /roles\.bean\.publish needs identity and a gitea definition \(companion never publishes\)/);
|
||||
});
|
||||
|
||||
// Row 194 (#1692, D2.5, T17): the per-agent forbid and the retired list.
|
||||
|
||||
@@ -286,7 +286,8 @@ test("row 213 a creative instance is the human's: add, vars and definition chang
|
||||
writeFileSync(join(f.root, "config", "personas", "acme", "bean.md"), text, { mode: 0o600 });
|
||||
const persona = { "persona.name": "Bean", "persona.sha256": createHash("sha256").update(text).digest("hex") };
|
||||
const view = f.settings.read("acme");
|
||||
assert.deepEqual(view.definitions.companion, { services: [], accepted: true });
|
||||
// Row 285 (mos-1332 item 4): the companion definition declares gitea.
|
||||
assert.deepEqual(view.definitions.companion, { services: ["gitea"], accepted: true });
|
||||
const add = { instance: "bean", op: "add", definition: "companion", vars: persona };
|
||||
for (const actor of ["chief-of-staff.chief", "tester"]) {
|
||||
assert.throws(() => f.settings.set("acme", { revision: view.revision, ...add }, actor), e => e.code === "organization-creative-human-only", actor);
|
||||
|
||||
Reference in new issue
Block a user