docs: settle open design items + dogfood backlog
Resolve the five design-session open items from PLAN.md: - decisions.md: soft write-path, poll-only sync (NAT), lognormal cold-start priors, purity test binds the SQLite cache - pm-state.md: sidecar layout + directive/capacity/calibration schemas + lifecycle inference table - agent-tools.md: query_project read tool + three write tools Also gitignore .env.* (protect the gitea PAT) and record the P0 actual: 10 labels, 5 milestones, 34 tracer-bullet issues + 51 dependencies filed on christian/commitea as the first managed project. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
73
docs/decisions.md
Normal file
73
docs/decisions.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Settled design decisions
|
||||
|
||||
Resolves the "Open items for design session" in [PLAN.md](./PLAN.md). Dated
|
||||
2026-07-08. Companion docs: [pm-state.md](./pm-state.md) (sidecar formats),
|
||||
[agent-tools.md](./agent-tools.md) (tool schemas).
|
||||
|
||||
## D1 — Write path is soft, split by semantics
|
||||
|
||||
Chat (Reginald) is the write path for **PM-semantic** mutations; gitea-native
|
||||
content stays directly editable.
|
||||
|
||||
- **Through the agent** — estimates (`est/*`), priority (`p/*`),
|
||||
`deadline/hard`, milestone assignment, dependency edits, and directives.
|
||||
Additive ops act directly; destructive ops go propose-approve (Dialog or the
|
||||
consequence diff on the Directives screen).
|
||||
- **Direct, reconciled** — issue title/description, comments, assignees. Edit
|
||||
them in the CommiTea UI ("composer writes to gitea, as you") or in the gitea
|
||||
web UI; reconcile absorbs out-of-band edits because **gitea is the source of
|
||||
truth** for intent. The agent observes changes on the next reconcile and may
|
||||
object in standup, but never blocks them.
|
||||
|
||||
Rejected: strict (every write through chat). Hostile to quick edits and fights
|
||||
the reconcile-from-gitea model — an edit made in gitea's own web UI would be
|
||||
un-representable.
|
||||
|
||||
## D2 — Sync is poll + reconcile, no live webhooks in v1
|
||||
|
||||
`gitea.stephenmann.io` is remote and the desktop app sits behind NAT, so the
|
||||
server cannot POST to a localhost webhook. v1:
|
||||
|
||||
- **Reconcile on launch** — full read of the work repo(s) + `pm-state` repo into
|
||||
the local SQLite cache.
|
||||
- **Light poll while running** — `since`/conditional-request poll of issues and
|
||||
the issue timeline (target 30–60 s cadence; visible < 2 s is a webhook-era
|
||||
goal, relaxed to the poll interval for v1).
|
||||
- The change-source is an **interface** (`ChangeSource`) with a polling
|
||||
implementation; a webhook implementation can plug in later for a LAN /
|
||||
self-hosted / tunnelled instance without touching the reconcile core.
|
||||
|
||||
Rejected now: reachability-detection hybrid (moving parts, cleanup-on-quit),
|
||||
outbound tunnel (runtime dependency + public ingress). Both remain future
|
||||
options behind the same interface.
|
||||
|
||||
## D3 — Cold-start forecasts use lognormal per-bucket priors
|
||||
|
||||
Before the team has n ≥ 20 closed issues with estimates, Monte Carlo samples a
|
||||
**lognormal** actual-duration distribution per estimate bucket
|
||||
(`1d/2d/3d/5d/8d`), with a pessimism-skewed median (actuals run long). The
|
||||
priors live in code (`@commitea/core`), not in a data file. At n ≥ 20 the
|
||||
scheduler switches to the team's own empirical fit (see calibration model in
|
||||
[pm-state.md](./pm-state.md)); `byLabel` / `byPerson` bias terms layer on once
|
||||
their own sample sizes clear a floor.
|
||||
|
||||
Rejected: uniform pessimism multiplier (`actual = est × U[1.3, 2.0]`) — cruder,
|
||||
dishonest tails, no path to per-bucket calibration.
|
||||
|
||||
## D4 — Purity test applies to the SQLite cache, not the pm-state repo
|
||||
|
||||
The plan's invariant — *delete the sidecar → resync → no truth lost* — is about
|
||||
the **local SQLite cache**, which is a rebuildable index over two durable
|
||||
sources:
|
||||
|
||||
- **Work repo(s) in gitea** — human-authored intent (issues, milestones + due
|
||||
dates, dependencies, assignees, labels, comments).
|
||||
- **`pm-state` repo in gitea** — the sidecar's own durable truth that is *not*
|
||||
regenerable from the work repo: directive log, capacity config, charter, and
|
||||
the (cached-but-committed) calibration model.
|
||||
|
||||
Delete SQLite → rebuild from both repos → nothing lost. The `pm-state` repo is
|
||||
never the thing you delete; it is versioned and backed up in gitea like any
|
||||
other repo. Regenerable state (issue mirror, inferred lifecycle timestamps,
|
||||
Monte Carlo forecasts, focus snapshot) lives in SQLite only and is recomputed on
|
||||
rebuild. See [pm-state.md](./pm-state.md) for the file/table split.
|
||||
Reference in New Issue
Block a user