Milestone = atomic vertical slice, 2–5 hari kerja (≈1–2 minggu weekday atau 1 blok weekend). Kriteria selesai testable; integration test di akhir tiap milestone. Branch per milestone.
Selesai bila: docs/ suite terisi (PROJECT, RESEARCH, ARCHITECTURE, DECISIONS, NFR, MILESTONES, CONTEXT);
CLAUDE.md ≤200 baris + symlink AGENTS.md; repo + .gitignore.
Status: hampir selesai. Stack di-lock 3 Jul (ADR-003/004 Accepted); ADR-010 (probe hybrid) LOCKED 3 Jul
malam (opsi #2 LS GetUserStatus interaktif ber-PTY terbukti — quotaInfo non-nil). Uji terminal 3 Jul: hook
StopFailure (TODO #7) selesai, probe agy item (d) selesai. Semua ADR terkunci kecuali ADR-001.
Sisa verifikasi (butuh limit/quota asli, non-blocking): fixture pesan limit lokal + varian agy TUI saat quota
habis (ADR-001, RESEARCH §6 TODO #2); residual probe agy #3/#1 = impl-tuning M3.
Slice: acca run -- <cli> men-spawn CLI target via PTY, mencatat tool/session-id/cwd/pid ke SQLite,
dan menampilkan output apa adanya.
Selesai bila: bisa menjalankan Claude Code & Antigravity CLI di bawah wrapper; sesi tercatat di store;
acca status menampilkan sesi RUNNING (empty state bila kosong). Integration test: run → exit normal → status EXITED.
Slice: kenali LIMIT_HIT — CC: hook StopFailure (primer) + pola output + exit code (print-mode) +
transcript; agy: pola output/exit — beserta kondisi proses (hidup|exit); isi reset_at (sinyal pasti →
heuristik → backoff, ditandai sumbernya).
Selesai bila: AC-1, AC-2 lulus dari fixture + hook event; false positive < 1/100 pada korpus uji;
overload (429/5xx/529) TIDAK terklasifikasi sebagai usage-limit.
Dependensi: fixture pesan limit + hasil uji hook (RESEARCH §6 TODO #2/#7).
Slice: jadwalkan lanjut; pada reset_at → probe kuota → lanjut sesuai kondisi proses (strategi ADR-014:
inject "continue" ke PTY hidup dengan gating foreground+idle+alive [preferred], ATAU resume-by-id di cwd asli
saat exited; gating-gagal sesi hidup → surface manual, tak auto-kill); backoff bila kosong; state tahan restart
daemon. Catatan agy: jalur inject provisional — verifikasi perilaku TUI agy saat quota habis dulu (TODO #2).
Selesai bila: AC-3, AC-6, AC-7, AC-8 lulus. Integration test end-to-end: simulasi LIMIT_HIT → tunggu →
probe → resume di cwd benar (uji juga kasus cwd hilang → BLOCKED).
M3 dieksekusi sebagai sub-slice. M3a (Daemon lifecycle + IPC ADR-015 + reconcile orphan) ✅ ·
M3b (Scheduler timer persisten + backoff + recovery) ✅ · M3c (Usage-Probe parser murni) ✅ —
ketiganya engine murni, tier-reviewed, merged main. Sisa = M3d (wiring live + continue-engine) di bawah.
M3d = HARD-STOP OTONOM (outward-facing: sentuh sesi live + jaringan + creds; butuh limit/quota asli;
keputusan user) → dirancang di sini, dieksekusi dengan user hadir, bukan otonom.
Progres M3d (4 Jul): M3d.8 ✅ (a1470b4) · M3d.1 ✅ (8d0a8b1) · M3d.2 ✅ (fc60cd8, tutup I-6) —
Tier-1, smoke live e2e (LIMIT_HIT→reset_at→probe job).
M3d.3–M3d.7 ✅ ENGINE (rebuild 3db7fa6) — percobaan Haiku di-revert (tag haiku-m3d-attempt, alasan: require-ESM,
Linux port-discovery salah, SpawnSpec tanpa cwd, inject-spin, 0 test); ditulis ulang testable (semua I/O di-inject),
184/184 test, Tier-1 review Opus. I-11 CLOSED (realDispatch).
Update 5 Jul (live-verify Ubuntu 24.04): (a) gate native-prebuild Ubuntu LULUS (node-pty compile-from-source +
better-sqlite3 prebuild → require+operasi OK; sisa M1 tertutup untuk Ubuntu); build+lint+184→187/187 test hijau di
Linux (sebelumnya hanya Windows). (b) port-discovery agy live-verified (G-22 terbukti pada proses agy LS nyata,
discoverLocalPorts → 2 port terkorelasi inode, 4× reproduksi) + GetUserStatus 200 → skema direkonsiliasi ke respons
live (I-7 CLOSED, G-23/G-24) + parseAgyUserStatus diperbaiki (label/modelOrAlias.model + G-17 exhausted usedFraction=1).
Update 6 Jul (actuation seams TERTUTUP — Windows): M3d.7/I-12 poin 1 ✅ (33e78b5) inject-continue via
kanal IPC per-sesi (wrapper host createIpcServer({inject}) ↔ daemon requestInject; token literal hardcoded =
injection firewall struktural; smoke live: child PTY terima continue\r) · M3d.6/I-12 poin 2 ✅ (76df6ae)
resume-by-id spawn wrapper PTY baru di cwd asli via runSession in-process (AC-8: cwd hilang→BLOCKED; smoke live:
sesi baru pid nyata + lama RESUMED). 209/209 test, Tier-1 self-review.
Update 7 Jul (Ubuntu — gating + verifikasi): I-13 ✅ (7dffcbe) gating foreground/idle DITEGAKKAN
(ADR-014 poin ii&iii): shared/foreground.ts (/proc tpgid==pgrp, live-verified Ubuntu, G-28) + shared/idle-tracker.ts
(jendela-sunyi esc to interrupt, G-29) di-wire ke createInjectHandler; inject tak lagi lolos saat drop-ke-shell /
(Claude) mid-turn. I-5 ✅ (280f8d7) stale-socket POSIX (G-14) diverifikasi otomatis di Ubuntu (test/ipc-stale-socket.test.ts,
POSIX-only). 231/231 test, build+lint bersih, Tier-1 self-review.
Update 7 Jul (Windows — utang struktural ditutup): I-14 ✅ (c4cf164) relokasi runSession
cli/run-core.ts→daemon/process-wrapper.ts (menutup layer-inversion G-27; cli/ & daemon/ sama-sama import dari
daemon/) + resume-chain link (migrasi 0002 kolom sessions.resumed_from FK, schema_version=2; acca status
render #new<-#old; live smoke upgrade v1→v2 pada DB ber-isi + FK enforced, G-30). I-10 ✅ (4255c99) daemon
hidup re-arm job lintas-proses via IPC rearm (scheduler.rearm() baca store segar + perintah tanpa payload +
notifyDaemonRearm best-effort; live smoke DUA PROSES: daemon nyata idle → proses terpisah tulis job+rearm →
dispatch tanpa restart). 235/235 test, build+lint bersih, Tier-1 self-review.
Update 7 Jul (Windows — I-16 hardening probe agy, dari cek CodexBar): I-16 ✅ probe agy pindah dari
GetUserStatus (buta window MINGGUAN) ke RetrieveUserQuotaSummary (weekly+5h per grup, G-31). Parser baru
parseAgyQuotaSummary (bucket→UsageLimit, kind=weekly/5h, absent→exhausted G-17, PII firewall tak sentuh displayName).
Dispatch every(usedFraction<1) kini benar mencakup weekly (dulu bisa keliru resume saat weekly habis). 244/244 test,
live PRODUCTION probe balas 4 limit weekly+5h dari agy nyata. parseAgyUserStatus dipertahankan (credits/proximity M4).
Sisa M3 (follow-up, bukan blocker loop): live-verify actuation dgn limit ASLI opportunistik (I-15: keystroke agy
- foreground Windows); residual I-10 = konsolidasi sole-writer
scheduled_jobs(daemon ambil-alih lifecycle sesi, refactor lebih besar).
Batas scope-file M3d: banyak slice menyentuh
daemon/supervisor.tssebagai titik integrasi → slice ber-supervisor diserialkan (bukan paralel). Slice adapter-probe (M3d.3/M3d.4) & fixture (M3d.8) = file terpisah → boleh paralel. Semua slice M3d Tier 1 (state-machine / egress / creds / inject PTY).
Slice: supervisor memasang Detector (classify()) ke stream output PTY sesi hidup (+ hook StopFailure utk CC);
sinyal limit → status LIMIT_HIT + proc_state + event status_change, tanpa aksi diturunkan dari isi output.
Scope file: daemon/supervisor.ts, daemon/process-wrapper.ts (baru/atau cli/run-core.ts wiring), store/repositories/sessions.ts. Pakai daemon/detector.ts apa adanya.
Di luar scope: adapters/*, scheduler.ts, continue.ts.
Kriteria selesai: sesi live + sinyal limit fixture (di-feed ke stream / hook) → baris sessions transisi LIMIT_HIT + event tercatat; overload (429/5xx) TIDAK memicu (overload firewall). Empty/tak-ada-sinyal = tetap RUNNING.
Bukti: test hijau (paste) transisi state + non-trigger overload; log run.
Tier review: 1 (state machine + jalur deteksi security-sensitive; injection firewall).
Slice: transisi LIMIT_HIT → hitung reset_at (reset-estimator, tandai sumber) → enqueue scheduled_jobs kind=probe (scheduler); recovery timer saat restart daemon.
Scope file: daemon/supervisor.ts, store/repositories/scheduled-jobs.ts (pakai), daemon/scheduler.ts (pakai), reset-estimator.ts (pakai).
Di luar scope: adapter probe live, continue.
Kriteria selesai (AC-7): LIMIT_HIT → row scheduled_jobs.run_at benar + reset_source; restart daemon → job pending re-armed (uji dgn fake timer + persistence asli). Tutup I-6 (adapter setTimer produksi bungkus rejection).
Bukti: test hijau recovery-dari-persistence + estimator precedence.
Tier review: 1 (persistensi timer/state).
Slice: adapters/claude.ts probeUsage() baca ~/.claude/.credentials.json (Bearer + anthropic-beta) → GET api/oauth/usage → parseClaudeOAuthUsage → UsageSnapshot. Egress hanya api.anthropic.com (guard).
Scope file: adapters/claude.ts, shared/ http+egress-guard kecil (baru), adapters/usage.ts (pakai).
Di luar scope: antigravity.ts, supervisor, continue.
Kriteria selesai: HTTP nyata → usedFraction/resetAt (dua format resets_at G-4 tertangani); creds hanya dibaca (tak di-log/disalin); egress non-whitelist ditolak (test guard). Error/401/timeout → UsageProbeError, bukan crash.
Bukti: log run probe nyata (angka, tanpa token/PII) + test egress-guard + test parser.
Tier review: 1 (egress jaringan + baca creds).
Slice: adapters/antigravity.ts probeUsage() temukan port LS dari PID sesi hidup lintas-OS (Win Get-NetTCPConnection; Linux /proc/ss) → POST GetUserStatus (Connect-JSON, tanpa csrf) → parseAgyUserStatus. Redaksi PII (G-9).
Scope file: adapters/antigravity.ts, shared/ port-discovery lintas-OS (baru), adapters/usage.ts (pakai).
Di luar scope: claude.ts, supervisor, continue.
Kriteria selesai: sesi agy live ber-PTY → quotaInfo per-model (I-7 skema dikonfirmasi dari respons asli). Tangani remainingFraction ABSENT = exhausted (G-17, jangan crash undefined). Catat caveat F1 (fraksi cached-at-init → snapshot, bukan real-time) + useG1Credits credit-fallthrough (G-16: limit agy soft bila credit aktif → probe wajib cek exhaustion=absent DAN credit) di komentar/docs. PII tak bocor ke log/events. Print-mode -p tak untuk deteksi limit (stdout kosong, G-18).
Bukti: log run (angka per-model, tanpa PII) + test parser + test redaksi.
Tier review: 1 (jaringan + PII + creds).
Live-verified 5 Jul (Ubuntu): port-discovery inode-correlation ✅ pada
agyLS nyata; GetUserStatus 200 → skema dikonfirmasi (I-7 CLOSED); parser + fixture direkonsiliasi ke respons live. Redaksi PII (G-9) tertutup di parser. ✅ WIRING DONE + live-verified Windows 5 Jul:probeAgyUsage(adapters/antigravity.ts, standalone injectable) =discoverLocalPorts→https(rejectUnauthorized:false) ke tiap port vialoopbackHttpsPostJson(shared/http.ts,node:https, insecure-TLS dibatasi ketat ke loopback — G-25) → retry ~tiap 2s cap 15s sampai HTTP 200 ber-userStatus(G-23) →parseAgyUserStatus. PII/injection firewall: body respons tak pernah masuk pesan error. Live Windows:Get-NetTCPConnectionport-discovery ✅ (3× fresh spawn, port cocok log agy) +probeAgyUsagebalas 8 model nyata (usedFraction/resetTime per-model, reset window beda per-model) dalam ~1s, tanpa PII/token. Tests:test/agy-probe.test.ts(7, retry-loop + wrong-port skip + PII-not-leaked) +test/http-egress.test.ts(+loopback https guard). 199/199 hijau, build+lint bersih, Tier-1 self-review lolos. Sisa non-blocking: wiringprobeUsageke dispatch resume (M3d.5 sudah adarealDispatch) sudah nyambung viaadapter.probeUsage; retrieveUserQuota standalone (#3) tetap impl-tuning.
Slice: job probe jatuh tempo → probeUsage(); kuota tersedia → enqueue job resume; kosong → backoff reschedule (scheduler) + notif "perkiraan". Tak spam-resume.
Scope file: daemon/supervisor.ts (dispatch scheduler→probe→keputusan), scheduler.ts (pakai).
Di luar scope: adapter internals (M3d.3/4), continue internals (M3d.6/7).
Kriteria selesai (AC-6): probe kosong → backoff berjenjang + jadwal ulang (tak resume); probe berisi → enqueue resume sekali. Uji fake-timer.
Bukti: test hijau kedua cabang.
Tier review: 1 (keputusan aksi-auto + state machine).
DONE:
supervisor.realDispatchcabangexited→spawnResumeFn(injectable; defaultrunSessionin-process, BUKANdaemon/continue.ts— actuation cukup di dispatch + engine wrapper yang sudah ada). Spawn wrapper PTY baru dispec.cwd(=cwd asli, AC-8) viaresumeCmd; cwd hilang → BLOCKED sebelum spawn. Sukses →markResumedsesi lama + eventresume_spawned {newSessionId,spec}. Sesi hasil resume host socket kontrol → re-injectable. Uji: dispatch test (cwd asli + BLOCKED no-spawn) + smoke live Win (sesi baru pid nyata di cwd benar, lama RESUMED). Live-verifyclaude --resumedgn sesi asli = opportunistik (I-15). Relokasi runSession→process-wrapper + link old→new = I-14. Slice: sesiexited+ kuota ok → jalankan resume di cwd asli (claude --resume <id>/agy --conversation <id>) via PTY; cwd hilang →BLOCKED(jangan resume di tempat salah). Scope file:daemon/continue.ts(baru),adapters/{claude,antigravity}.ts resumeCmd()(pakai),daemon/supervisor.ts(panggil). Di luar scope: jalur inject-PTY (M3d.7). Kriteria selesai (AC-3, AC-8): exited → resume spawn di cwd benar → statusRESUMED; cwd hilang/berubah →BLOCKED+ notif, tak resume. Bukti: integration test (cwd benar + cwd hilang→BLOCKED); log run. Tier review: 1 (spawn proses + korektness cwd = AC-8).
M3d.7 — Continue-engine: inject "continue" ke PTY hidup + gating (ADR-014 §1-2, preferred) ✅ SEAM (33e78b5, 6 Jul)
DONE (kanal IPC + actuation): wrapper
acca run(pemilik PTY) hostcreateIpcServer({inject})di socket kontrol per-sesi (sessionControlSocketPath, ADR-015 — tanpa transport baru); daemonrequestInject→ wrapper gating lokal (checkInjectGating+hasPtyHandle) +ptyProcess.write(CONTINUE_TOKEN='continue\r'). Injected →markResumed(RESUMED, proc alive) + event; gagal/unreachable →inject_skipped+ done (surface, TANPA spin). Injection firewall STRUKTURAL: token hardcoded wrapper, perintahinjecttanpa payload (G-26). Uji:inject-continue.test.ts(8, incl firewall-ignores-args) + dispatch (injected/unreachable) + smoke live Win (child PTY terimacontinue\r). I-13 ✅ (7 Jul,7dffcbe): komputasi gatingforegroundIsAgent(/proctpgid==pgrp, Linux; Windows TBD) +idle(jendela-sunyiesc to interrupt) kini ADA & di-wire → inject diblokir saat drop-ke-shell / (Claude) mid-turn. Keystroke agy + foreground Windows + live-verify limit asli = I-15. Slice: sesialive+ gating LULUS (proc alive = child kita · foreground = agent bukan shell · sesi idle bukan mid-turn · probe kuota ok) → inject literal tetap"continue"\nke PTY. Gating GAGAL → surface manual, TAK auto-kill. Token tak pernah dari isi output (injection firewall). Scope file:daemon/continue.ts,shared/proc.ts(foreground/idle detection lintas-OS — reuse spike burn2 sesi ini: idle marker footer, foreground=agent),daemon/supervisor.ts(panggil). Di luar scope: resume-by-id (M3d.6), remote. Kriteria selesai: alive+idle+foreground=agent → inject "continue" → lanjut; drop-to-shell ATAU mid-turn ATAU proc≠child → tak inject, di-surface; token = literal (uji tak ada aksi dari output). Bukti: test gating tiap cabang (lulus + 3 gagal) + test literal-only. Tier review: 1 (inject PTY = paling security-sensitive; injection firewall + literal token).
M3d.8 — Fixture limit agy ASLI ke korpus detektor (observasi 4 Jul SUDAH ada → tinggal encode) ✅ (a1470b4)
Slice: observasi limit agy ASLI sudah tertangkap 4 Jul (agy-REAL-limit-message.txt: ⚠ Individual quota reached. Please upgrade your subscription to increase your limits. Resets in <Xm Ys>. + Error ID; agy tetap hidup;
remainingFraction absent). Tinggal: encode fixture pesan ke korpus detektor agy (ganti 4 fixture provisional) + fixture
respons LS exhausted (field absent); set jalur continue agy = alive/inject (ADR-014 sudah dianotasi verified). Detector agy corpus provisional→verified.
Scope file: adapters/patterns.ts (korpus agy), test/fixtures/agy-limit*, test/detector.test.ts.
Di luar scope: supervisor, adapter probe.
Kriteria selesai: detector klasifikasi fixture limit agy ASLI benar; ADR-001 (bagian agy) bisa naik Accepted; ADR-014 catatan agy diperbarui dari observasi.
Bukti: test hijau fixture agy asli; ADR/GOTCHAS diperbarui.
Tier review: 1 (korektness deteksi).
Urutan eksekusi M3d: M3d.1→M3d.2→M3d.5 (rantai supervisor, serial) ; M3d.3 ∥ M3d.4 ∥ M3d.8 (file terpisah) ; M3d.6→M3d.7 (continue, serial, setelah probe siap). M3d.8 memanfaatkan eksperimen sesi ini → bisa duluan. Semua Tier-1 → tier-review Opus wajib. Fixture/observasi live = sumber kebenaran, bukan asumsi.
Slice: notifikasi desktop/CLI pada transisi LIMIT_HIT/RESUMED/FAILED; acca status lengkap
(usage best-effort + indikator "perkiraan" + loading/empty/error state); acca log.
Selesai bila: AC-4 ✅ (usage-view + acca log ✅; reset_at terjadwal + liveness daemon di acca status ✅ per
I-24, 12 Jul — kolom reset HH:MM+sumber + baris daemon: HIDUP/MATI; overclaim 11 Jul dikoreksi lalu benar-benar
ditutup), AC-5 ✅ lulus; UX states eksplisit teruji ✅. (Sisa opsional: Notifier desktop = gate dep.)
Progres (10 Jul, Ubuntu):
- ✅ Notifier core (
src/notify/notifier.ts): pemetaan MURNInotificationForEvent(event)→Notification|nulluntuk transisi layak-surface (LIMIT_HIT · RESUMED [injectstatus_change+ resume-by-idjob_dispatch_done resume_spawned] · FAILED · BLOCKED [job_dispatch_error status=BLOCKED]); dipasang sbg dekorator atasEventsRepo(withNotifications) → surface otomatis tanpa sentuh call-site. Sink default = stderr (out-of-band); desktop node-notifier = opt-in menyusul (gate dep). Firewall PII (G-9): body hanya field terkontrol,evidence/probe/spec.argstak di-echo;deliverthrow di-swallow (tak putus lifecycle). Wired:cli/commands/run.tsdaemon/supervisor.ts(+depnotify). Tier-1 self-review. 270/270 test (+26), build+lint bersih, live smoke PTY (frasa limit CC asli →[acca warn] …stderr, evidence tak bocor).
- ✅ Proximity ENGINE (I-8):
proximityNotifications(snapshot, thresholds)murni (0.90 5h / 0.75 weekly, exhausted dilewati). Wiring → I-17 (DONE 11 Jul). - ✅ I-17 usage-monitor + wiring (11 Jul, autonomous-run): engine
daemon/usage-monitor.ts(Sonnet, murni- injectable: dedup per-tool, isolasi, re-entry guard, firewall) + wiring supervisor (Opus, Tier-1): probe periodik ~2 mnt (owner Ziffan) saat RUNNING →metacache snapshot (usage_snapshot_<tool>, tanpa migrasi) + proximity→notify. Opt-instartUsageMonitor(produksiacca daemon; G-32). 290/290 test (+11). Live-verify sesi asli = opportunistik (I-15). → Ini sumber dataacca statususage-view (AC-4). - ✅
acca log(US-8) — 11 Jul (autonomous-run, Windows): perintah read-onlyacca log [sessionId] [-n <limit>]→events.listRecent/listBySession(repo +2 method baca) →formatEventLine(PURE, exported). Firewall (G-9, ADR-013): summary HANYA dari allowlist field terkontrol (to/from/source/reason/action/status/kind/jobId/ newSessionId/run_at/attempts/exitCode/where/reachable) —evidence/spec/kunci tak dikenal TAK PERNAH di-dump; parse payload defensif. DekoratorwithNotificationsdi-{...events}(teruskan method baca; menutup fragilitas "method hilang"). Subagent Sonnet + tier-review Opus (firewall + type-soundness). 279/279 test (+9), build+lint bersih. Merender ke stdout lokal (bukan egress). - ✅
acca statususage-view (AC-4) — 11 Jul (autonomous-run, Sonnet+Opus): plain ANSI (TUI decision), baca cachemeta.usage_snapshot_<tool>→ helper purerenderUsageBar(▓▓░clamp) +formatUsageLines(header umur snapshot + baris per limit kind/bar/pct; empty-state "usage belum ada—jalankan acca daemon" + "tak terbaca" defensif). Firewall G-9: hanya tool/kind/bar/pct —scope(display-name model) tak dirender (diuji + smoke render live: 'SECRET' 0×). Blok sesi lama utuh. 305/305 test (+15). Smoke render nyata: bar 37%/36%/92% (CC) + 74%/10% (agy) tampil benar. - Sisa M4: Notifier desktop (node-notifier) — butuh gate DEPENDENCY-POLICY (dep baru = keputusan user). AC-4 ✅ · AC-5 ✅ (notif transisi engine + surface). M4 inti selesai; desktop-notifier = opsional di belakang gate dep.
Kenapa ada: audit menyeluruh 11 Jul (docs/audit/AUDIT-2026-07-11.md) menemukan 4 P1 di jalur resume/continue
yang lolos 308 test (test men-stub seam yang justru cacat). Klaim "loop auto-continue penuh selesai & bertes" =
overstated — yang live cuma inject ke proses proxy + spawn wrapper baru, bukan resume percakapan CLI nyata.
M-remote DITUNDA sampai gate keluar hijau (tier B resume-now akan expose jalur resume yang rusak; I-15 pasti
gagal di A-1).
Slice (= rencana remedi audit R1–R8):
- R1 — daemon-no-crash (I-20/A-2) ✅ (
9027dc4): defaultspawnResumeFnkonsumsiwaitForExit(tak ada unhandledRejection yang mematikan daemon) + tak keliru markResumed saat spawn gagal. Test menjalankan DEFAULT path (bukan stub). 310 test hijau, Tier-1 self-review. - R2a — cli_session_id di dispatch (I-20/A-1 paruh) ✅ (
df3904b): resume pakaisession.cli_session_id; absen → BLOCKED (surface), bukan spawn id supervisor yang dijamin ditolak CLI.setCliSessionIdrepo siap. Test bug-encoding dikoreksi + test NULL→BLOCKED. Tier-1 self-review. - R2b — capture cli_session_id (I-20, belum): tangkap id CLI nyata (CC transcript/
SessionStarthook; agy printed cmd). Butuh live-verify (audit §6). Gabung ke slice hook (R6/I-23). Sampai ada → resume-by-id exited = BLOCKED. - R3 — resume-cycle (I-21/A-3, belum): transisi RESUMED→RUNNING + un-latch watcher + monitor mencakup sesi hidup + test siklus 2×.
- R4 — agy-exited-policy (I-22/A-4): ✅ RESOLVED via ADR-019 (12 Jul, pivot dari ADR-018). Live-verify slice 2
(otorisasi user) buktikan probe standalone OAuth
retrieveUserQuotabaca pool kuota SALAH (gemini-cli harian ≠ grup agy weekly+5h; Summary via OAuth=403, G-38) → ADR-018 opsi #3 GUGUR → **ADR-018 di-supersede ADR-019 = optimistic resume- detect** (agy-exited: skip probe, enqueue resume langsung di reset_at; sesi hasil-resume alive → deteksi ulang via LS
bila masih limit; bounded B-1). Guard slice-1 (
probe_impossible) DIGANTI.oauth2/cloudcode-padihapus dari egress (least-privilege). 369 test hijau, Tier-1 self-review. R5 status-completeness (I-24) ✅.
- detect** (agy-exited: skip probe, enqueue resume langsung di reset_at; sesi hasil-resume alive → deteksi ulang via LS
bila masih limit; bounded B-1). Guard slice-1 (
- R6 — stopfailure-hook + sessionstart-capture (I-23) ✅ (12 Jul, LIVE-VERIFIED CC 2.1.207): wrapper generate
settings.json terisolasi →
claude --settings <file>memasang hook StopFailure (deteksi limit CC PRIMER, ADR-001/§7) + SessionStart (capturecli_session_id→ tutup paruh CC I-20/R2b). Forwarder internalacca __hook <id>(exec-form, best-effort) → socket kontrol per-sesi →feedSignal/setCliSessionId; injection firewall (kanal DATA vs AKSI,daemon/hook-relay.ts). 368 test (+9); live productionacca run claude→cli_session_idterpersist dari SessionStart nyata. Sisa opportunistik:rate_limitStopFailure end-to-end asli. R7 resume-gate-per-tool (I-25). R8 housekeeping (I-27/I-28) ✅. Gate keluar (sebelum M-remote): R1–R3 ✅ + R4 ✅ PENUH (ADR-019 optimistic resume, 12 Jul) + R6 (I-23, deteksi limit CC primer + capture id CC) ✅ + I-15 live-verify lulus dgn CLI nyata (limit asli, resume nyata melanjutkan percakapan — sisa terbesar & satu-satunya gate tersisa). M5 aman setelah R1 (crash) tertutup — sudah ✅.
Slice (bertahap per tier, satu kanal Telegram — ADR-011):
- Tier A (egress-only): Notifier kirim notif transisi (LIMIT_HIT/RESUMED/FAILED) ke
chat_idterotorisasi via long-polling bot (outbound-only keapi.telegram.org). (US-14) - Tier B (kontrol masuk): command listener + Authz allowlist
chat_iddefault-deny; perintah whiteliststatus/resume-now <id>/cancel <id>; sender tak sah di-drop+audit; rate-limit. (US-15) - Tier C (egress sensitif + relay ber-konfirmasi): lihat output (redaksi rahasia + size-cap +
opt-in per sesi) + kirim instruksi lewat Confirm gate (queue→echo→
/confirm <token>→inject PTY); injection firewall (isi output = data, tak jadi aksi). (US-16, US-17) Selesai bila: AC-9..AC-12 lulus + security-review gate (skillmilestone-wrapup) terhadap keempatnya. Uji khusus: test injection (payload di output tak memicu aksi), test redaksi (pola rahasia ter-redaksi), test authz (sender tak sah ditolak+audit), test konfirmasi (tanpa/confirmtak ada inject). Dependensi (gate ADR-013 §5): THREAT-MODEL.md (✅ ada) di-review; pola redaksi rahasia (✅ hybrid regex+entropy, ADR-013 §2) & lib Telegram bot Node (✅grammy1.44.0, ADR-011) diputuskan & ADR-011/012/013 di-LOCK (3 Jul malam); butuh Notifier (M4). Sisa yang di-tune saat M-remote: regex/threshold redaksi eksak + test corpus. Catatan: ini milestone paling sensitif — tak dimulai sebelum tier prasyaratnya hijau dan gate terpenuhi.
PRD+TRD di-lock 2026-07-18 (doc-first, skill
docs-first-specmode modul). ADR pengikat: ADR-028 (read-only localhost) di atas ADR-008/013 (read-only ⇒ nol aksi) + ADR-023/T-L1 (data-minimize). Gate keamanan: THREAT-MODEL §9 (T-W1..W6 + R-7).STATUS: ✅ DITUTUP FORMAL 2026-07-19 (security-review gate M-web LULUS PENUH). M-web.1 diimplementasi + verified (18 Jul,
77763a6); gate T-W1..T-W6 dijalankan 19 Jul (skillmilestone-wrapup, persona security-review) — semua CONFIRMED, nol gap: T-W1 proyeksi ter-firewall (code + negative-control test: JSON kabel tak memuatcli_session_id/cwd/secret; callerweb.ts:44proyeksikan viatoSessionStatusView), T-W2 GET-only 405, T-W3 Host-guard 403 (IPv6-aware, tolak subdomain-attack), T-W4 self-contained (grep nol aset eksternal), T-W5textContentanti-XSS, T-W6 port validasi + bind-fail exit + proses terisolasi dari daemon; R-7 (loopback terjangkau proses lokal) DITERIMA (single-user desktop). M-web.2 (daemon --web) tetap opsional (W-2), tak menghalangi penutupan.
PRD — apa & untuk siapa: solo orchestrator ingin memantau usage/sesi/log acca di browser lokal tanpa terminal (US-10). Read-only murni; nol aksi kontrol (owner 18 Jul).
TRD — kontrak teknis (ADR-028): acca web [--port] (opt-in, default 4599, env ACCA_WEB_PORT) →
http.createServer bind 127.0.0.1 saja. GET / = HTML self-contained (CSS+JS inline, poll ~5s,
render textContent). GET /api/status = JSON dari proyeksi ter-firewall yang SUDAH ADA
(toSessionStatusView + formatEventLine/allowlist + data formatUsageLines). Host non-loopback → 403;
method non-GET → 405. Nol dep/framework; nol mutasi; nol aset eksternal.
Vertical slices:
- M-web.1 — Monitor read-only end-to-end ✅ (
77763a6, 18 Jul) [SANDBOX-testable]:web/status-json.ts(PURE — rakit payload dari proyeksi ter-firewall) +web/server.ts(bind 127.0.0.1, routing GET /(page) + /api/status, Host-guard 403, method-guard 405) +web/page.ts(HTML self-contained, fetch/api/statuspoll, render textContent) + commandacca web. Selesai bila: server hidup di port efemeral,fetch('/api/status')→ JSON tanpacli_session_id/cwd/secret (test properti);Host: evil.com→ 403;POST /→ 405; bind non-loopback DILARANG (assert host literal127.0.0.1); greppage.ts= nol URL eksternal. - M-web.2 —
acca daemon --webco-host [SANDBOX] (opsional, nilai kemudahan): mount server yang sama di daemon (flag--web, port sama). Selesai bila: daemon dgn--webmelayani/api/status; tanpa flag = tak ada listener (default-off).
Selesai (milestone) bila: AC-W1..W4 lulus + security-review gate (skill milestone-wrapup,
persona security-review) terhadap T-W1..T-W6 (THREAT-MODEL §9.3): proyeksi ter-firewall terverifikasi
(nol cli_session_id/cwd di JSON kabel), Host-guard 403, method-guard 405, bind loopback-saja, HTML
nol-aset-eksternal. Uji khusus: test data-minimize (JSON kabel), test Host-guard (DNS-rebinding), test
method-guard, test self-contained (grep aset eksternal).
STATUS: ✅ DITUTUP PARSIAL 2026-07-17 (Linux track lengkap & LIVE-verified; Windows ditunda). Slice: M5.1/M5.2 backup ✅ (engine SANDBOX + restore LIVE-verified M5.6 —
tl6xter-revert = bukti restore genuine) · M5.3 security pass ✅ (T-L1/2/4/5/8 tutup, T-L7 Linux tutup via M5.4, T-L6 tutup via M5.6 restore LIVE) · M5.4 systemd--user✅ LIVE (AC-M5-1 penuh + AC-M5-3 Linux) · M5.5 Windows ✅ DITUTUP PENUH (ADR-026, LIVE 18 Jul) — autostart per-user (Task Scheduler @logon) menyelesaikan I-33 by construction; AC-M5-2 hijau LIVE (daemon=user + same-DB + creds + @logon-fire + watchdog ~65s + nol-jendela viaconhost --headless) · M5.6 wrap-up ✅. Suite hijau di M5-close. M5 TUTUP PENUH (Linux + Windows). (Jumlah test bergantung-mesin; angka-of-record di CLAUDE.md §2 — RD-5.) Gate security-review ke M-remote BERSIH (semua T-L lokal tutup; T-L3 N/A). Paruh Windows AC-M5-3 (reboot→login saat job pending) = kelas I-15 (butuh limit asli utk stage job resume; recovery-on-start sudah terbukti Linux).
PRD+TRD di-lock 2026-07-17 (doc-first, skill
docs-first-specmode modul). ADR pengikat: ADR-021 (Windows Service), ADR-022 (backup/DR minimal), ADR-023 (IPC DACL residual + hardening I-26), di atas ADR-007/015/017 yang sudah ada. Slice formal (vertical) ada di sub-bagian "Vertical slices M5" bawah.
Tujuan M5: jadikan daemon dari "jalan saat user buka terminal" menjadi layanan OS selalu-nyala yang survive
reboot + auto-restart on-crash, lalu audit keamanan fondasi sebelum M-remote memperluas permukaan, plus jalur
backup/restore state. Ini yang membuat JTBD inti (auto-resume tengah-malam saat user jauh/tidur) benar-benar
terjamin — bukan bergantung terminal terbuka.
Untuk: Solo Orchestrator (PROJECT §2) di host always-on (laptop Ubuntu daily, PC Windows weekend, node headless 24/7).
Batasan M5 (DILARANG scope-creep): BUKAN dashboard web (US-10, Later); BUKAN multi-user (US-12); BUKAN fitur acca backup in-daemon (skrip+doc cukup MVP, ADR-022); BUKAN native addon DACL (ADR-023 tolak). Install = template + skrip
manual, DILARANG menambah dependency npm runtime baru (ADR-021).
A. Service lifecycle lintas-OS (ADR-007 + ADR-021).
- Linux — systemd
--userservice + lingering. HARUS: sediakan template unitacca-daemon.service(ExecStart=node <path>/dist/cli/index.js daemon,Restart=on-failure,RestartSec) + skrip install yangsystemctl --user enable --now acca-daemondanloginctl enable-linger $USER(WAJIB — tanpa linger, service mati saat user logout; verified 17 Jul via ArchWiki/systemd docs). Daemon runtime DILARANG butuh root. - Windows — Windows Service (ADR-021, bukan Task Scheduler). HARUS: template config WinSW XML (primary) yang
membungkus
node <path>\dist\cli\index.js daemondengan auto-restart on failure + log redirect; dokumentasikan jalursc.exe(built-in) sebagai fallback nol-tool. Install butuh admin sekali (registrasi); daemon runtime least-privilege. DILARANG dep npm runtime baru; WinSW = binary vendored terpisah (pin versi+hash, gate DEPENDENCY-POLICY). - Recovery state lintas-restart (sudah ada, AC-7): service yang restart HARUS memanggil
supervisor.start()yang recoverscheduled_jobspending → job LIMIT_HIT yang jatuh tempo saat daemon mati tetap dijalankan. Slice service HARUS memverifikasi ini end-to-end (bukan asumsi): reboot host saat ada job pending → job tetap fire pasca-boot.
B. Security pass menyeluruh-terfokus (persona security-review, skill tier-review tier 4).
Audit 5 permukaan fondasi; tiap temuan → tutup atau catat residual di THREAT-MODEL.md:
- IPC / named pipe DACL (I-26, ADR-023). HARUS: dokumentasikan DACL terbuka sbg residual risk + terapkan hardening
lapisan-app (minimalkan data sensitif lewat pipe; hanya daemon mutasi state — verifikasi;
injecttanpa payload — verifikasi firewall struktural utuh). DILARANG native addon / cek-PID (spoofable, ADR-023). - Egress whitelist (NFR §Security). HARUS: verifikasi kode hanya egress ke host allowlist (
api.anthropic.com, localhost loopback agy LS,api.telegram.orgbila M-remote nanti) viaguardEgress/ALLOWED_HOSTS; tak ada jalur lolos. Test: egress ke host non-allowlist →EgressBlockedError. - Credential-read at rest (ADR-005/010). HARUS: verifikasi
oauth_creds.json/.credentials.jsonhanya dibaca, tak disalin/di-log; tak ada secret dievents.payload/log. Test: grep jalur log/DB untuk kebocoran token. - Inject firewall (ADR-008/013/014/020). HARUS: verifikasi token inject = literal hardcoded wrapper, IPC
injecttanpa payload; tak ada aksi diturunkan dari isi output. Test regresi sudah ada (ADR-020 guard) — konfirmasi cakupan. - Retensi state (ADR-004). HARUS: verifikasi no-hard-delete (arsip
archived_at, tak ada DELETE);eventsappend-only. Test: coba path yang menghapus → tak ada.
C. Backup/DR minimal (ADR-022).
- HARUS: skrip backup lintas-OS —
PRAGMA wal_checkpoint(TRUNCATE)→ salinacca.db(+-wal/-shm) ke lokasi backup ber-timestamp → pangkas ke N snapshot terakhir (N + lokasi + interval = konfigurasi, bukan hardcode). - HARUS: dokumentasikan restore (stop service → ganti file → start) di quick-start.
- DILARANG: fitur backup in-daemon di MVP; DR penuh (replikasi/PITR).
D. Dokumentasi user + install (docs + template + skrip).
- HARUS:
README/quick-start berisi — instalasi service per-OS (langkah admin sekali), konfigurasi (path, backup,chat_idbila M-remote), backup/restore, uninstall. HARUS: template unit/XML + skrip discripts/(atau folderdeploy/). DILARANG: dokumentasi yang mengklaim "service hijau" tanpa bukti verifikasi live di mesin asli.
- AC-M5-1 Service Linux (systemd --user + linger) survive logout + reboot; auto-restart on-crash. (live-verify Ubuntu) — ✅ PENUH 17 Jul (Ubuntu, systemd 255): install→
active (running)· auto-restart on-crash (SIGKILL→restart PID baru ~5s,NRestarts=1, <30s; G-47) · same-DB (acca status→daemon HIDUP, kontras I-33) · logout→login survive (owner) · reboot→auto-start (owner + korroborasi:up 1min, daemonactive since+6s pasca-boot, PID baru 2642,enabled+Linger=yesbertahan). - AC-M5-2 ✅ DITUTUP 18 Jul (LIVE, mesin Windows asli + 2× logout/login owner) (DI-REVISI ADR-026 — jalur autostart per-user, bukan Windows Service; restart target DIAMANDEMEN <30s→<90s, 18 Jul) Autostart Windows per-user (Task Scheduler @logon, run-hidden) auto-start saat login + auto-restart on-crash <90s (SIGKILL, bukan exit-bersih). Amandemen restart (18 Jul, keputusan owner): floor
RestartOnFailureTask Scheduler = PT1M (60s), tak bisa <30s spt systemd (RestartSec=5) → target Windows direlakan ke <90s (konsisten ADR-026 yang sudah menerima always-on terdegradasi utk laptop). Mekanisme restart = watchdog repetisi (LogonTriggerber-Repetition PT1M+MultipleInstancesPolicy=IgnoreNew), BUKANRestartOnFailuresendiri — LIVE 18 Jul membuktikanRestartOnFailureTAK me-restart proses yang di-kill (G-49). Bukti WAJIB (diperkuat — "task RUNNING" TAK cukup, kelas kegagalan I-33): (a) daemon bacaacca.dbyang SAMA dengan CLI user (acca statuskonsisten, bukan DB kosong baru) DAN (b)claude/agyter-spawn TERAUTENTIKASI (resume nyata jalan, bukan gagal-auth senyap) DAN (c) nol jendela konsol (run-hidden terverifikasi). Scope jujur: logon-scoped — tak dituntut survive-logout / at-boot-pra-login (direlakan untuk profil laptop, ADR-026/ADR-007; truly always-on = Linux M5.4). ✅ LIVE 18 Jul (hampir penuh): (a) identitas daemon=user (lab2026zf\ziffa, bukan SYSTEM) + (b) same-acca.db(acca status→HIDUP di PID hasil-spawn task) + (c) credentials.credentials.jsonterlihat + (d) @logon trigger FIRE terkonfirmasi (owner logout→login →LastRunTime=waktu login, daemon start otomatis sbg user) + (e) watchdog restart ~65s<90s + (f) nol jendela konsol viaconhost.exe --headless. Koreksi jujur: klaim awal "nol-jendela (MainWindowHandle=0)" SALAH — logon nyata memunculkanPseudoConsoleWindownode terlihat walau Hidden=true (mata owner + detektorEnumWindows;MainWindowHandlenaif lolos-palsu, G-52); fix = jalankan node viaconhost --headless(nol jendela, conhost=induk → IgnoreNew tetap sah), terverifikasi on-demand + watchdog. ✅ SEMUA terkonfirmasi 18 Jul: logout/login final owner → daemon auto-start (pid 420, owner=ziffa, parent=conhost), nol tampilan terminal (mata owner +EnumWindows→NONE),acca status→HIDUP, watchdog armed. Catatan (b) spawn-terautentikasi: dibuktikan pada level KAPABILITAS (daemon jalan sbg user →.credentials.jsonterlihat → basis sama Linux M5.4); resume-nyata end-to-end = kelas I-15 (butuh limit asli, gate lintas-cutting, bukan spesifik M5.5). (live-verify Windows asli — sandbox tak bisa registrasi Task Scheduler) - AC-M5-3 Reboot host saat ada job LIMIT_HIT pending → job tetap fire pasca-boot (recovery AC-7 end-to-end). (live-verify) — ✅ Linux 17 Jul: job
probepending di-stage (sesi EXITED → guard I-35 = no-op aman, nol resume), daemon di-stop, host reboot → daemon auto-start → recovery-on-start fire job 7s pasca-boot (job_dispatch_done skipped:probe_stale_status, created_at > boot) + job terkonsumsi. Paruh Windows menunggu M5.5 (ditunda/I-33). - AC-M5-4 Security pass 5-permukaan selesai; tiap temuan ditutup atau tercatat residual di THREAT-MODEL.md. — ✅ M5.3 (T-L1 hardened + T-L2/4/5/8 verified, T-L3 N/A, T-L6/T-L7 kelak LIVE → keduanya kini ✅); THREAT-MODEL §8.4 close-out per-item.
- AC-M5-5 Egress ke host non-allowlist →
EgressBlockedError(test); credential-read tak bocor ke log/DB (test/grep). — ✅ M5.3test/security-egress.test.ts(exact-hostnameSet.has, typosquat/malformed→blocked) +test/security-credential.test.ts(8 bentuk error tak bocor token). - AC-M5-6 Backup:
wal_checkpoint+copy hasilkan.dbkonsisten yang bisa di-restore & daemon start bersih. (sandbox-testable + 1 live) — ✅ LIVE 17 Jul (M5.6): backup-saat-daemon-live →integrity_check: ok; restore (prosedur terdokumentasi) → daemon start bersih (HIDUP) + markertl6xter-revert +m53tterjaga.test/backup.test.ts(SANDBOX) + LIVE ini. - AC-M5-7 Retensi backup pangkas ke N (config), tak hapus di luar N; no-hard-delete state terverifikasi. — ✅
pruneSnapshotstiered (24 hourly + 30 daily, ADR-024) ditest/backup.test.ts;events/sessionsno-hard-delete (arsip, CONVENTIONS); LIVEbackup.jspruned 0(1 snapshot, nihil di luar N). - AC-M5-8 Quick-start install/backup/restore/uninstall lengkap per-OS; template unit/XML + skrip ada. — ✅ Linux 17 Jul: install (
install-linux.sh) + backup (deploy/backup/systemd/+backup.js) + restore (README, LIVE) + uninstall (uninstall-linux.sh, round-trip LIVE: uninstall→gone→reinstall→active); semua ter-gatetest/shell-script.test.ts. Windows =acca daemonmanual + Task Scheduler backup (M5.5 ditunda/I-33). - AC-M5-9 Security-review gate (persona, skill
milestone-wrapup) lolos untuk keseluruhan M5. — ✅ 17 Jul (M5.6 wrap-up): T-L1/2/4/5/6/7/8 tutup (Linux) + T-L3 N/A → gate BERSIH untuk track Linux; checklist web-app N/A (CLI lokal). Paruh Windows (T-L7) menunggu M5.5/I-33.
- Sandbox-testable (unit/integration, tak butuh mesin asli): logika backup (checkpoint+copy+prune) atas DB fixture, egress guard, credential-read firewall, retensi/no-delete, generator template unit/XML (string-render).
- WAJIB live-verify di mesin asli (DILARANG klaim hijau tanpa output nyata dari user): registrasi service per-OS, survive logout/reboot, auto-restart on-crash, recovery job pasca-boot, DACL hardening behavior. Orkestrator siapkan skrip + perintah; user jalankan di terminal disk asli + setor bukti (output service status, log pasca-reboot).
Selesai bila: AC-M5-1..9 lulus (yang live-verify dengan bukti dari mesin asli) + security-review gate lolos +
quick-start siap. Backlog M5 (post-MVP): acca backup/acca install in-CLI, native DACL (bila multi-akun host nyata).
Di-generate 2026-07-17 (skill
vertical-slice). Urutan = dependency: backup (pure, fondasi) → security-audit (pure/review) → service per-OS (template+live) → integration+gate. Tiap slice tandai [SANDBOX] (testable tanpa mesin asli) atau [LIVE] (WAJIB verifikasi mesin asli, user setor bukti — COWORK-TOOLING-NOTES). Slice security & service = Tier 1 (security-sensitive: IPC, egress, credential, service privilege). Backup = Tier 1 (state/DB).
Slice: Fungsi murni yang meng-checkpoint WAL acca.db (wal_checkpoint(TRUNCATE)), menyalin file utama saja
(bukan sidecar -wal/-shm — menyalin -wal basi = korupsi; pasca-TRUNCATE data ada di file utama) ke lokasi backup
ber-timestamp, lalu memangkas ke N snapshot terakhir — di-test end-to-end atas DB fixture (bukan CLI nyata).
Scope file: src/store/backup.ts (baru), src/shared/paths.ts (helper lokasi backup bila perlu), test/backup.test.ts (baru).
Di luar scope: daemon/, cli/, service template. DILARANG fitur backup in-daemon (skrip = M5.2).
Kriteria selesai (testable):
- Given
acca.dbWAL aktif dengan data, WhenbackupDatabase(cfg), ThenPRAGMA wal_checkpoint(TRUNCATE)dijalankan → file.dbyang disalin konsisten (integrity_check OK, tak ada-walsisa transaksi di salinan). - Retensi tiered (ADR-024, amandemen 17 Jul): pertahankan
hourlysnapshot terbaru (default 24) + 1 representatif per hari-kalender lokal (epoch terbesar hari itu) untukdailyhari terakhir (default 30); prune sisanya. Snapshot yang di-keep tak dihapus (no-hard-delete state asli — ini salinan). (Kriteria lama "pangkas ke N terakhir" di-amandemen ADR-024; engineretention:number→{hourly,daily}.) - Config (lokasi, hourly, daily, interval) dibaca dari konfigurasi (env
ACCA_BACKUP_*), bukan hardcode (ADR-022/024). - Edge: DB tak ada → error jelas; lokasi backup tak bisa ditulis → error jelas (tak silent).
Bukti verifikasi: paste output
test/backup.test.tshijau + integrity_check pasca-restore atas fixture. Tier review: 1 (menyentuh DB/state + jalur restore — korupsi = kehilangan data).
Slice: Skrip backup (memanggil engine M5.1) + langkah restore, dengan template penjadwalan (cron/systemd-timer Linux,
Task Scheduler/skrip Windows), didokumentasikan di quick-start.
Scope file: src/store/backup.ts (amandemen ADR-024: retensi tiered {hourly,daily}), test/backup.test.ts (test tiered), scripts/backup.js (baru — .js ESM, pola copy-migrations.js), deploy/backup/* (template timer/task), README/docs bagian backup.
Di luar scope: service unit daemon (M5.4/M5.5).
Kriteria selesai (testable):
- Engine amandemen (ADR-024):
backupDatabaseconfigretention:number→{hourly,daily}; prune tiered (24 hourly + 1 representatif/hari-lokal × 30 hari). Test tiered (bucket hourly + representatif-per-hari + gap-hari + hourly=1/daily=0 = rolling murni back-compat). - Skrip render/exec atas engine → hasil backup valid (sandbox: jalankan skrip atas DB fixture). Template jadwal default = hourly (ADR-024).
- Restore terdokumentasi: stop service → ganti file → start; 1× LIVE: user backup→restore→daemon start bersih.
- Template penjadwalan per-OS ada + dokumentasi interval config.
Bukti verifikasi: output skrip atas fixture (sandbox) + [LIVE] bukti user: backup→restore→
acca statusdaemon hidup. Tier review: 1 (jalur restore state).
Slice: Audit + hardening 5 permukaan fondasi (IPC/DACL, egress, credential-read, inject firewall, retensi); tiap
temuan ditutup (kode/test) atau tercatat residual di THREAT-MODEL §8; verifikasi via test + persona security-review.
Scope file: src/shared/http.ts (egress guard test), src/daemon/ipc-*.ts (hardening status data-minimize),
src/shared/credentials.ts (audit), test/security-*.test.ts (baru), docs/THREAT-MODEL.md (close-out T-L1..T-L8).
Di luar scope: service registration (M5.4/5), backup (M5.1/2). DILARANG native addon DACL (ADR-023).
Kriteria selesai (testable):
- Egress: request ke host non-allowlist →
EgressBlockedError(test). Loopback agy LS tetap lolos guard (test). - Credential: grep/test —
oauth_creds.json/token tak muncul dievents.payload/log; hanya dibaca. - Inject firewall: konfirmasi
injectIPC tanpa payload (test regresi cakup); token literal wrapper. - IPC DACL hardening:
statusvia IPC tak dump cwd tak perlu (data-minimize); residual R-5 tercatat. - Retensi: no-hard-delete state (
eventsappend-only) terverifikasi (test/review). - Tiap dari T-L1..T-L8 (THREAT-MODEL §8) → status "tutup" atau "residual + alasan".
Bukti verifikasi: paste
test/security-*.test.tshijau + ringkasan audit per-permukaan (persona security-review) + THREAT-MODEL §8 ter-update. Tier review: 1 (auth/IPC/egress/credential — inti keamanan; persona security-review skilltier-reviewtier 4).
M5.4 — Service Linux (systemd --user + lingering) template + skrip + LIVE [SANDBOX render + LIVE] — ✅ SANDBOX + LIVE PARSIAL (17 Jul)
✅ 17 Jul (Opus inline, Tier-1). Gate artefak DIDESAIN DULU (pelajaran I-34) lalu render:
test/systemd-unit.test.ts(struktur unit + render placeholder→assert<…>nol + Restart/RestartSec/Type/WantedBy + install-sh menyubstitusi tiap placeholder = celah I-34 ditutup) +test/shell-script.test.ts(LF/shebang/BOM floor lintas-OS +sh -ndepth) +deploy/linux/acca-daemon.service+scripts/install-linux.sh. 585 test (+15), 3 negative control terbukti konkret. LIVE (mesin Ubuntu) — AC-M5-1 PENUH: install→active, auto-restart SIGKILL ~5s (G-47), same-DB (kontras I-33), linger, logout + reboot auto-start terverifikasi owner (daemonactive+6s pasca-boot, PID baru). AC-M5-3 ✅ (job probe pending di-stage pada sesi EXITED → reboot → recovery-on-start fire 7s pasca-boot, no-op aman guard I-35). Semua AC Linux M5.4 (AC-M5-1 + AC-M5-3 paruh Linux) HIJAU. Paruh Windows AC-M5-2/M5-3 = M5.5 (ditunda/I-33). Slice: Template unitacca-daemon.service+ skrip install (systemctl --user enable --now+loginctl enable-linger), di-verify survive logout+reboot+auto-restart di Ubuntu asli. Scope file:deploy/linux/acca-daemon.service(template),scripts/install-linux.sh(baru),docsbagian install Linux. Di luar scope: Windows (M5.5), backup (M5.2). Generator template = string-render (testable); registrasi = LIVE. Kriteria selesai (testable):
- Template render dengan path
dist/cli/index.js daemon,Restart=on-failure,RestartSec(sandbox: assert isi unit). - [LIVE Ubuntu] install →
systemctl --user statusactive; logout→login → masih hidup (linger); reboot → auto-start; kill daemon → auto-restart <30s. (AC-M5-1) - [LIVE] reboot saat job LIMIT_HIT pending → job fire pasca-boot (AC-M5-3 paruh Linux).
Bukti verifikasi: assert render (sandbox) + [LIVE] paste
systemctl --user statuspasca-reboot + log recovery job. Tier review: 1 (service privilege + lifecycle; least-privilege runtime).
M5.5 — Autostart Windows per-user (Task Scheduler @logon) template + skrip + LIVE [RE-SCOPED ADR-026 — ✅ DITUTUP PENUH 18 Jul (SANDBOX + LIVE)]
✅ 18 Jul (Opus inline Tier-1, mesin Windows asli). Gate DIDESAIN DULU (I-34):
test/task-scheduler-xml.test.ts(18 test) — well-formed +---in-comment (gap ditemukan saat MENJALANKANSystem.Xml, naive tag-balance lolos) + ASCII + LogonTrigger/Principal(LeastPrivilege)/Hidden/PT0S/battery-safe/IgnoreNew/watchdog Repetition/RestartOnFailure
- render nol-remnant + substitusi-coverage
.ps1. Render:deploy/windows/acca-daemon.task.xml+scripts/install-windows.ps1/uninstall-windows.ps1(ter-gateps1-encodingG-44). LIVE (hampir penuh): lihat AC-M5-2 (identitas user + same-DB + creds + @logon-fire terkonfirmasi + watchdog-restart ~65s + nol-jendela via conhost; sisa = logon-final owner). 3 temuan LIVE mengubah artefak: (1)RestartOnFailureTAK andal restart proses di-kill → watchdog repetisi + IgnoreNew (G-49); (2) XML comment--ditolak parser sungguhan (G-50); (3)Hidden=trueTAK cegah jendela konsol node @logon → jalankan viaconhost.exe --headless(G-52). 615 test hijau. ♻ RE-SCOPED 17 Jul (ADR-026, owner Ziffan) — dari "Windows Service via WinSW" ke "autostart per-user via Task Scheduler @logon". Probe empiris (17 Jul) membuktikan Windows Service ≠ sesi user: default LocalSystem →acca.dbBERBEDA +.claude/.credentials.jsontak ada → produk mati SENYAP (I-33). Ganti jalur menyelesaikan I-33 by construction: Task Scheduler trigger "At log on" (current user) jalan sebagai user login → DB + kredensial benar, session-0 PTY tak relevan. Windows Service = jalur dorman (opsi host non-laptop, tetap ter-blok I-33; pin WinSW ADR-025 disimpan sah bila dibuka lagi — spec WinSW lama diarsipkan di bawah<details>/riwayat git). DILARANG Task Scheduler "run whether user is logged on or not" (butuh password/S4U → reintroduce I-33). DILARANG Startup-folder/Run-key polos sbg primary (nol restart + flash konsol). Butuh owner + mesin Windows asli (LIVE-only).
Slice: Template Task Scheduler XML (trigger LogonTrigger current-user + Settings restart-on-failure + <Hidden>true</Hidden>)
- skrip install
.ps1(Register-ScheduledTask/schtasks /create /xml+ idempotensi + uninstall), di-verify auto-start-saat-login - auto-restart + hidden di Windows asli.
Scope file:
deploy/windows/acca-daemon.task.xml(Task Scheduler template),scripts/install-windows.ps1+scripts/uninstall-windows.ps1(baru),docsbagian install Windows. Di luar scope: Linux (M5.4), backup, jalur Windows Service/WinSW (dorman — ADR-026). DILARANG dep npm baru. Kriteria selesai (testable):
- Gate artefak lintas-OS DULU (I-34, sebelum render):
.ps1ter-gatetest/ps1-encoding.test.ts(pure-ASCII/BOM — G-44); XML template ter-gate (well-formed + assertLogonTrigger+<UserId>current-user + restart-on-failure settings +<Hidden>true). Desain gate sebelum template di-render (pelajaran I-34). - Template Task Scheduler XML render dengan
Actions/Exec/Command=node,Arguments= path...\dist\cli\index.js daemon, trigger @logon current-user, restart-on-failure (RestartCount/RestartInterval),<Hidden>true</Hidden>(sandbox: assert isi XML). - Skrip install idempoten (task sudah ada → update, bukan gagal) + uninstall bersih (round-trip, ala
uninstall-linux.sh). - [LIVE Windows] install (nol admin, task per-user) → logout→login → daemon auto-start di sesi user; kill (SIGKILL) → auto-restart <30s; nol jendela konsol. Bukti I-33-proof:
acca statustunjukacca.dbSAMA (bukan DB kosong) +claudeter-spawn TERAUTENTIKASI (resume nyata). (AC-M5-2) - [LIVE] reboot→login saat job pending → fire pasca-login (AC-M5-3 paruh Windows). (Catatan: at-boot-pra-login TIDAK dituntut — logon-scoped, ADR-026.)
Bukti verifikasi: assert render + gate XML/
.ps1(sandbox) + [LIVE] pasteGet-ScheduledTask/schtasks /querypasca-login +acca status(DB sama) + log resume terautentikasi + log recovery. Tier review: 1 (autostart privilege boundary + spawn-agent path).
Slice: Quick-start lengkap (install/backup/restore/uninstall per-OS) + integration test M5 + security-review gate
menyeluruh (skill milestone-wrapup), menutup M5.
Scope file: README/docs/QUICKSTART.md, docs/CONTEXT.md, CHANGELOG; agregasi (tak sentuh src slice lain).
Di luar scope: implementasi slice (sudah di M5.1–5.5).
Kriteria selesai (testable):
- Quick-start: install service, konfigurasi, backup/restore, uninstall — lengkap per-OS, langkah admin ditandai.
- Integration test M5 (agregasi) hijau; AC-M5-1..9 tercentang (yang LIVE dengan bukti user).
- Security-review gate (persona,
milestone-wrapup): T-L1..T-L8 tertutup/residual; egress/credential/inject/retensi checklist lolos. Bukti verifikasi: quick-start lengkap + integration test hijau + laporan gate security-review (paste). Tier review: 1 (gate keamanan menyeluruh — persona security-review).
Ringkasan M5: 6 slice. Semua Tier 1 (state/keamanan/service-privilege). Dependency: M5.1→M5.2 (engine→skrip); M5.3 independen (bisa paralel M5.1/2 — scope file tak tumpang-tindih); M5.4/M5.5 paralel (OS beda, file beda) tapi keduanya butuh 1 pemegang mesin per-OS untuk LIVE; M5.6 terakhir (agregasi + gate). Slice [LIVE] (M5.2 sebagian, M5.4, M5.5, M5.6) WAJIB bukti dari mesin asli — DILARANG klaim hijau tanpa output user (COWORK-TOOLING-NOTES insiden 5).
- v1 (Nice): mode
askkonfirmasi resume (US-6), backoff cerdas (US-7), riwayat kaya (US-8), notifikasi eksternal opt-in (US-9). - v2+ (Later): dashboard web (US-10), adapter OpenCode & lain (US-11), multi-user/tim (US-12), prediksi proaktif (US-13).
PROJECT → ARCHITECTURE (+DECISIONS) → DATA-MODEL/CONTRACTS → NFR/CAPACITY/FAILURE/SECURITY → MILESTONES → MAP+CONVENTIONS. Sudah dibuat: THREAT-MODEL.md (✅ 3 Jul, gate tier C), DATA-MODEL.md (✅ 3 Jul malam, skema store), MAP.md (✅), CONVENTIONS.md (✅), DEPENDENCY-POLICY.md (✅) — fondasi M1 siap. File yang belum dibuat (menyusul saat dibutuhkan): FAILURE-MODES.md, SECURITY.md, CONTRACTS (adapter interface — bisa di kode M1).