This commit is contained in:
@@ -27,7 +27,8 @@ The fleet path never falls back to an interactive wizard. It exits nonzero befor
|
|||||||
when:
|
when:
|
||||||
|
|
||||||
- `MOSAIC_AGENT_NAME` is not an exact roster member;
|
- `MOSAIC_AGENT_NAME` is not an exact roster member;
|
||||||
- an ambient `MOSAIC_AGENT_CLASS` disagrees with that member's canonical class;
|
- a defined ambient `MOSAIC_AGENT_CLASS` is blank/whitespace or disagrees with that member's
|
||||||
|
canonical class;
|
||||||
- a missing destination has no safe regular default source;
|
- a missing destination has no safe regular default source;
|
||||||
- a source or existing destination is a symlink (including dangling), directory, unavailable, or over the bounded size;
|
- a source or existing destination is a symlink (including dangling), directory, unavailable, or over the bounded size;
|
||||||
- the fleet communications helper/roster cannot be validated; or
|
- the fleet communications helper/roster cannot be validated; or
|
||||||
@@ -56,8 +57,8 @@ The build leg is load-bearing: `dist/` is ignored, so a direct Vitest invocation
|
|||||||
absent or stale CLI output. The gate runs the exact-source built CLI in subprocesses with piped stdin,
|
absent or stale CLI output. The gate runs the exact-source built CLI in subprocesses with piped stdin,
|
||||||
temporary homes, a canonical fixture roster, fake runtime/broker executables, and no provider call. It
|
temporary homes, a canonical fixture roster, fake runtime/broker executables, and no provider call. It
|
||||||
covers no-TTY launch, exact identity,
|
covers no-TTY launch, exact identity,
|
||||||
private modes, no-clobber, missing/symlink defaults, unknown members, class mismatch,
|
private modes, no-clobber, missing/symlink defaults, unknown members, blank/mismatched class,
|
||||||
standalone wizard preservation, and concurrent first start.
|
portable standalone composition/wizard preservation, and concurrent first start.
|
||||||
|
|
||||||
Do not use this fixture as proof that a real provider credential is present or that a package has
|
Do not use this fixture as proof that a real provider credential is present or that a package has
|
||||||
been deployed. Those require separate environment-specific evidence.
|
been deployed. Those require separate environment-specific evidence.
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ The fix remains at `checkSoul()` and does not add flags to `yolo`, fleet command
|
|||||||
|
|
||||||
1. A present, nonblank, whitespace-exact `MOSAIC_AGENT_NAME` selects the fleet path.
|
1. A present, nonblank, whitespace-exact `MOSAIC_AGENT_NAME` selects the fleet path.
|
||||||
2. `resolveFleetIdentity()` must resolve that exact member through the existing roster/helper
|
2. `resolveFleetIdentity()` must resolve that exact member through the existing roster/helper
|
||||||
boundary, and any ambient `MOSAIC_AGENT_CLASS` must canonicalize to the roster class, before any
|
boundary, and any defined `MOSAIC_AGENT_CLASS` (including blank/whitespace) must canonicalize to
|
||||||
identity seed.
|
the roster class, before any identity seed. Only undefined means absent.
|
||||||
3. `lstatSync()` preflights every destination directory entry without following links, so a dangling
|
3. `lstatSync()` preflights every destination directory entry without following links, so a dangling
|
||||||
link is rejected before its counterpart can be published.
|
link is rejected before its counterpart can be published.
|
||||||
4. Safe bounded snapshots are read from only the missing contracts under `defaults/`.
|
4. Safe bounded snapshots are read from only the missing contracts under `defaults/`.
|
||||||
@@ -26,10 +26,12 @@ The fix remains at `checkSoul()` and does not add flags to `yolo`, fleet command
|
|||||||
concurrent seat or operator won; the existing path is preserved and revalidated.
|
concurrent seat or operator won; the existing path is preserved and revalidated.
|
||||||
7. Temporary files are removed, and both installed contracts are re-opened through the no-symlink
|
7. Temporary files are removed, and both installed contracts are re-opened through the no-symlink
|
||||||
secure-file reader before launch continues.
|
secure-file reader before launch continues.
|
||||||
8. `composeContract()` independently re-resolves the roster, securely reads `USER.md` through a
|
8. `composeContract()` independently re-resolves the roster, securely reads fleet `USER.md` through
|
||||||
descriptor at the point of use, and injects exact member identity and communications data.
|
a Linux descriptor at the point of use, and injects exact member identity and communications data.
|
||||||
|
|
||||||
A standalone launch with no `MOSAIC_AGENT_NAME` retains the interactive wizard.
|
A standalone launch with no `MOSAIC_AGENT_NAME` retains the portable tolerant USER read and the
|
||||||
|
interactive wizard. Fleet-only no-follow enforcement must not make supported standalone macOS
|
||||||
|
composition depend on Linux `/proc` descriptor traversal.
|
||||||
|
|
||||||
## Identity and authority
|
## Identity and authority
|
||||||
|
|
||||||
@@ -42,9 +44,9 @@ not the source of a fleet seat's identity. The canonical roster controls:
|
|||||||
- tmux socket and helper target; and
|
- tmux socket and helper target; and
|
||||||
- communications generation.
|
- communications generation.
|
||||||
|
|
||||||
An unknown/padded ambient name or mismatched ambient class fails before any file is seeded. This
|
An unknown/padded ambient name, mismatched class, or explicitly blank/whitespace class fails before
|
||||||
avoids replacing the interactive wall with a fleet of indistinguishable or ambiently invented
|
any file is seeded. This avoids replacing the interactive wall with a fleet of indistinguishable or
|
||||||
identities.
|
ambiently invented identities.
|
||||||
|
|
||||||
## Concurrency and filesystem properties
|
## Concurrency and filesystem properties
|
||||||
|
|
||||||
@@ -64,8 +66,9 @@ no-TTY subprocess, not a direct wizard test. The package `test:vitest` gate buil
|
|||||||
Vitest, while the clean-checkout command builds its workspace dependencies first, so ignored
|
Vitest, while the clean-checkout command builds its workspace dependencies first, so ignored
|
||||||
`dist/cli.js` cannot be absent or stale. A fake lease launcher records whether execution reached the
|
`dist/cli.js` cannot be absent or stale. A fake lease launcher records whether execution reached the
|
||||||
runtime boundary and captures the composed prompt.
|
runtime boundary and captures the composed prompt.
|
||||||
Positive and negative cases prove the check can both proceed and refuse. Composition coverage also
|
Positive and negative cases prove the check can both proceed and refuse. Fleet composition coverage
|
||||||
replaces a previously validated `USER.md` with an external symlink and proves point-of-use refusal.
|
replaces a previously validated `USER.md` with an external symlink and proves point-of-use refusal;
|
||||||
|
a standalone unreadable-optional-USER case proves the portable tolerant branch remains separate.
|
||||||
|
|
||||||
Real Pi authentication and provider task execution remain environment tests, not claims of this
|
Real Pi authentication and provider task execution remain environment tests, not claims of this
|
||||||
fixture.
|
fixture.
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ base. The canonical roster row supplies each seat's exact name, class, peers, so
|
|||||||
|
|
||||||
## Operator behavior
|
## Operator behavior
|
||||||
|
|
||||||
A normal standalone launch without a fleet identity still uses the interactive wizard when
|
A normal standalone launch without a fleet identity retains its portable configuration path and still
|
||||||
`SOUL.md` is absent:
|
uses the interactive wizard when `SOUL.md` is absent:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mosaic pi
|
mosaic pi
|
||||||
@@ -38,8 +38,8 @@ A roster-owned seat may be started without attaching to its pane:
|
|||||||
mosaic fleet start <exact-roster-name>
|
mosaic fleet start <exact-roster-name>
|
||||||
```
|
```
|
||||||
|
|
||||||
Mosaic refuses before runtime execution if the requested member is absent, its ambient class
|
Mosaic refuses before runtime execution if the requested member is absent, its explicitly supplied
|
||||||
conflicts with the roster, a required default is missing or unsafe, or an existing identity contract
|
ambient class is blank or conflicts with the roster, a required default is missing or unsafe, or an existing identity contract
|
||||||
is not a safe regular file. Repair the named component and retry the same exact roster member; do not
|
is not a safe regular file. Repair the named component and retry the same exact roster member; do not
|
||||||
copy another seat's personalized identity.
|
copy another seat's personalized identity.
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,25 @@ Result: risk `none`, confidence `0.93`, 9 files, no critical/high/medium/low fin
|
|||||||
could not run Vitest because Vite attempted to create a temporary config artifact on its read-only
|
could not run Vitest because Vite attempted to create a temporary config artifact on its read-only
|
||||||
mount (`EROFS`); executor-owned focused and full results are recorded in the QA report.
|
mount (`EROFS`); executor-owned focused and full results are recorded in the QA report.
|
||||||
|
|
||||||
|
## Second exact-head review
|
||||||
|
|
||||||
|
Daphne reviewed exact head `9dc90be7e13b1cd609f6df97d43d890ef5392ca0` and filed Gitea review
|
||||||
|
ID 169 as `REQUEST_CHANGES`. Review 169 confirmed all review-168 closures, then found:
|
||||||
|
|
||||||
|
1. the new point-of-use reader was Linux-only but had been applied to every standalone USER read,
|
||||||
|
breaking supported non-fleet macOS composition; and
|
||||||
|
2. explicit blank/whitespace `MOSAIC_AGENT_CLASS` was treated as absent and could seed before
|
||||||
|
runtime, while only undefined should mean absent.
|
||||||
|
|
||||||
|
Red-first remediation preserves legacy `readOptional()` for standalone composition, keeps descriptor
|
||||||
|
no-follow consumption fleet-only, moves the replacement-symlink case under a valid fleet identity,
|
||||||
|
and rejects defined blank/whitespace classes before seeding. Three blank-class CLI cases and one
|
||||||
|
tolerant standalone composition case failed before the source change and pass after it.
|
||||||
|
|
||||||
|
Review-169 remediation code review approved at confidence `0.90` (4 files, no findings). Security
|
||||||
|
review reported risk `none` at confidence `0.90` (4 files, no findings). The review sandbox retained
|
||||||
|
its known Vite `EROFS` limitation; executor-owned tests are in the QA report.
|
||||||
|
|
||||||
## Remaining review gate
|
## Remaining review gate
|
||||||
|
|
||||||
Daphne must re-review the next exact pushed head. This report cannot record that future verdict
|
Daphne must re-review the next exact pushed head. This report cannot record that future verdict
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
- [x] Initial padded-name finding remediated and automated re-review approved.
|
- [x] Initial padded-name finding remediated and automated re-review approved.
|
||||||
- [x] Daphne formal review ID 168 completed on exact first head `43fa0477` and requested changes.
|
- [x] Daphne formal review ID 168 completed on exact first head `43fa0477` and requested changes.
|
||||||
- [x] Four formal-review groups reproduced red and remediated; automated remediation code/security
|
- [x] Four review-168 groups reproduced red and remediated; automated reviews are clean.
|
||||||
reviews are clean.
|
- [x] Daphne review ID 169 completed on exact head `9dc90be7` and confirmed review-168 closures.
|
||||||
- [ ] Daphne exact-remediation-head re-review completed after push (Fred/goals excluded).
|
- [x] Review-169 standalone-portability and blank-class blockers reproduced red and remediated;
|
||||||
|
automated reviews are clean.
|
||||||
|
- [ ] Daphne exact-second-remediation-head re-review completed after push (Fred/goals excluded).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# #1264 Unattended Fleet First-Start Verification
|
# #1264 Unattended Fleet First-Start Verification
|
||||||
|
|
||||||
> Status: **IN PROGRESS — review remediation complete locally; push/re-review pending** | Executor:
|
> Status: **IN PROGRESS — review-169 remediation complete locally; push/re-review pending** |
|
||||||
> goals | Date: 2026-08-16 | Target: isolated local fixtures only
|
> Executor: goals | Date: 2026-08-16 | Target: isolated local fixtures only
|
||||||
|
|
||||||
## Objective
|
## Objective
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ executables.
|
|||||||
| ---------------------------------------------------------------------- | --------------------------------------------------------------- | ----------------------------- |
|
| ---------------------------------------------------------------------- | --------------------------------------------------------------- | ----------------------------- |
|
||||||
| No-TTY fleet first start avoids wizard and reaches runtime | Exact-source built CLI with piped stdin | CLI GREEN |
|
| No-TTY fleet first start avoids wizard and reaches runtime | Exact-source built CLI with piped stdin | CLI GREEN |
|
||||||
| Missing top-level identity files are initialized from shipped defaults | Exact-byte and `0600` assertions | CLI + filesystem GREEN |
|
| Missing top-level identity files are initialized from shipped defaults | Exact-byte and `0600` assertions | CLI + filesystem GREEN |
|
||||||
| Exact seat identity remains roster-owned | Captured argv; name/class mismatch no-side-effect refusals | CLI GREEN |
|
| Exact seat identity remains roster-owned | Captured argv; mismatched/blank class no-side-effect refusals | CLI GREEN |
|
||||||
| Existing operator identity is never overwritten | Custom bytes/mode with defaults removed | CLI + filesystem GREEN |
|
| Existing operator identity is never overwritten | Custom bytes/mode with defaults removed | CLI + filesystem GREEN |
|
||||||
| Concurrent/repeated first start is safe | Four parallel CLIs plus repeated launch | CLI GREEN |
|
| Concurrent/repeated first start is safe | Four parallel CLIs plus repeated launch | CLI GREEN |
|
||||||
| Missing/unsafe defaults and destinations fail before partial mutation | Missing, target/dangling symlink, oversized, invalid-root cases | Filesystem/CLI GREEN |
|
| Missing/unsafe defaults and destinations fail before partial mutation | Missing, target/dangling symlink, oversized, invalid-root cases | Filesystem/CLI GREEN |
|
||||||
@@ -85,7 +85,18 @@ passed:
|
|||||||
3. dangling `USER.md` allowed `SOUL.md` to be published before refusal; and
|
3. dangling `USER.md` allowed `SOUL.md` to be published before refusal; and
|
||||||
4. replacing a securely validated `USER.md` with an external symlink was followed by composition.
|
4. replacing a securely validated `USER.md` with an external symlink was followed by composition.
|
||||||
|
|
||||||
This establishes that all four reviewer findings were observable on the pushed implementation.
|
This establishes that all four review-168 findings were observable on the pushed implementation.
|
||||||
|
|
||||||
|
Daphne's review ID 169 then found two more exact-head failures at `9dc90be7`. Before production
|
||||||
|
changes, four new assertions failed:
|
||||||
|
|
||||||
|
1. standalone composition routed an unreadable optional `USER.md` through the Linux-only descriptor
|
||||||
|
reader instead of the legacy portable tolerant path; and
|
||||||
|
2. explicit `MOSAIC_AGENT_CLASS` values `""`, `" "`, and tab were treated as absent, seeded both
|
||||||
|
identity files, and reached runtime.
|
||||||
|
|
||||||
|
The replacement-symlink case was also moved under a valid roster identity so it tests the fleet-only
|
||||||
|
security boundary rather than standalone behavior.
|
||||||
|
|
||||||
## Final GREEN
|
## Final GREEN
|
||||||
|
|
||||||
@@ -105,16 +116,17 @@ env -u DATABASE_URL sh -c '
|
|||||||
'
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
Exit `0`: `6/6` files, `124/124` tests.
|
Exit `0`: `6/6` files, `128/128` tests.
|
||||||
|
|
||||||
- 12 real-CLI/no-TTY tests cover exact roster name/class, byte-equal `0600` seeds, no-clobber,
|
- 15 real-CLI/no-TTY tests cover exact roster name/class, byte-equal `0600` seeds, no-clobber,
|
||||||
partial seed, missing/symlink defaults, unknown/padded/blank name, mismatched class, standalone
|
partial seed, missing/symlink defaults, unknown/padded/blank name, mismatched or explicitly blank
|
||||||
wizard preservation, and four concurrent starts.
|
class, standalone wizard preservation, and four concurrent starts.
|
||||||
- 12 direct filesystem tests cover complete publication, existing operators, idempotence, source
|
- 12 direct filesystem tests cover complete publication, existing operators, idempotence, source
|
||||||
prevalidation, target and dangling destination links, invalid roots, oversized input, and
|
prevalidation, target and dangling destination links, invalid roots, oversized input, and
|
||||||
unexpected link errors.
|
unexpected link errors.
|
||||||
- Composition coverage deterministically replaces validated `USER.md` with an external symlink and
|
- Composition coverage deterministically replaces a valid fleet seat's validated `USER.md` with an
|
||||||
requires refusal at point of use.
|
external symlink and requires refusal at point of use. A separate standalone case proves tolerant
|
||||||
|
optional composition remains outside the Linux-only fleet reader.
|
||||||
|
|
||||||
Full package gate (which rebuilds Mosaic itself after the clean-checkout dependency build):
|
Full package gate (which rebuilds Mosaic itself after the clean-checkout dependency build):
|
||||||
|
|
||||||
@@ -122,13 +134,13 @@ Full package gate (which rebuilds Mosaic itself after the clean-checkout depende
|
|||||||
env -u DATABASE_URL pnpm --filter @mosaicstack/mosaic run test:vitest
|
env -u DATABASE_URL pnpm --filter @mosaicstack/mosaic run test:vitest
|
||||||
```
|
```
|
||||||
|
|
||||||
Exit `0`: `88/88` files, `1,573/1,573` tests.
|
Exit `0`: `88/88` files, `1,577/1,577` tests.
|
||||||
|
|
||||||
Focused helper + point-of-use coverage:
|
Focused helper + point-of-use coverage:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
2 files, 52/52 tests
|
2 files, 53/53 tests
|
||||||
Statements 97.97% | Branches 88% | Functions 100% | Lines 97.97%
|
Statements 97.84% | Branches 91.66% | Functions 100% | Lines 97.84%
|
||||||
Exit 0
|
Exit 0
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -164,9 +176,14 @@ because this checkout prohibits the PostgreSQL-dependent gateway isolation path.
|
|||||||
- Codex security review of the remediation: risk `none`, confidence `0.93`, 9 files, no findings.
|
- Codex security review of the remediation: risk `none`, confidence `0.93`, 9 files, no findings.
|
||||||
Its sandbox could not execute Vitest because Vite attempted a write on a read-only mount; the
|
Its sandbox could not execute Vitest because Vite attempted a write on a read-only mount; the
|
||||||
executor-owned results above are the test evidence.
|
executor-owned results above are the test evidence.
|
||||||
- Daphne formal review ID 168 at exact head `43fa0477`: `REQUEST_CHANGES`, four blocking groups. All
|
- Daphne formal review ID 168 at exact head `43fa0477`: `REQUEST_CHANGES`, four blocking groups; all
|
||||||
four have red-first regressions and local green remediation. Re-review of the next pushed exact
|
closed by review 169.
|
||||||
head is necessarily pending until that head exists.
|
- Daphne formal review ID 169 at exact head `9dc90be7`: `REQUEST_CHANGES`, two blocking groups
|
||||||
|
(standalone portability and explicit blank class). Both now have red-first regressions and local
|
||||||
|
green remediation.
|
||||||
|
- Codex review of review-169 remediation: `approve`, confidence `0.90`, 4 files, no findings.
|
||||||
|
- Codex security review of review-169 remediation: risk `none`, confidence `0.90`, 4 files, no
|
||||||
|
findings. Exact-new-head Daphne re-review is pending until that head is pushed.
|
||||||
|
|
||||||
## CI evidence and external blocker
|
## CI evidence and external blocker
|
||||||
|
|
||||||
@@ -183,7 +200,9 @@ FAIL: host provides 'pi' in the system path; missing-binary cases are not measur
|
|||||||
That line comes from the inherited `test-start-agent-session.sh` CI-fit guard, not #1264. Fred filed
|
That line comes from the inherited `test-start-agent-session.sh` CI-fit guard, not #1264. Fred filed
|
||||||
the correction as PR #1270. Its pipeline 2448 is terminal green and proves the four formerly masked
|
the correction as PR #1270. Its pipeline 2448 is terminal green and proves the four formerly masked
|
||||||
suites execute, but #1270 is not merged, so `next` still carries the failing chain. A new #1268
|
suites execute, but #1270 is not merged, so `next` still carries the failing chain. A new #1268
|
||||||
pipeline is pending the remediation push. Terminal-green #1268 CI is not claimed.
|
pipeline 2449 at `9dc90be7` reproduced the same single inherited `FAIL:` after Mosaic passed
|
||||||
|
`1,573/1,573`. A new pipeline is pending the review-169 remediation push. Terminal-green #1268 CI is
|
||||||
|
not claimed.
|
||||||
|
|
||||||
PR #1268's envelope was read back as `user.login=mos-dt-0`; its commit is explicitly authored and
|
PR #1268's envelope was read back as `user.login=mos-dt-0`; its commit is explicitly authored and
|
||||||
committed by `goals <[email protected]>`. No goals Gitea login exists on this host, and no
|
committed by `goals <[email protected]>`. No goals Gitea login exists on this host, and no
|
||||||
|
|||||||
@@ -7,13 +7,14 @@
|
|||||||
- Branch: `fix/1264-fleet-unattended-first-start`
|
- Branch: `fix/1264-fleet-unattended-first-start`
|
||||||
- Base: `origin/next@476db12b92971634b67fd2057b7577ee5894e449`
|
- Base: `origin/next@476db12b92971634b67fd2057b7577ee5894e449`
|
||||||
- First pushed head: `43fa0477877e0d0f110da8d11c3033b40ddeb191`
|
- First pushed head: `43fa0477877e0d0f110da8d11c3033b40ddeb191`
|
||||||
- Current remediation worktree: `/var/home/jason.woltje/agent-work/1264-review-remediation`
|
- Current remediation worktree: `/var/home/jason.woltje/agent-work/1264-review2-remediation`
|
||||||
- Coordinator: Fred; reviewer must be neither Fred nor this implementation seat.
|
- Coordinator: Fred; reviewer must be neither Fred nor this implementation seat.
|
||||||
- `docs/TASKS.md` is orchestrator-owned and is not modified by this worker.
|
- `docs/TASKS.md` is orchestrator-owned and is not modified by this worker.
|
||||||
|
|
||||||
The original `/var/home/jason.woltje/agent-work/1264-unattended-first-start` worktree was removed
|
The original `/var/home/jason.woltje/agent-work/1264-unattended-first-start` and first remediation
|
||||||
without force after its pushed head and clean state were verified. The Fred-authorized plain-Git
|
worktrees were removed without force after each pushed head and clean state were verified. The
|
||||||
worktree exception was reused for exact-head review remediation because `/src` remains unavailable.
|
Fred-authorized plain-Git worktree exception was reused for exact-head review remediation because
|
||||||
|
`/src` remains unavailable.
|
||||||
|
|
||||||
## Objective
|
## Objective
|
||||||
|
|
||||||
@@ -37,14 +38,16 @@ preserving the standalone interactive wizard.
|
|||||||
|
|
||||||
- PRD IDs: `FCM-REQ-12`, `AC-FCM-10`; `FCM-REQ-11` is reserved by #1256.
|
- PRD IDs: `FCM-REQ-12`, `AC-FCM-10`; `FCM-REQ-11` is reserved by #1256.
|
||||||
- A present fleet name must be nonblank, whitespace-exact, and resolve through the canonical roster.
|
- A present fleet name must be nonblank, whitespace-exact, and resolve through the canonical roster.
|
||||||
- Any ambient class must canonicalize to the roster class before mutation.
|
- Any defined ambient class, including blank/whitespace, must canonicalize to the roster class before
|
||||||
|
mutation; only undefined means absent.
|
||||||
- Preflight all destination directory entries with no-follow existence semantics so dangling links
|
- Preflight all destination directory entries with no-follow existence semantics so dangling links
|
||||||
fail before counterpart publication.
|
fail before counterpart publication.
|
||||||
- Seed only missing top-level files from bounded regular defaults with owner-private, atomic,
|
- Seed only missing top-level files from bounded regular defaults with owner-private, atomic,
|
||||||
no-clobber hard links.
|
no-clobber hard links.
|
||||||
- Generic defaults are behavior, not identity or authority.
|
- Generic defaults are behavior, not identity or authority.
|
||||||
- Securely consume `USER.md` through a descriptor at composition time.
|
- Securely consume fleet `USER.md` through a Linux descriptor at composition time.
|
||||||
- Standalone missing identity retains the wizard.
|
- Standalone composition retains the portable tolerant USER read and missing identity retains the
|
||||||
|
wizard.
|
||||||
|
|
||||||
## Progress
|
## Progress
|
||||||
|
|
||||||
@@ -54,9 +57,11 @@ preserving the standalone interactive wizard.
|
|||||||
- [x] Initial automated review finding (padded name before write) remediated.
|
- [x] Initial automated review finding (padded name before write) remediated.
|
||||||
- [x] Commit `43fa0477` pushed; PR #1268 opened against `next`; original worktree removed cleanly.
|
- [x] Commit `43fa0477` pushed; PR #1268 opened against `next`; original worktree removed cleanly.
|
||||||
- [x] Daphne formal review ID 168 completed on exact first head: `REQUEST_CHANGES` with four groups.
|
- [x] Daphne formal review ID 168 completed on exact first head: `REQUEST_CHANGES` with four groups.
|
||||||
- [x] All four groups reproduced red before remediation and now pass locally.
|
- [x] All four review-168 groups reproduced red before remediation and passed at `9dc90be7`.
|
||||||
- [x] Remediation Codex review approved; remediation security review risk `none`.
|
- [x] Daphne review ID 169 completed on `9dc90be7`: review-168 closures confirmed; two new blockers.
|
||||||
- [ ] Commit/push remediation with explicit goals author/committer; verify remote object/content.
|
- [x] Review-169 portability and blank-class blockers reproduced red and now pass locally.
|
||||||
|
- [x] Review-169 Codex review approved; security review risk `none`.
|
||||||
|
- [ ] Commit/push second remediation with explicit goals author/committer; verify remote object/content.
|
||||||
- [ ] Daphne exact-new-head re-review.
|
- [ ] Daphne exact-new-head re-review.
|
||||||
- [ ] Terminal #1268 CI. Pipeline 2445's only `FAIL:` was the inherited Pi-PATH CI-fit guard; PR
|
- [ ] Terminal #1268 CI. Pipeline 2445's only `FAIL:` was the inherited Pi-PATH CI-fit guard; PR
|
||||||
#1270's pipeline 2448 is green, but #1270 is not merged.
|
#1270's pipeline 2448 is green, but #1270 is not merged.
|
||||||
@@ -73,13 +78,15 @@ and never created the fake runtime-boundary capture.
|
|||||||
|
|
||||||
Against exact first-head production code, four new tests failed while 1,568 existing tests passed:
|
Against exact first-head production code, four new tests failed while 1,568 existing tests passed:
|
||||||
class mismatch mutated before refusal; each dangling destination left its counterpart; and a
|
class mismatch mutated before refusal; each dangling destination left its counterpart; and a
|
||||||
replacement `USER.md` symlink was consumed by composition.
|
replacement `USER.md` symlink was consumed by composition. Review-169 RED then proved standalone
|
||||||
|
composition hit the Linux-only reader and three explicit blank/whitespace class cases seeded and
|
||||||
|
launched.
|
||||||
|
|
||||||
### Final local GREEN
|
### Final local GREEN
|
||||||
|
|
||||||
- Exact-source focused gate: `6/6` files, `124/124` tests.
|
- Exact-source focused gate: `6/6` files, `128/128` tests.
|
||||||
- Full exact-source Mosaic Vitest: `88/88` files, `1,573/1,573` tests.
|
- Full exact-source Mosaic Vitest: `88/88` files, `1,577/1,577` tests.
|
||||||
- Helper + point-of-use coverage: `52/52`; 97.97% statements/lines, 88% branches, 100% functions.
|
- Helper + point-of-use coverage: `53/53`; 97.84% statements/lines, 91.66% branches, 100% functions.
|
||||||
- Root preflight passed; typecheck `45/45`, lint `25/25`, build `25/25`.
|
- Root preflight passed; typecheck `45/45`, lint `25/25`, build `25/25`.
|
||||||
- Initial targeted shell gates passed: start-agent-session, install migration `21/21`, init-RCE.
|
- Initial targeted shell gates passed: start-agent-session, install migration `21/21`, init-RCE.
|
||||||
- Local aggregate framework shell stops at operator-global Pi `0.84.2` versus measured `0.84.1`.
|
- Local aggregate framework shell stops at operator-global Pi `0.84.2` versus measured `0.84.1`.
|
||||||
@@ -90,8 +97,8 @@ The full evidence and command boundaries are in
|
|||||||
|
|
||||||
## Review / delivery notes
|
## Review / delivery notes
|
||||||
|
|
||||||
- Codex remediation review: approve, confidence `0.88`, no findings.
|
- Review-168 remediation Codex review: approve `0.88`; security risk `none` `0.93`.
|
||||||
- Codex remediation security review: risk `none`, confidence `0.93`, no findings.
|
- Review-169 remediation Codex review: approve `0.90`; security risk `none` `0.90`.
|
||||||
- PR envelope reads `mos-dt-0`; the commit reads goals/goals. No goals Gitea principal exists on this
|
- PR envelope reads `mos-dt-0`; the commit reads goals/goals. No goals Gitea principal exists on this
|
||||||
host, so no other principal will be borrowed. Tracked in #1272.
|
host, so no other principal will be borrowed. Tracked in #1272.
|
||||||
- PR #1270 is pushed, not merged. Do not represent `next` or #1268 CI as green until measured.
|
- PR #1270 is pushed, not merged. Do not represent `next` or #1268 CI as green until measured.
|
||||||
|
|||||||
@@ -334,7 +334,22 @@ describe('composeContract — overlay composer', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('refuses a USER.md replacement symlink at the point of composition', () => {
|
it('refuses a fleet USER.md replacement symlink at the point of composition', () => {
|
||||||
|
mkdirSync(join(fixture.home, 'fleet'), { recursive: true });
|
||||||
|
writeFileSync(
|
||||||
|
join(fixture.home, 'fleet', 'roster.yaml'),
|
||||||
|
[
|
||||||
|
'version: 1',
|
||||||
|
'transport: tmux',
|
||||||
|
'agents:',
|
||||||
|
' - name: exact-user-seat',
|
||||||
|
' runtime: pi',
|
||||||
|
' class: worker',
|
||||||
|
'',
|
||||||
|
].join('\n'),
|
||||||
|
);
|
||||||
|
process.env['MOSAIC_AGENT_NAME'] = 'exact-user-seat';
|
||||||
|
process.env['MOSAIC_AGENT_CLASS'] = 'worker';
|
||||||
writeFileSync(join(fixture.home, 'defaults', 'SOUL.md'), '# Generic soul\n');
|
writeFileSync(join(fixture.home, 'defaults', 'SOUL.md'), '# Generic soul\n');
|
||||||
writeFileSync(join(fixture.home, 'defaults', 'USER.md'), '# Generic user\n');
|
writeFileSync(join(fixture.home, 'defaults', 'USER.md'), '# Generic user\n');
|
||||||
expect(seedFleetIdentityDefaults(fixture.home)).toEqual(['SOUL.md']);
|
expect(seedFleetIdentityDefaults(fixture.home)).toEqual(['SOUL.md']);
|
||||||
@@ -351,6 +366,17 @@ describe('composeContract — overlay composer', () => {
|
|||||||
expect(readFileSync(external, 'utf8')).toBe('UNSAFE-REPLACEMENT-USER-CONTENT\n');
|
expect(readFileSync(external, 'utf8')).toBe('UNSAFE-REPLACEMENT-USER-CONTENT\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('preserves tolerant standalone composition when optional USER.md is unreadable', () => {
|
||||||
|
const userPath = join(fixture.home, 'USER.md');
|
||||||
|
rmSync(userPath);
|
||||||
|
mkdirSync(userPath);
|
||||||
|
|
||||||
|
const out = composeContract('pi', fixture.home);
|
||||||
|
|
||||||
|
expect(out).toContain(AGENTS);
|
||||||
|
expect(out).not.toContain('# User Profile');
|
||||||
|
});
|
||||||
|
|
||||||
it.each(['claude', 'codex', 'opencode', 'pi'] as const)(
|
it.each(['claude', 'codex', 'opencode', 'pi'] as const)(
|
||||||
'never injects installed TOOLS.md through a target symlink for %s',
|
'never injects installed TOOLS.md through a target symlink for %s',
|
||||||
(runtime) => {
|
(runtime) => {
|
||||||
|
|||||||
@@ -51,12 +51,11 @@ function installedEntryExists(path: string): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Secure point-of-use read for a top-level identity contract. */
|
/** Secure fleet point-of-use read for a top-level identity contract. */
|
||||||
export function readOptionalInstalledIdentityContract(
|
export function readInstalledIdentityContractAtPointOfUse(
|
||||||
mosaicHome: string,
|
mosaicHome: string,
|
||||||
entry: (typeof FLEET_IDENTITY_DEFAULTS)[number],
|
entry: (typeof FLEET_IDENTITY_DEFAULTS)[number],
|
||||||
required: boolean = false,
|
): Buffer {
|
||||||
): Buffer | undefined {
|
|
||||||
const configuredPath = join(mosaicHome, entry);
|
const configuredPath = join(mosaicHome, entry);
|
||||||
try {
|
try {
|
||||||
// Preserve the launcher's established support for a symlinked Mosaic home,
|
// Preserve the launcher's established support for a symlinked Mosaic home,
|
||||||
@@ -68,7 +67,6 @@ export function readOptionalInstalledIdentityContract(
|
|||||||
maxBytes: MAX_IDENTITY_CONTRACT_BYTES,
|
maxBytes: MAX_IDENTITY_CONTRACT_BYTES,
|
||||||
}).content;
|
}).content;
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (!required && isFilesystemError(error, 'ENOENT')) return undefined;
|
|
||||||
throw unsafeIdentityError('installed', configuredPath, error);
|
throw unsafeIdentityError('installed', configuredPath, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -317,6 +317,23 @@ describe('fleet unattended first start (#1264)', () => {
|
|||||||
expect(existsSync(join(fixture.mosaicHome, 'USER.md'))).toBe(false);
|
expect(existsSync(join(fixture.mosaicHome, 'USER.md'))).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.each(['', ' ', '\t'])(
|
||||||
|
'refuses explicit blank ambient fleet class %j before seeding',
|
||||||
|
(agentClass: string) => {
|
||||||
|
const fixture = createGreenfieldFixture();
|
||||||
|
|
||||||
|
const result = launchSync(fixture, { agentClass });
|
||||||
|
const output = outputOf(result);
|
||||||
|
|
||||||
|
expect(result.status, output).toBe(1);
|
||||||
|
expect(output).toContain('Refusing split identity authority');
|
||||||
|
expect(output).not.toContain('Running setup wizard');
|
||||||
|
expect(existsSync(fixture.capturePath)).toBe(false);
|
||||||
|
expect(existsSync(join(fixture.mosaicHome, 'SOUL.md'))).toBe(false);
|
||||||
|
expect(existsSync(join(fixture.mosaicHome, 'USER.md'))).toBe(false);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
it.each([' unattended-seat', 'unattended-seat ', ''])(
|
it.each([' unattended-seat', 'unattended-seat ', ''])(
|
||||||
'refuses non-exact ambient fleet name %j before seeding',
|
'refuses non-exact ambient fleet name %j before seeding',
|
||||||
(agentName: string) => {
|
(agentName: string) => {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import { readPersonaContractBlock } from '../fleet/persona-contract.js';
|
|||||||
import { canonicalizeRoleClass } from './fleet-personas.js';
|
import { canonicalizeRoleClass } from './fleet-personas.js';
|
||||||
import { launchClaudex, type ClaudexHarnessAdapter } from './claudex.js';
|
import { launchClaudex, type ClaudexHarnessAdapter } from './claudex.js';
|
||||||
import {
|
import {
|
||||||
readOptionalInstalledIdentityContract,
|
readInstalledIdentityContractAtPointOfUse,
|
||||||
seedFleetIdentityDefaults,
|
seedFleetIdentityDefaults,
|
||||||
} from './fleet-first-start-identity.js';
|
} from './fleet-first-start-identity.js';
|
||||||
import { runLeaseEnforcementDoctorCheck } from './lease-doctor-check.js';
|
import { runLeaseEnforcementDoctorCheck } from './lease-doctor-check.js';
|
||||||
@@ -236,7 +236,7 @@ function checkRuntime(cmd: string): void {
|
|||||||
|
|
||||||
function assertAmbientFleetClassMatches(canonicalName: string, canonicalClass: string): void {
|
function assertAmbientFleetClassMatches(canonicalName: string, canonicalClass: string): void {
|
||||||
const configuredClass = process.env['MOSAIC_AGENT_CLASS'];
|
const configuredClass = process.env['MOSAIC_AGENT_CLASS'];
|
||||||
if (!configuredClass?.trim()) return;
|
if (configuredClass === undefined) return;
|
||||||
|
|
||||||
const ambientClass = canonicalizeRoleClass(configuredClass).canonicalClass;
|
const ambientClass = canonicalizeRoleClass(configuredClass).canonicalClass;
|
||||||
if (ambientClass !== canonicalClass) {
|
if (ambientClass !== canonicalClass) {
|
||||||
@@ -583,20 +583,21 @@ For required push/merge/issue-close/release actions, execute without routine con
|
|||||||
parts.push(readFileSync(join(mosaicHome, 'AGENTS.md'), 'utf-8'));
|
parts.push(readFileSync(join(mosaicHome, 'AGENTS.md'), 'utf-8'));
|
||||||
|
|
||||||
// USER.md (+ USER.local.md operator overlay, appended directly under the
|
// USER.md (+ USER.local.md operator overlay, appended directly under the
|
||||||
// profile its base owns).
|
// profile its base owns). Fleet first start is Linux/systemd-owned and uses
|
||||||
|
// the no-follow reader at point of use. Standalone launches retain the
|
||||||
|
// portable tolerant path used on macOS and other supported hosts.
|
||||||
|
const fleetAgentName = process.env['MOSAIC_AGENT_NAME'];
|
||||||
const user =
|
const user =
|
||||||
readOptionalInstalledIdentityContract(
|
fleetAgentName === undefined
|
||||||
mosaicHome,
|
? readOptional(join(mosaicHome, 'USER.md'))
|
||||||
'USER.md',
|
: readInstalledIdentityContractAtPointOfUse(mosaicHome, 'USER.md').toString('utf8');
|
||||||
process.env['MOSAIC_AGENT_NAME'] !== undefined,
|
|
||||||
)?.toString('utf8') ?? '';
|
|
||||||
if (user) parts.push('\n\n# User Profile\n\n' + user);
|
if (user) parts.push('\n\n# User Profile\n\n' + user);
|
||||||
const userLocal = readOptional(join(mosaicHome, 'USER.local.md'));
|
const userLocal = readOptional(join(mosaicHome, 'USER.local.md'));
|
||||||
if (userLocal.trim()) {
|
if (userLocal.trim()) {
|
||||||
parts.push('\n\n## Operator Overlay (USER.local.md)\n\n' + userLocal);
|
parts.push('\n\n## Operator Overlay (USER.local.md)\n\n' + userLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fleetIdentity = resolveFleetIdentity(mosaicHome, process.env['MOSAIC_AGENT_NAME']);
|
const fleetIdentity = resolveFleetIdentity(mosaicHome, fleetAgentName);
|
||||||
if (!fleetIdentity.ok) {
|
if (!fleetIdentity.ok) {
|
||||||
throw new Error(`Fleet communications contract unavailable: ${fleetIdentity.error}`);
|
throw new Error(`Fleet communications contract unavailable: ${fleetIdentity.error}`);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user