test(installer): preregister P0-P9 greenfield RED

This commit is contained in:
2026-08-05 17:46:58 -05:00
parent 85d2108e4e
commit 4904d4553c
4 changed files with 474 additions and 163 deletions
+33
View File
@@ -1368,3 +1368,36 @@ All work is **alpha** (< 0.1.0) until Jason approves 0.1.0 beta release.
10. ASSUMPTION: **Conversations and messages get their own PG tables** (not stored in brain's entity model). They follow a chat-specific schema with proper foreign keys to users and projects. Rationale: Chat has different access patterns (streaming, pagination, search) than brain entities.
11. RESOLVED: **Pi handles all target LLM providers natively.** Anthropic, OpenAI/Codex, Z.ai, Ollama, LM Studio, and llama.cpp are all supported via Pi's built-in providers or `models.json` configuration with `openai-completions` API type. No custom provider adapters needed in @mosaicstack/agent — only configuration management.
---
## Greenfield install correctness — C1 (#1050)
### Problem and objective
A from-zero install can report success while leaving the target host unusable because the installer has no transactional state machine capable of certifying its own postconditions. C1 supplies the structural spine and red-first fixture; later cards repair the individual failed postconditions.
### Normative requirements
1. The installer SHALL implement the canonical P0P9 numbering from the greenfield-install PRD v2: P0 Resolve context; P1 Preflight; P2 Acquire artifacts; P3 Install CLI; P4 Install framework + skills; P5 Identity; P6 Runtime linking / activation; P7 Services; P8 Shell discoverability; P9 Verify + commit.
2. Every phase SHALL declare preconditions, action, committed postconditions, and rollback. An unverifiable postcondition SHALL fail the install non-zero with the named phase and a remediation line; no best-effort failure may still certify success. P1's required-tool closure includes tools invoked by later phases, including `git`; a downstream prerequisite may not remain undeclared and degrade silently.
3. A durable mutation journal SHALL open before the first mutation and commit at P9. Fallible command output needed to diagnose a phase SHALL be journaled and surfaced, never discarded.
4. `--check` SHALL run exactly the P0P8 postcondition predicates without mutation, report each phase PASS/FAIL, and exit non-zero if any predicate fails.
5. P4 SHALL consume a checkout-free, lane/versioned shipped-set declaration published by the installer. C1 SHALL NOT select among the currently disagreeing framework-payload, repository-root, sync-source, and W-jarvis populations; while no declaration exists, P4 reports `NOT-MEASURED / UNDECLARED` and remains blocking rather than fabricating a count. C5 owns the declaration's contents and containment/loadability fulfillment.
6. The from-zero fixture SHALL be lane-parametric, use Debian/glibc, run the documented install command as a non-root target user with an isolated HOME, and inherit no host credentials, npm cache, home directory, or runtime configuration.
7. The fixture SHALL select `next` with `--next` or `MOSAIC_NEXT=1` and assert the resolved lane version. Internal predicates use P3's absolute CLI path; shell discoverability is tested only at P8.
8. Fault injection after each P2P8 phase SHALL prove either clean rollback or a durable, honestly reported resumable partial state, with no journal incorrectly left in progress.
9. Unsupported musl/Alpine and unavailable Docker SHALL fail loudly rather than skip as pass.
### C1 acceptance criteria
1. The pre-C1 from-zero matrix records both discriminating controls: with `git` absent, the legacy installer still exits zero while P1 fails and skill sync degrades; with `git` present, P1 passes and the observed sync store/runtime links are 101/101. The C1 installer must fail at P1 before mutation when `git` is absent.
2. The discriminating P3 row passes: the binary exists at the expected absolute path and reports exactly the resolved `next` lane version, while P4, P5, and P8 fail.
3. The `--check` mutation negative control proves host fingerprints are byte-identical before and after observation.
4. Woodpecker executes and validates the expected RED fixture; C1 does not repair P4/P5/P8 or activate #869.
### Explicit exclusions and dependencies
- C2 owns P8/PATH, C3 owns P5/headless identity, C4 owns P6 activation policy, and C5 owns P4/skills.
- Main-lane execution is a promotion precondition owned by #1037; C1 only makes the fixture lane-parametric.
- RM-02 and #869 activation are out of scope.
@@ -0,0 +1,62 @@
# #1050 — Installer P0P9 state machine and red-first fixture
## Objective
Implement C1 from the canonical greenfield-install PRD v2: a transactional P0P9 installer spine, a side-effect-free P0P8 `--check`, and a lane-parametric Debian/glibc non-root from-zero fixture. The acceptance milestone is an attributable RED on the pre-C1 installer while preserving P3 PASS.
## Authority and scope
- Canonical requirements: `jason.woltje/jarvis-brain` `docs/plans/2026-08-04-greenfield-install-blockers-PRD-v2.md`, read from local `origin/main` object `b2b6ed41f5aff5ea964e69b7c701cb45718742fa`; remote currency is **unestablished** because authenticated fetch returned repository-not-found.
- Tracking: `mosaicstack/stack#1050` on `git.mosaicstack.dev` (author read back as `be-coder-05`).
- Base: `origin/next` `4df478cdd150fdf8d52ea109f02ade5d85017acd`.
- Out of scope: PATH, skills, headless wizard/identity, activation remediation, #869 wiring, RM-02, main promotion.
- `docs/TASKS.md` is orchestrator-single-writer and is not modified by this worker.
## Plan
1. Pre-register the canonical phase/output/side-effect-free/fault-injection checks and observe RED against the base installer.
2. Commit the immutable red-first acceptance fixture before implementation.
3. Add the state-machine/journal/postcondition spine without repairing P4/P5/P8 symptoms.
4. Wire the expected-RED from-zero fixture into Woodpecker using Debian/glibc and a non-root target user.
5. Run shell/static baselines, situational container validation, code review, security review, then deliver through a PR to `next` under the coordinator-owned merge path.
## Budget
- Working estimate: 32K reasoning/output tokens.
- Hard external cap: none stated.
- Adaptation: keep implementation in shell surfaces already in scope; no package dependency install unless repository gates require it.
## Pre-registered acceptance checks
| ID | Exact case | Expected pre-fix result |
|---|---|---|
| C1-R1 | `tools/e2e-install-test.sh --lane next` in a clean Debian 12 container as uid 1001 | non-zero; P3 PASS; P4 `NOT-MEASURED / UNDECLARED`; P5/P6/P8 FAIL with own reasons |
| C1-R2 | `tools/install-state-machine.test.sh` phase table case | RED because base installer does not enumerate canonical P0P9 contracts |
| C1-R3 | side-effect-free `--check` case over a fingerprinted HOME | RED because base `--check` is version-only rather than P0P8 predicates |
| C1-R4 | fault injection after each P2…P8 | RED because base installer has no injectable durable journal/rollback state |
| C1-R5 | Docker unavailable | base harness incorrectly exits 0; replacement must fail non-zero |
| C1-R6 | lane resolution | bare checkout is forbidden; fixture must pass `--next` and assert the resolved prerelease version |
| C1-R7 | same Debian fixture with `git` absent vs present | absent: P1 FAIL while legacy installer exits 0 and sync degrades; present: P1 PASS and observed store/runtime containment 101/101 |
## Progress
- [x] Charter, doctrine, delivery/CI/QA/docs guides read.
- [x] Canonical PRD v2 and charters read from local origin object; numbering reconciles with the TL spec. No numbering conflict found. TL additions (early durable journal and INV-C) are additive, not contradictory.
- [x] Target base reachability verified with `merge-base --is-ancestor`.
- [x] Issue #1050 created and provider author read back.
- [x] Initial RED captured; TL rejected P4's repo-root count as a false RED. Four populations disagree (framework payload 1, repo root 13, sync store 101 in the fixture, W-jarvis observation 7), so C1 now requires a checkout-free declared shipped-set artifact and reports P4 `NOT-MEASURED / UNDECLARED` until C5 supplies it.
- [x] P6 strengthens #869: the two dead enforcement hooks reproduce from zero on a clean broker-less container. C1 asserts the breach but neither wires nor unwires it.
- [x] P1 false pass identified from the P4 evidence row: `git` is absent from the Debian base and was undeclared even though skill sync shells out to it. C1 adds `git` to P1; the fixture matrix preserves absent/present controls. The prior claim that web1's missing runtime skills reproduce this greenfield mechanism is withdrawn by the TL and is not carried here.
- [ ] Corrected RED transcript captured and reported.
- [ ] State machine implemented.
- [ ] Reviews complete.
## Risks / blockers
- The deployed create wrappers do not expose `--dry-run`; identity preflight was performed through `pr-merge.sh --dry-run` on the same HOMELAB repo, which resolved `git.mosaicstack.dev` + `be-coder-05`. The issue create then fell back from tea to the API but provider read-back confirmed author `be-coder-05`.
- `next` is an integration lane; `main` promotion remains #1037-owned.
- #869 must remain staged and inactive.
## Verification log
(To be updated with exact commands and resulting objects.)