## User
- **User:** Howard Enos (howard)
- **Machine:** Howard-Home
- **Role:** tech

## Session Summary

Worked on the `synology` skill end-to-end, taking it from `[PLUMBED]` (coded to spec,
never run against the device) to fully live-verified against the Cascades NAS
(cascadesDS, DS718+, 192.168.0.120) with the site VPN up. The session began with a
single `test` call to confirm the Web API client could authenticate and discover the
device, then expanded to exercising the complete command surface and proving the write
path.

First exercised the full read surface via both backends. All Web API read commands
(`test`, `apis`, `sysinfo`, `util`, `storage`, `shares`, `users`, `groups`, `packages`,
`services`, `connections`, `ls` share-roots, `call`) and the SSH backend (`info`, `df`,
`run` including privileged `sudo`/`synowebapi`) were confirmed working. This surfaced
four bugs that were fixed in place.

After confirming reads, the focus moved to the write/setter path — the last unverified
capability and the one the user explicitly wanted proven ("full control so you can make
the needed changes when needed"). A safe, self-reverting round-trip was chosen: create a
hidden throwaway shared folder, verify it appears, delete it, verify it is gone. Both
mutating calls passed CSRF (synotoken) end-to-end and the device was left pristine,
proving the write path works for create and delete (directly relevant to the user's
migration goal which centers on shares/permissions/users).

Documentation was updated throughout: SKILL.md status moved from PLUMBED to VERIFIED with
per-command results and the write-path confirmation; the Cascades wiki gained the NAS
device specs (resolving the model/RAM/DSM TODO in the network-logging plan). Work was
committed in four commits as it progressed.

The user clarified the larger migration (Drive<->CS-SERVER 2-way sync, migrate domain
users to CS-SERVER shares, retire the Synology sync) is NOT being executed now — this
session was solely about verifying the skill has the capability to do that work when
called upon. That capability is now confirmed.

## Key Decisions

- Placed the session log under `clients/cascades-tucson/` (not general skill logs) because
  all verification ran against cascadesDS and the work serves the Cascades migration.
- Chose a **share create+delete** round-trip to prove the write path rather than re-setting
  an existing setting: creating a new throwaway share cannot harm production config, whereas
  read-modify-write on an existing share risks dropping a field. Also the most relevant
  capability to the user's stated shares/permissions migration goal.
- Used the on-box `synowebapi --exec` (via SSH, golden rule #5) as the authority to diagnose
  the FileStation `list` failure rather than guessing param encodings from the Web API.
- Did NOT execute the actual migration — user confirmed this was a capability test only.

## Problems Encountered

- **`services` returned error 103** (`SYNO.Core.Service.list` method does not exist on DSM
  7.2.1). Probed methods; correct method is `get` (returns `{"service":[...]}`). Fixed.
- **`apis | head` raised a `BrokenPipeError` traceback.** Added top-level BrokenPipeError
  handler that closes stdout and exits cleanly.
- **`ls <folder>` (FileStation `list`) returns 400 via Web API / 407 on-box.** Confirmed
  on-box as SYSTEM_ADMIN that the built-in admin account lacks FileStation file privileges —
  a device permission state, not a skill bug. `list_share` (share roots) works. Made `ls`
  catch the 400/407 and print an SSH file-browse hint; real file browsing goes through the
  SSH backend (`run "ls -la /volume1/<share>/<subpath>"`).
- **`--confirm`/`--vault` after the subcommand were rejected by argparse** — meaning every
  documented gated-write example (`call X set k=v --confirm`, `pkg-start <id> --confirm`)
  would have failed. Moved both flags to a shared parent parser with SUPPRESS defaults so
  they work before AND after the subcommand. This was the most impactful fix — without it no
  write command worked as documented.
- **MSYS path-mangling** rewrote a bare `ls /Public` argument to `/Public` ->
  `C:/Program Files/Git/Public` before Python saw it (Windows friction). Logged to errorlog
  (--friction, ref feedback_tmp_path_windows). The `call ... folder_path=/x` form is not
  mangled; FileStation 407 denial blocks the path regardless.

## Configuration Changes

Modified:
- `.claude/skills/synology/scripts/syno_client.py` — services method `list`->`get`;
  BrokenPipeError handler; `ls <folder>` 400/407 graceful SSH hint; argparse refactor
  (shared parent parser for `--confirm`/`--vault`, works in either position).
- `.claude/skills/synology/SKILL.md` — status PLUMBED -> VERIFIED; per-command results;
  SSH backend results; FileStation `ls` limitation; write-path VERIFIED with share-create
  signature; list of live fixes.
- `wiki/clients/cascades-tucson.md` — added NAS device-specs line to the Synology section;
  resolved the "Confirm Synology model/RAM/DSM before build" TODO in the network-logging plan.
- `errorlog.md` — auto-appended API 103 entries during method probing + one --friction entry
  for the MSYS `ls` path-mangling.

No changes left to the device: the test share `synowritetest_del` was created and deleted;
cascadesDS config is unchanged.

## Credentials & Secrets

No new credentials discovered or created. Used the existing vaulted admin credential at
`clients/cascades-tucson/synology-cascadesds.sops.yaml` (fields host / port /
credentials.username / credentials.password) for both Web API and SSH auth. Not displayed.

## Infrastructure & Servers

- **cascadesDS (Synology NAS):** 192.168.0.120, DSM Web API on :5000 (http), SSH enabled.
  Model **DS718+**, **DSM 7.2.1-69057 Update 11**, **6 GB RAM** (5924876 kB), serial
  **1920PEN537202**, CPU Intel Celeron J3455 (4 cores @ 1.5GHz), sys temp ~40C, timezone
  Arizona, NTP server time.nist.gov. Hostname CascadesDS, model string
  synology_apollolake_718+.
- **Filesystem:** ext4 (NOT Btrfs). volume1 = `/dev/mapper/cachedev_0`, 913G total, 389G
  used, 525G avail (43%). 2x WD10EZEX 1 TB drives (sda WD-WCC3F4HXHDFF, sdb), both normal.
- **Shares (10):** homes, home, Public, SalesDept, Server, Management, plus hidden
  Activities, chat, pacs, Sandra Fish, web. Several in Windows-ACL mode (is_aclmode).
- **Users:** 41 local. **Groups (4):** administrators, http, MainOffice, users.
- **Packages (30 running):** incl. Active Backup for Business 3.1.0-24967 (running on ext4 —
  only ABB dedup/self-healing needs Btrfs), Synology Drive Server 3.5.0-26088, Synology Chat
  2.4.6, VPN Server 1.4.9, Hybrid Share 1.4.1, File Station, SMB Service 4.15.13.
- Reachable only with the Cascades site VPN up.

## Commands & Outputs

```bash
PY="$PWD/.claude/scripts/py.sh"; S=".claude/skills/synology/scripts/syno_client.py"
X=".claude/skills/synology/scripts/syno-ssh.sh"

# read verification
bash "$PY" "$S" test            # ok: DS718+, DSM 7.2.1-69057 U11, 6144 MB
bash "$PY" "$S" services        # FIXED: now uses `get` (was `list` -> 103)
bash "$PY" "$S" apis service    # confirmed SYNO.Core.Service maxVersion 3, method=get

# FileStation list diagnosis (denied for admin)
bash "$PY" "$S" call SYNO.FileStation.List list folder_path=/Public   # -> 400
# on-box authority:
bash "$X" run "echo '<pw>' | sudo -S -p '' /usr/syno/bin/synowebapi --exec \
  api=SYNO.FileStation.List method=list version=2 folder_path='\"/Public\"'" --confirm
  # -> {"error":{"code":407}}  (operation not permitted, even as SYSTEM_ADMIN)
bash "$X" run "ls -la /volume1/Public/Documents" --confirm   # SSH fallback works

# write-path round-trip (CSRF proven, device left pristine)
bash "$PY" "$S" call SYNO.Core.Share create name=synowritetest_del \
  'shareinfo:={"name":"synowritetest_del","vol_path":"/volume1","desc":"...","enable_recycle_bin":false,"hidden":true}' \
  --confirm                                  # -> {"name":"synowritetest_del"}
bash "$PY" "$S" call SYNO.Core.Share delete name=synowritetest_del --confirm  # -> {"success":true}

# argparse fix verification
bash "$PY" "$S" call SYNO.Core.Share create name=x   # gate: blocked w/o --confirm (correct)
bash "$PY" "$S" test --confirm                       # --confirm AFTER subcommand now accepted
bash "$PY" "$S" --confirm test                       # --confirm BEFORE subcommand still accepted
```

## Pending / Incomplete Tasks

- **Migration (NOT started — capability test only this session).** End goal per Howard:
  1) map Synology Drive to CS-SERVER for 2-way sync, 2) migrate domain users onto CS-SERVER
  shares, 3) end the Synology sync so all users are on CS-SERVER. All required capabilities
  (share create/modify, share permissions, users/groups, package/service control) are now
  verified reachable + writable via the skill. Awaiting explicit go.
- **Session-expiry re-login (106/119)** not forced live (would need an expired SID); auth/
  CSRF/setter plumbing otherwise proven.
- **Log Center package** not yet confirmed installed on cascadesDS — check `apis logcenter`
  before the network-logging-plan build.
- Optional: consider granting the admin account FileStation file privileges if Web API file
  browsing is ever wanted (currently SSH-only).

## Reference Information

- Skill files: `.claude/skills/synology/{SKILL.md,scripts/syno_client.py,scripts/syno-ssh.sh,references/dsm-api.md}`
- Vault: `clients/cascades-tucson/synology-cascadesds.sops.yaml`
- Commits this session:
  - `7173f4d` synology: live-verify against cascadesDS, fix services method + pipe handling
  - `fc36f98` synology: full read-surface sweep + FileStation ls graceful fallback
  - `21ef1f2` synology: fix --confirm arg position + verify write path live
- On-box synowebapi path: `/usr/syno/bin/synowebapi` (root only, mode 0700)
- FileStation error codes seen: 400 (invalid param / web-api translation), 401 (unknown file
  op), 407 (operation not permitted), 408 (no such file).
- Wiki: `wiki/clients/cascades-tucson.md` (Synology NAS section + network-logging plan).
