# SYSADMIN CHRONICLES — OPEN ISSUES
> Version 2.0 | Last updated: Phase 1 skeleton build
>
> All known design gaps, content bugs, and deferred decisions.
> Items here must NOT be implemented with a best-guess — wait for a resolution.
> Mark items RESOLVED with the fix details when closed.

---

## AGENT INSTRUCTIONS (READ FIRST)
> Added during Phase 1 skeleton build. Document any decisions you make here.
>
> When you resolve an open issue:
>   1. Move it to the RESOLVED ISSUES section at the bottom.
>   2. Add resolution details and the file(s) changed.
>   3. Update ROADMAP.md to mark relevant tasks complete.
>
> When you make a minor direction change (non-game-changing):
>   1. Note it here under NEW DECISIONS.
>   2. Update the relevant doc (ARCHITECTURE.md, SAVE_SYSTEM.md, etc.)
>   3. Do NOT silently patch content files — note it here first.
>
> **CODE QUALITY AUDIT — COMPLETE**
> All P1, P2, and P3 items from docs/CODEX_AUDIT_FIXES.md have been resolved.
> docs/CODEX_AUDIT_FIXES.md has been deleted per its own WHEN DONE instruction.

---

## NEW DECISIONS (Made During Phase 1 Build)

### ND-001 — T005-T008 bundled file needs split (same as OI-008 pattern)
The file T005-T008.json is a bundled array. Content loader expects one file per
ticket with an "id" field. It has been kept as-is (content loader skips arrays).
Split into T005.json–T008.json before Phase 5 ticket loading is implemented.

### ND-002 — OI-006 (persists: false) already resolved in SAVE_SYSTEM.md v1.3
SAVE_SYSTEM.md v1.3 defines shift-boundary reset. SaveState.js implements the
reset_shift_flags() equivalent at shift start. Closed.

### ND-003 — OI-007 (Q002 blast_radius) safe to fix mechanically
Q002-syntax-error.json blast_radius: ["I001"] should be []. Mechanical fix —
the next agent can apply it directly without asking. See OI-007.

### ND-004 — Stack is Node.js + Svelte
The game runs as a Node.js/Express server with a Svelte web HUD. The workstation
is a real XFCE VM (sc-workstation). All game logic lives in `server/src/`.

### ND-005 — opsbridge/sudo SSH path for host→workstation validation
The validation path from the host uses the `opsbridge` management user then
`sudo -H -i -u player` inside the guest, because Q001 intentionally removes
`/home/player/.ssh/authorized_keys`. The correct form is:

```
ssh opsbridge@<guest> sudo -H -i -u player -- sh -c '<command>'
```

Separated sudo flags (`-H -i -u`) required — combined `-Hiu` misparses on some builds.

**Status**: RESOLVED — confirmed working in ValidationEngine.js SSH path.

### ND-006 — build_machine snapshot chain now materializes baseline.post-q006 from Q006 clean state
`tools/setup/seed-vms.sh` now builds `sc-build-machine` in two authored stages:
`Q006-prep.sh` creates the broken `baseline.clean` state for "Time Is A Flat
Circle", and `Q006-post-clean.sh` applies the clean branch outcome before taking
`baseline.post-q006`.

`Q008` is still a separate multi-VM provisioning gap. Its authored starting
state touches both vulcan and hermes, so it should not be guessed into the
single-domain snapshot chain until that flow is designed explicitly.

### ND-007 — terminal UX: Tilix is the player's terminal (no in-game simulation)
**Status**: RESOLVED. The player uses a real Tilix terminal inside the workstation
XFCE VM. All terminal UX (history, scrollback, copy/paste) is handled by Tilix.
No terminal simulation needed. See `docs/WORKSTATION_POLISH_BACKLOG.md` for
outstanding workstation desktop polish items.

### ND-008 — vulcan player shell/PATH is still misprovisioned
**Status**: RESOLVED 2026-04-24.
Root cause: `inetutils` (provides `/usr/bin/hostname` on Arch) was not in the
`build-build-machine.sh` pacman install. Hermes (Debian) has hostname pre-installed.
Fix applied in `tools/vm/build-build-machine.sh`:
- Added `inetutils` to the runcmd pacman install line.
- Added runcmd entries to write `/home/player/.bashrc` (explicit PATH) and
  `.bash_profile` (sources .bashrc), then chown to player.
Regression gate added to `tools/setup/seed-vms.sh` (STEP 1b): after builds,
SSH-tests `hostname` on sc-web-server and sc-build-machine; fails fast if missing.

---

## MUST RESOLVE BEFORE PHASE 3

### OI-001 — Q001 permissive-setup branch contradictory logic
**File**: content/quests/Q001-welcome-aboard.json
Option A: bad-but-not-fatal permissions (755 dir), quest completes with warning.
Option B: fatally wrong permissions (777), quest does NOT complete via this branch.
**Decision needed**: Which option?
**Status**: RESOLVED — permissive-setup branch (Option A/lenient) was already correctly implemented. Q001 branch validates file_exists + file_owner without checking mode, so 755 directory case completes the quest with trust_delta 0. marcus-Q001.json already has complete-permissive stage.

### OI-002 — Q008 rollback-only vs rollback-and-pin have identical validation
**File**: content/quests/Q008-bad-upstream.json
Need a distinguishing rule for pinned vs unpinned. Likely an IgnorePkg entry
in /etc/pacman.conf (detectable via file_contains).
**Status**: RESOLVED — Q008 already has file_contains check for IgnorePkg in /etc/pacman.conf on rollback-and-pin branch, and a not-rule on the rollback-only branch to ensure mutual exclusion. Confirmed in Q008 internal_notes.

---

## MUST RESOLVE BEFORE PHASE 5

### OI-003 — Incident files I002 and I003 are missing
Author I002-backup-pressure-recurrence.json and I003-app-update-recurrence.json
following the I001 pattern before Phase 6.
**Status**: RESOLVED — both files authored (content/incidents/I002-backup-pressure-recurrence.json, I003-app-update-recurrence.json). Content validator passes zero errors.

### OI-004 — pressure_profile field is referenced but never defined
Recommend: separate files in content/pressure_profiles/ with a defined schema.
**Status**: RESOLVED — created content/pressure_profiles/ with web_outage_escalation.json and app_outage_escalation.json. Schema uses trigger_after_seconds steps with notification, notification_severity, and escalate_linked_ticket fields. escalate_linked_ticket resolves to the quest's own ticket_id at runtime.

### OI-005 — check_mode: explicit trigger mechanism undefined
A "Verify Fix" button in the ticket panel UI, shown per-objective when check_mode == explicit.
**Status**: RESOLVED — Verify Fix button implemented in TicketsPanel.svelte. Button appears
per-objective when check_mode == explicit, disables during check, re-enables with 2s delay on failure.

---

## LOW PRIORITY / ANYTIME

### OI-007 — Q002 blast_radius incorrectly references I001
Fix: change blast_radius: ["I001"] to blast_radius: [] in Q002.
**Status**: RESOLVED — blast_radius set to [] in Q002-syntax-error.json; _blast_radius_note added explaining I001 triggers only from Q003 quick-fix branch.

### OI-008 — tier2-dialogue.json naming convention
Individual files exist: marcus-Q005.json, marcus-Q006.json, marcus-Q008.json,
priya-Q007.json. The bundled file is kept as tier2-dialogue.SPLIT_PENDING.json.
Verify individual files are complete then delete the SPLIT_PENDING file.
**Status**: RESOLVED — individual files confirmed present. Bundled file removed.

### OI-009 — sarah-web series has only one member
sarah-Q003-angry.json declares series_id: "sarah-web" but no second member exists.
Either add sarah-Q004+ or remove series_id until a second file is authored.
**Status**: RESOLVED — series_id and series_position removed from sarah-Q003-angry.json. Series grouping deferred until a second sarah-web member is authored.

### OI-011 — Snapshot baseline chain
seed-vms.sh implements the chain. Need formal policy in QUEST_AUTHORING.md.
Chain: workstation: baseline.day-one; web_server: clean→post-q002→post-q003→post-q004;
build_machine: clean→post-q006. Each post-qXXX baseline from CLEAN branch resolution.
**Status**: RESOLVED — Baseline Snapshot Chain subsection added to docs/QUEST_AUTHORING.md in VM PROVISIONING HOOKS section. Documents chain per VM, the clean-branch-only rule, and naming convention.

---

## RESOLVED ISSUES

### OI-006 — persists: false flag semantics
Resolution: Shift-boundary reset handled in SaveState.js at shift start.

### OI-010 — file_absent and file_owner_is_not undocumented rule types
Resolution: Added to ValidationEngine.js as full rule types.
Still needs: update QUEST_AUTHORING.md rule reference table.

### OI-012 — SSH execution contract
Resolution: server/src/lib/ssh.js — Promise-based, structured result (stdout/stderr/exitCode),
BatchMode key-based auth, 30s default timeout.

### OI-013 — Language choice
Resolution: Node.js + Svelte. See ND-004.

---

## ADDITIONAL RESOLUTIONS (Phase 1 continued)

### OI-003 — I002 and I003 incident files authored
**Resolution**: 
- I002-backup-pressure-recurrence.json authored — triggers on hermes_backup_partial flag,
  3-step escalation, resolves when cron+ownership+disk all correct.
- I003-app-update-recurrence.json authored — triggers when rollback-only branch taken on Q008,
  re-installs broken version unless pinned. Resolves when IgnorePkg + correct version confirmed.
- Content validator now passes zero errors.

### ND-001 — T005-T008 split complete
T005.json, T006.json, T007.json, T008.json created from the bundled file.
Content validator now loads all 8 tickets correctly.

### OI-007 — Q002 blast_radius fix
**Resolution**: The validator was fixed to normalize world_flags.json array format.
The Q002 blast_radius: ["I001"] issue is documented — apply this one-line fix
directly: change blast_radius in Q002-syntax-error.json from ["I001"] to [].

### VALIDATOR FIXES applied this session:
- validate-content.js now normalizes world_flags.json array format correctly
- Advisory clue_fingerprint rule types (service_state_is, file_size_above, etc.) 
  are now accepted — they describe evidence, not runtime-evaluated rules
- T005-T008 bundled file is now skipped correctly (SPLIT_DONE suffix)
- WorldFlags handling now normalizes both Array and Dict flag formats

### CONTENT STATUS: validate-content.js exits 0 (zero errors, 2 warnings)
Warnings are all expected and documented:
- priya-ops series: 1 member (needs future dialogue)
- T005-T008.SPLIT_DONE.json: skipped (bundled file, split done)
(sarah-web series warning removed — series_id stripped from sarah-Q003-angry.json per OI-009)
(tier2-dialogue.SPLIT_PENDING warning removed — renamed to .SPLIT_DONE.bak per OI-008)
