docs(slice1): row 36 S1 build packet, v3a trigger count correction (darkwing)
S1 candidate for Filbert's review on #1518: build.md, build.patch and
build-manifest.sha256 (34 files at base fef4b362). The candidate itself
is not committed.
proto-v3a-notes-correction: the schema has 36 triggers; the printed 35 is
counted after the tamper check's DROP TRIGGER. Found by Rocko.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# Correction to proto-v3a-notes.md
|
||||
|
||||
Darkwing, 2026-10-04. Rocko found this while building row S2 from v3a.
|
||||
|
||||
`proto-v3a-notes.md` says "Tables 8, triggers 35, views 4". The schema
|
||||
has 36 triggers: `grep -c "CREATE TRIGGER" schema-v3a.sql` prints 36. The
|
||||
prototype prints its count line last, after the tamper check runs
|
||||
`DROP TRIGGER task_snapshots_no_update`, so the printed figure is one
|
||||
short. v2 and v3 have the same gap: v2 prints 32 for a schema with 33,
|
||||
and v3 prints 33 for 34. v1 prints 27 for 27; it drops no trigger.
|
||||
|
||||
Nothing else changes. The schema files, the outputs and their sha256s
|
||||
stand as recorded; only the notes' reading of the count was wrong. Row S2
|
||||
should count 36 triggers in an intact v3a database.
|
||||
@@ -0,0 +1,34 @@
|
||||
2e4df0820d431eda19b07d264a55c713cc1cbf7e55cf8a1f648150161f995620 docs/TOOLS.md
|
||||
f1e3b3224e0b211eb62533c67c69c32f969f3174320698d55a11ad6d6b0ab9e9 packages/business/README.md
|
||||
8d83d88c68813eea5fb1bd0577736bf89cfc5166f582aca290635d4f0170e477 packages/business/examples/mosaic-stack.example.json
|
||||
0e15a5be600573ff7fa0b41c425ee6e57dad788be3d42991185c3a84d6090fe9 packages/business/package.json
|
||||
b0987c03bd762992f33cde08ea547158532414e427ff6053a2b80f77871c652f packages/business/src/business.mjs
|
||||
afba0aa4b751bc079adbded8798c788b669d65c970047f78a182ff01e8c32db9 packages/business/src/cli.mjs
|
||||
0231361f3063ee841749b2486ebbaa3a521b5687b3e0c1abc0499e7df38c49fa packages/business/src/credentials.mjs
|
||||
cd4eb5960c17ce32f26d1a49196866ce04efc42c1d90b18b046af5fda8b9ff0a packages/business/src/errors.mjs
|
||||
956dfb37868b3dd002bd8245995c416cf35dbdf9f82b154a951eb19db334d584 packages/business/src/index.mjs
|
||||
9472996134c520c31971e66006d1c1683709f6df4f76fe3445bdc97a18637eff packages/business/src/project.mjs
|
||||
d781f4fabd9e8cb0d6f836dafda95455f18dbfba58f5ce1a3582a0c2d7b7adfc packages/business/src/resolve.mjs
|
||||
bfd331d97fe165b2b70512725892b27491c54347ba05233fb4c67c7c1a77e802 packages/business/src/role.mjs
|
||||
7f7053aaee994fe445221b26e7e5884b23a6ee88afef0fec92e628a2b1985c9a packages/business/src/util.mjs
|
||||
b831cac0224cfb5cd32e482ad7fd4cbea9e16c02d2750d5e8a757785a7c56589 packages/business/src/vars.mjs
|
||||
1fa6df30bd52b032c065839efcde022456cdc4e2b735fb73884fd842e1794743 packages/business/src/vocabulary.mjs
|
||||
41c9f576818fc60fa7fc127cc4ec048ddd475d8e2f82c13cfae2419f07bffdd4 packages/business/tests/business.test.mjs
|
||||
69280b0b8390dacf899bab8f56580edcc0cb8ef8275395cc0abe7351180c2eb2 packages/business/tests/cli.test.mjs
|
||||
820286995fd2f2f258303e6a3563f16afd64c47345e4c61e963878f9fd3794e2 packages/business/tests/credentials.test.mjs
|
||||
1ea0617318f4a2246ea96d7b44fea1b278cbb0ab2e46b3deb8db11d30bb2ef19 packages/business/tests/helpers.mjs
|
||||
6aa211be6f5067d3247acf45df2f415221c36ca37720b72dbfe2726d690b3d55 packages/business/tests/project.test.mjs
|
||||
f1daa2a14aa166208f32fe8edf72d2d509e1c34cba69c22f674394921683d8ef packages/business/tests/resolve.test.mjs
|
||||
21fb723ccd2f8a8e734b527df0402cb08252b3e195022e78dcdafdda386704aa packages/business/tests/role.test.mjs
|
||||
6e5a57fa22d67ba1a94c91fd4ea338814fc5cace8394b2607a9b33cda3777c9a packages/business/tests/vars.test.mjs
|
||||
739bd95b73f3ada2438b7cbba745471efcab4feb949fcf79673f1c80c6edff7f roles/coder.json
|
||||
191e44e3a9868ef8b615db747d6684f32baa8ceb424e4e42c1f7a04668ac3288 roles/coder.md
|
||||
e394bf806220f5c91344f83bc1f8b18b9b23db4fc05092b88de7651ca4b9d8d1 roles/cto.json
|
||||
0b2ccc0efe5681fe5b06d37a80a0756c2a05daee2ccb8efe148cbd908a664c29 roles/cto.md
|
||||
6abb3d3fa80e0e753e7dbc73dfb2e599ad06223ae4211e221b1357996abb6046 roles/pm.json
|
||||
f27a0809d95e4a1d9b4b69ac9d612a237bb81f4c5fcd16d889c03ea3cf07e15a roles/pm.md
|
||||
268b93056579d1c64c59f66da3c4fb33e3357871f6a30a584229dd25725e32e1 roles/reviewer.json
|
||||
8492a681245b5b72c6249b9672ea5cb4752d7defccf70263ff9ba1415f4e9a3b roles/reviewer.md
|
||||
a0002e8b1f3a723dcbb62c1a3f4d512065bbf89f0771881c42192df4bdbc7756 scripts/mosaic
|
||||
ceea32f56dc607bf684baa6de4f260ae56ad70bbecc5510bf7a226d4269b6f6d scripts/mosaic-task.mjs
|
||||
ef8b105fca02283c73b616f1884ce3ae9a0cae3b8530d55584cea416d4d14b9f scripts/test-task.sh
|
||||
@@ -0,0 +1,153 @@
|
||||
# Row 36, S1: roles v2, business and project files, variable layers
|
||||
|
||||
Darkwing, 2026-10-04. Issue #1518, reviewer Filbert. Brief:
|
||||
`docs/plans/2026-10-04_slice-1.md`, section "Slice 1 S1". Design:
|
||||
`agents/darkwing/work/slice1-data-model-2026-10-04.md` sections 1 and 2,
|
||||
addendum A sections 7 and 8, addendum B section 2. Nothing in the
|
||||
candidate is committed, staged or pushed.
|
||||
|
||||
Base is fef4b362 (origin/refactor at build time). In a fresh clone at that
|
||||
commit the patch applies, the result matches the manifest 34/34, and
|
||||
`node --test packages/business/tests/` passes 57/57 in three runs.
|
||||
|
||||
## Files
|
||||
|
||||
`build.patch` (sha256
|
||||
`8067882052abc6e75684b318f738ef990f53c7a35913a8313a341282d259bd94`) changes
|
||||
4 files and adds 30. `build-manifest.sha256` (sha256
|
||||
`d934e5af30cd646194bbf1d9bffc2b4d51486a4bb4c097ec43376352830b0195`) pins all
|
||||
34 after the patch.
|
||||
|
||||
New:
|
||||
- `roles/pm.json`, `cto.json`, `coder.json`, `reviewer.json`: version 2
|
||||
definitions. `roles/pm.md`, `cto.md`, `coder.md`, `reviewer.md`: their
|
||||
duty contracts (Duties, Authority, Protocol).
|
||||
- `packages/business/src/`: `vocabulary.mjs` (the closed lists),
|
||||
`role.mjs` (versions 1 and 2), `vars.mjs` (the key registry and merge),
|
||||
`credentials.mjs` (reference parse and stat checks), `business.mjs`,
|
||||
`project.mjs`, `resolve.mjs` (`resolveInstance`, `classify`), `cli.mjs`,
|
||||
`util.mjs`, `errors.mjs`, `index.mjs`.
|
||||
- `packages/business/tests/`: 57 tests in 7 files plus `helpers.mjs`.
|
||||
- `packages/business/examples/mosaic-stack.example.json`: the business
|
||||
file for Sage's SR template. It refuses as shipped (every `botId` is 0,
|
||||
every date `YYYY-MM-DD`); a test proves it validates once filled in.
|
||||
- `packages/business/README.md`, `package.json`.
|
||||
|
||||
Changed:
|
||||
- `scripts/mosaic-task.mjs`: `validateRole` delegates to the package, so
|
||||
both versions share one validator. `resolve-role` also prints
|
||||
`MOSAIC_ROLE_CONTRACT=<absolute path>` for a version 2 role.
|
||||
- `scripts/test-task.sh`: 8 new checks (version 1 prints no contract line;
|
||||
the four shipped roles resolve with their contracts; a minimal version 2
|
||||
role passes; unknown action, gated-only action, a Vikunja verb no role
|
||||
may hold, a missing contract and a linked contract each exit 2).
|
||||
- `scripts/mosaic`: a `business` branch, like `queue`. This is outside the
|
||||
brief's file list. The brief asks for a TOOLS entry for any new command,
|
||||
and a command needs an entry point; the change is four lines.
|
||||
- `docs/TOOLS.md`: a section for `scripts/mosaic business`, and the
|
||||
`resolve-role` row now says it takes versions 1 and 2.
|
||||
|
||||
## Does the vocabulary go under `contracts/`?
|
||||
|
||||
No. `contracts/` is baked into the worker image because workers read it.
|
||||
Nothing in a worker reads the action vocabulary: the broker classifies
|
||||
actions on the host, and the role files are read on the host by the
|
||||
launcher and the broker. Baking it in would give the image a copy that
|
||||
nobody checks against. The vocabulary lives in
|
||||
`packages/business/src/vocabulary.mjs`, and a change to it is a reviewed
|
||||
commit, like a role file. `Containerfile` copies `package.json`,
|
||||
`contracts`, `src` and `adapters` only, so neither `packages/` nor
|
||||
`scripts/mosaic-task.mjs` is in the image, and the new import doesn't
|
||||
reach it. No contracts change, so no review by Sage for one.
|
||||
|
||||
## Choices and deviations from the design
|
||||
|
||||
1. `contract` is a file name in the role file's own directory
|
||||
(`"coder.md"`), not the note's `"roles/coder.md"`. A path relative to
|
||||
the repository breaks under `MOSAIC_ROLES_DIR`, which `agent.sh` and
|
||||
the tests use for sandbox role directories. The validator refuses a
|
||||
name with a slash, a non-`.md` name, a missing, empty or linked file.
|
||||
2. pm authority adds three actions to the note's table (section 1.2):
|
||||
- `task.update.assigned` (within): addendum A section 2 says all four
|
||||
roles update the tasks assigned to them, and the note's pm row left
|
||||
it out.
|
||||
- `task.reassign` (within): addendum A's action table gives
|
||||
reassign to pm, cross-role for the others.
|
||||
- `task.scope.change` (cross): pm splits and rewrites tasks, and a
|
||||
scope change on one in technical work needs the CTO, the technical
|
||||
arbiter. Filbert, push back if you read it differently.
|
||||
3. The business file must belong to the user and not be group or other
|
||||
writable. It holds authority, so a file someone else can edit would let
|
||||
them widen it. Missing file: exit 4. A linked file: exit 4.
|
||||
4. Bot names and bot ids are unique across role instances and the sync
|
||||
bot. Two instances sharing one Vikunja bot would make the tracker's
|
||||
record of who did what wrong.
|
||||
5. `role.launch` stays within-role only for the instance the business
|
||||
file's `launch.by` names. Everywhere else the resolver removes it, so
|
||||
`classify` returns gated. With no `launch` block nobody launches.
|
||||
6. `limits.authority` is an allowlist. A role action it doesn't name
|
||||
becomes gated. It can't add an action the definition lacks.
|
||||
7. Credential checks use `lstat` and `realpath` only. A test makes a token
|
||||
file mode 0200 (write-only) and the check still passes, which shows the
|
||||
package never opens it. A token inside the repository, `dataRoot` or a
|
||||
project root refuses, also through a linked directory. Vikunja: past
|
||||
`expires` refuses, within 7 days warns. Gitea: past `rotateBy` warns;
|
||||
Gitea tokens don't expire on their own. An `env` reference that isn't
|
||||
set warns, because the launcher sets it.
|
||||
8. Lookups use `Object.hasOwn`. Ids may be any lowercase name, and
|
||||
`constructor` is one, so `roles[name]` would have treated it as
|
||||
declared. Tests cover arbiters, launch, the model family and a label
|
||||
titled `__proto__`.
|
||||
9. `validate` treats a declared project with no project file as a
|
||||
warning ("absent"). `resolve --project` treats it as a missing file,
|
||||
exit 4. When a project file exists, `validate` resolves every instance
|
||||
against it, so a project file naming an undeclared instance refuses
|
||||
there.
|
||||
10. Error text for version 1 roles now comes from the package. Every
|
||||
existing `test-task.sh` case still passes; only wording changed.
|
||||
11. The package says "role file" for `roles/<name>.json`, so it doesn't
|
||||
share a name with the Markdown contract. `mosaic-task.mjs` and
|
||||
`agent.sh` keep their old wording ("role contract"); I didn't touch
|
||||
those messages.
|
||||
|
||||
## Tests and suites
|
||||
|
||||
Node 26.8.1 on the host, outputs teed:
|
||||
- `node --test packages/business/tests/`: 57/57. Files: role 12, vars 6,
|
||||
credentials 6, business 14, project 2, resolve 8, cli 9.
|
||||
- `scripts/test-config.sh` 24/24, `scripts/test-task.sh` 98/98,
|
||||
`scripts/test-conductor.sh` 17/17, `scripts/test-queue.sh` 27/27
|
||||
(`scripts/mosaic` changed).
|
||||
|
||||
Node 24.21.0 in the `node:24` image, no network, the clone mounted
|
||||
read-only: `node --test "packages/business/tests/*.test.mjs"` 57/57. The
|
||||
glob is needed because Node 24 reads `node --test tests/` as a module
|
||||
path and fails. That is true of every package in the repository; I
|
||||
checked `packages/queue` the same way. Follow-up for Sage, not part of
|
||||
S1.
|
||||
|
||||
Mutants, each run against the full test set and each caught: the
|
||||
forbidden-root check off (3 failures), the `role.launch` gate off (1),
|
||||
the token mode mask widened to other only (1), `hasOwn` dropped from the
|
||||
instance lookup (2), the business file mode check off (1), limit
|
||||
intersection replaced by overwrite (2).
|
||||
|
||||
The CLI tests point `MOSAIC_CONFIG`, `HOME` and `MOSAIC_ROLES_DIR` into a
|
||||
temp directory. No test reads the real `~/.config`.
|
||||
|
||||
## For other rows
|
||||
|
||||
- S2 (Rocko) consumes `loadBusiness` and `resolveInstance`. The frozen
|
||||
API is in `packages/business/README.md`, section "API".
|
||||
- S3 (mine) opens token files, so it repeats the stat checks at open
|
||||
time and trims one trailing newline.
|
||||
- S6 decides how a launcher passes `MOSAIC_ROLE_CONTRACT` to the session.
|
||||
`agent.sh` reads only `MOSAIC_ROLE_TOOLS` today and ignores the new
|
||||
line.
|
||||
|
||||
## Follow-ups, not in this candidate
|
||||
|
||||
- `node --test <dir>/` fails on Node 24 in every package (above).
|
||||
- `scripts/mosaic-task.mjs` keeps its own `SUPPORTED_TOOLS` for tasks.
|
||||
The package has the same list in `TOOLS`. One should import the other
|
||||
in a later change.
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user