Files
stack/BUILD-LOG.md
T
jason.woltje c2365ae519 chore: baseline container POC and atomic foundation plan
- Containerized Pi hello-world proof (image mosaic-poc-agent:0.84.4, non-root)
- Four immutable contract fixtures loaded into a generated system prompt
- build/hello/verify/reset scripts with exact-match gating and reset safety
- Documented Pi discovery (v0.84.4, -p mode, --system-prompt, container auth)
- Append-only BUILD-LOG with corrections; deferred layers in LAYERS.md
- Architecture plan: docs/plans/2026-09-02_atomic-mosaic-foundation.md
2026-09-02 18:24:36 -05:00

8.9 KiB
Raw Permalink Blame History

BUILD-LOG

Append-only build log for the Minimal Mosaic Stack container proof of concept. Each phase records the plan before it runs and the observed result after it runs. No credentials are recorded in this file.


Phase 1: Pi package discovery

Entry 1.1 — before

  • Timestamp: 2026-02-02 (session start, local)
  • Intended action: Locate the current package documentation for @earendil-works/pi-coding-agent, determine the current version, the supported noninteractive command, the custom system prompt mechanism, and the documented container authentication method.
  • Reason: The brief forbids guessing CLI flags, authentication paths, or SDK methods; all runtime commands must be derived from the package documentation.
  • Expected result: Documented answers for all five discovery questions, recorded below, with the Pi package version pinned in the project.

Entry 1.2 — after

  • Timestamp: 2026-02-02
  • Commands run:
    • Read README.md of the locally installed @earendil-works/pi-coding-agent package
    • Read docs/containerization.md, excerpts of docs/models.md and docs/providers.md
    • grep '"version"' .../pi-coding-agent/package.json
    • npm view @earendil-works/pi-coding-agent version
    • Inspected host auth store structure (keys only, values never printed)
  • Observed result:
    1. Package documentation: full docs ship inside the installed package (README.md plus a docs/ directory including docs/containerization.md).
    2. Current package version: 0.84.4 — the locally installed version and the npm registry latest are identical. Selected version to pin: 0.84.4.
    3. Supported noninteractive command: pi -p / pi --print — "Print response and exit". Documented in the CLI Reference. Print mode also merges piped stdin into the initial prompt (not used here).
    4. Custom system prompt: documented CLI flag --system-prompt <text> — "Replace default prompt (context files and skills still appended)". Because the generated contract prompt must fully control behavior, the run also passes the documented discovery-off switches (--no-context-files, --no-skills, --no-extensions, --no-prompt-templates, --no-themes) so nothing is appended from ambient files. (APPEND_SYSTEM.md / .pi/SYSTEM.md file conventions exist but the CLI flag is the documented noninteractive path.)
    5. Documented container authentication: docs/containerization.md documents the "Plain Docker" pattern: run the whole pi process in the container and pass provider API keys at runtime via environment variables (example: docker run -e ANTHROPIC_API_KEY ...). The documented alternative credential store is auth.json written by /login under the pi agent directory (~/.pi/agent/auth.json).
  • Decision: supply the credential at runtime as a read-only mounted credential file (host auth.json, which contains a static API-key entry for the built-in zai provider) mounted at the container pi agent directory, and additionally allow the documented environment-variable path (ZAI_API_KEY / ANTHROPIC_API_KEY) as an alternative. Provider and model are non-secret settings supplied via .env (PI_PROVIDER=zai, PI_MODEL=glm-5.3-flash).
  • Failure or correction: none. Host check confirmed no API-key environment variables are exported on the host, so the read-only auth.json mount is the working runtime credential path for this experiment.

Phase 2: Project scaffold

Entry 2.1 — before

  • Timestamp: 2026-02-02
  • Intended action: Create the contract fixtures (exact brief contents), the contract loader (src/load-contracts.sh), the one-shot agent runner (src/run-agent.sh), the four required scripts (scripts/build.sh, hello.sh, verify.sh, reset.sh), Containerfile, compose.yaml, pinned package.json + package-lock.json, .gitignore, README.md, LAYERS.md.
  • Reason: Implement exactly the file set the brief requires, with no extra machinery (no schemas, overlays, manifests, or policy loading).
  • Expected result: A complete project whose only remaining unknown is whether the pinned image builds and the real model request returns MOSAIC_HELLO_OK.

Entry 2.2 — after

  • Timestamp: 2026-02-02
  • Commands run: file creation; npm install --package-lock-only --ignore-scripts to generate the lockfile from the pinned dependency.
  • Observed result: All files created; package-lock.json pins @earendil-works/[email protected] (exact, no range).
  • Failure or correction: none.

Phase 3: Container image build

Entry 3.1 — before

  • Timestamp: 2026-02-02
  • Intended action: Run scripts/build.sh (Docker Compose build) to produce image mosaic-poc-agent:0.84.4 from node:24-bookworm-slim with the pinned Pi, the four contract fixtures at /opt/mosaic/contracts, and a non-root user (uid/gid 1000).
  • Reason: Phase 1 of the required proof path; node:24-bookworm-slim is the maintained base image used in Pi's own documented containerization example.
  • Expected result: docker compose build exits 0 and the image contains the contracts, the runner scripts, and the pinned pi binary, with no credentials baked in.

Entry 3.2 — after

  • Timestamp: 2026-02-02
  • Commands run: scripts/build.sh; docker run --rm mosaic-poc-agent:0.84.4 --version; id via --entrypoint; contract listing; credential file scan.
  • Observed result:
    • Build exit 0; image tagged mosaic-poc-agent:0.84.4.
    • pi --version inside the image reports 0.84.4 (and this run also executed the contract loader successfully, writing /var/lib/mosaic/system-prompt.md).
    • Container user is uid=1000(node) gid=1000(node) — non-root.
    • All four contract files present at /opt/mosaic/contracts with read-only permissions (0555).
    • Credential scan: no auth.json or other auth files exist in the image; /home/node/.pi/agent/ is empty in the image.
  • Failure or correction:
    1. First build failed: Docker Compose expects Dockerfile by default; fixed by setting build.dockerfile: Containerfile in compose.yaml.
    2. Second build failed: useradd exit 4 (uid 1000 already exists) because the maintained node image ships a node user at uid/gid 1000. Fixed by reusing the built-in node user (same 1000:1000 host mapping) instead of creating a duplicate mosaic user; container paths updated from /home/mosaic/... to /home/node/... in Containerfile, compose.yaml, README.md, .env.example.

Phase 4: Runtime verification

Entry 4.1 — before

  • Timestamp: 2026-02-02
  • Intended action: Run scripts/hello.sh (one-shot request: "Return your startup marker and nothing else."), then scripts/verify.sh (exact-match gate against MOSAIC_HELLO_OK), then the negative test (EXPECTED_MARKER=MOSAIC_NOT_OK scripts/verify.sh must exit nonzero), then the scripts/reset.sh safety tests and a final rerun after reset.
  • Reason: Phases 27 of the required proof path plus acceptance criteria 511.
  • Expected result: hello prints only the marker; verify exits 0; negative test exits nonzero; reset refuses unsafe paths and succeeds on the real path; rerun after reset reproduces the success.

Entry 4.2 — after

  • Timestamp: 2026-02-02
  • Commands run: scripts/hello.sh; scripts/verify.sh; EXPECTED_MARKER=MOSAIC_NOT_OK scripts/verify.sh; scripts/reset.sh (refusal tests: missing marker, symlink with canary file, then real reset, then missing dir); scripts/build.sh && scripts/verify.sh after reset; docker compose config mount inspection.
  • Observed result:
    • hello.sh: stdout exactly MOSAIC_HELLO_OK — a real model request (provider zai, model glm-5.3-flash, auth via the read-only mounted auth.json credential file). The request string contains no marker.
    • verify.sh: PASS: response matches expected marker, exit 0.
    • Negative test: FAIL: response does not match expected marker (expected MOSAIC_NOT_OK, actual MOSAIC_HELLO_OK), exit 1.
    • reset.sh refusal tests: missing marker → exit 1, nothing deleted; symlink (with canary file at the target) → exit 1, canary survived; real path with marker → removed, exit 0; missing dir → "nothing to remove", exit 0.
    • Rerun after reset: build + verify → PASS, exit 0 (criterion 11).
    • Resolved compose mounts: only /home/jwoltje/.mosaic-dev → /var/lib/mosaic (rw) and ~/.pi/agent/auth.json → /home/node/.pi/agent/auth.json (read-only). No ~/.mosaic or ~/.config/mosaic mounts, no Docker socket.
  • Failure or correction:
    1. First hello run: the contract loader's status line was printed on stdout, mixing runtime data into the model response stream and contaminating the exact-match capture. Fixed by sending the loader's status message to stderr (src/load-contracts.sh), rebuilt the image, reran: stdout is exactly the model response.
  • Credential check: no credential material appears in this log, in hello/verify output, or in the image (image scan found no auth files).

Result

All 11 acceptance criteria demonstrated. The real model request passed.