29650ca512
Move to openspec/changes/archive/2026-07-09-per-instance-hook-scoping/ (R100 renames preserved). 9 artifacts. Canonical openspec/specs/ service-instance-scoping/ remains. Resolves multi-instance wrong-data bug (hooks now scope by instance.id; instance switcher re-scopes). Carry-overs: fetchBackupDashboard untouched (design decision 5); subquery scoping for runs/alerts (schema asymmetry).
175 lines
12 KiB
Markdown
175 lines
12 KiB
Markdown
# Sync Report — `per-instance-hook-scoping`
|
|
|
|
> Phase: **sync** · Change: `per-instance-hook-scoping` · Repo: `/home/user/manage`
|
|
> Mode: file-backed (`artifactStore: openspec`). No source-code edits; only OpenSpec artifacts were
|
|
> written. Not committed (parent owns the commit). The change folder was **not** moved (that is
|
|
> `sdd-archive`'s job). The flat `spec.md` was left in place as the authoritative planning artifact.
|
|
|
|
**Status: SYNCED.** A new canonical domain `openspec/specs/service-instance-scoping/spec.md` was
|
|
created from the verified change, and the change-side domain delta spec that unblocks the native
|
|
status engine's `sync`/`archive` gates is also in place.
|
|
|
|
---
|
|
|
|
## 1. Executive summary
|
|
|
|
The `per-instance-hook-scoping` change shipped a **complete but flat** `openspec/changes/per-instance-hook-scoping/spec.md`
|
|
(21 requirements, PI-101 … PI-121) with **no** per-domain delta spec under
|
|
`openspec/changes/per-instance-hook-scoping/specs/<domain>/`. `sdd-sync` requires a domain delta
|
|
spec; the flat spec alone does not satisfy the canonical-merge contract (native status engine
|
|
reported `specs: partial`, blockedReasons: "domain specs are missing or partial" + "Legacy flat spec
|
|
is present without domain specs").
|
|
|
|
Verify already returned **PASS** (verdict in `verify-report.md`; all five gates green — backend
|
|
`pytest` 368 passed, `ruff` clean, frontend `npm run build` exit 0, `npm run lint` 0 errors,
|
|
`npx vitest run` 46 files / 165 tests passed). Functional coverage was **21/21 requirements satisfied
|
|
against source**. The verify report's single CRITICAL was an **archive** blocker (17 unchecked task
|
|
checkboxes + missing `apply-progress.md`); per the dispatch brief, `apply-progress.md` has since been
|
|
reconciled and that condition does **not** block `sdd-sync` of the green code.
|
|
|
|
This sync **reconciles** the flat-spec-vs-domain-spec gap:
|
|
|
|
1. Authored the missing **change-side domain delta spec** —
|
|
`openspec/changes/per-instance-hook-scoping/specs/service-instance-scoping/spec.md` — using a pure
|
|
`## ADDED Requirements` structure that preserves the exact requirement IDs (PI-101 … PI-121) and
|
|
body text (including the per-requirement GIVEN/WHEN/THEN scenarios) from the verified flat
|
|
`spec.md`. This is what flips the native status engine's `specs` artifact from partial → done.
|
|
2. **Synced** the end-state into the **canonical store** —
|
|
`openspec/specs/service-instance-scoping/spec.md` — the actual sync target. Because the canonical
|
|
`service-instance-scoping` domain did not previously exist, the native helper rule applies: *when
|
|
the canonical spec does not exist, the change spec becomes the new canonical spec.* The two files
|
|
carry identical requirement bodies (delta under `## ADDED Requirements`; canonical under
|
|
`## Requirements`), verified identical for the requirement region.
|
|
|
|
Domain name **`service-instance-scoping`** was chosen (per the dispatch brief) because it names the
|
|
cross-cutting concern the change establishes: observability and backup service-type tabs/hooks must
|
|
scope to the operator-selected instance. It is distinct from the existing canonical domains
|
|
(`web-ui`, `prometheus-charting`, `service-storage`, `service-credential-testing`), none of which
|
|
were touched.
|
|
|
|
## 2. Structured status & actionContext findings
|
|
|
|
The native `gentle-pi.sdd-status` reports `state: blocked`, `artifactStore: openspec`,
|
|
`taskProgress: 17/17 complete`, `applyState: blocked`, and `blockedReasons` citing missing domain
|
|
specs + legacy flat spec present without domain specs. These blockers are **artifact-hygiene, not
|
|
implementation gaps**: the code is committed (`3bc7ce5`), all five gates are green, and 21/21
|
|
requirements pass against source. This sync resolves the missing-domain-spec condition; the
|
|
remaining `applyState`/checkbox hygiene is an **archive**-phase concern.
|
|
|
|
- `artifactStore: openspec`; change root `openspec/changes/per-instance-hook-scoping/`.
|
|
- Artifacts present: `proposal.md`, `spec.md` (flat), `design.md`, `tasks.md`, `verify-report.md`,
|
|
`apply-progress.md`.
|
|
- `verify: PASS` (verify-report verdict; gates green at `3bc7ce5`).
|
|
- `actionContext`: `mode: repo-local`, `workspaceRoot: /home/user/manage`,
|
|
`allowedEditRoots: ["/home/user/manage"]`, `warnings: []`. All three files written are inside the
|
|
authoritative workspace / allowed edit roots. ✓
|
|
- `relationships.sameDomainActiveChanges: []`, `collisions: []` — **no active same-domain
|
|
collisions**, so no archive/sync ordering decision was required.
|
|
- The new `service-instance-scoping` domain is distinct from the existing `web-ui`,
|
|
`prometheus-charting`, `service-storage`, and `service-credential-testing` canonical domains; all
|
|
four were left untouched.
|
|
|
|
**Post-sync structural change:** `openspec/changes/per-instance-hook-scoping/specs/service-instance-scoping/spec.md`
|
|
now exists (`hasDomainSpecs` → true), resolving the missing-domain-spec condition that gated sync.
|
|
The flat `spec.md` is intentionally **left in place** as the authoritative planning artifact the
|
|
work was built against (the archive convention keeps flat specs too); it no longer triggers the
|
|
"flat spec without domain specs" condition now that a domain delta sits alongside it.
|
|
|
|
## 3. Domains synced & canonical files updated
|
|
|
|
| Domain | Change-side delta (source) | Canonical (sync target) | Action |
|
|
|---|---|---|---|
|
|
| `service-instance-scoping` | `openspec/changes/per-instance-hook-scoping/specs/service-instance-scoping/spec.md` | `openspec/specs/service-instance-scoping/spec.md` | **NEW domain** — `## ADDED Requirements` copied into canonical as a new spec |
|
|
|
|
- **Canonical file created:** `openspec/specs/service-instance-scoping/spec.md` (21 requirements).
|
|
- **Change-side delta created:** `openspec/changes/per-instance-hook-scoping/specs/service-instance-scoping/spec.md`
|
|
(21 requirements, all `## ADDED Requirements`).
|
|
|
|
## 4. Requirement delta (ADDED / MODIFIED / REMOVED)
|
|
|
|
- **ADDED (21)** — all to the new `service-instance-scoping` domain (canonical did not exist
|
|
pre-change). IDs and text preserved verbatim from the verified flat `spec.md`. Grouped logically:
|
|
- *Frontend hooks (serviceId param + queryKey)* — PI-101, PI-102, PI-103, PI-104, PI-105, PI-106, PI-107
|
|
- *API client functions (serviceId → query param)* — PI-108, PI-109
|
|
- *Backend backup endpoints (service_id filter)* — PI-110, PI-111, PI-112
|
|
- *Tabs pass instance.id (TODO comments removed)* — PI-113, PI-114, PI-115, PI-116
|
|
- *Non-regression (dashboard widgets, global hooks untouched)* — PI-117
|
|
- *Backward compatibility* — PI-118
|
|
- *Test + build greenness* — PI-119, PI-120, PI-121
|
|
- **MODIFIED (0)** — none (new domain; no pre-existing canonical requirements to replace).
|
|
- **REMOVED (0)** — none.
|
|
- **RENAMED (0)** — none (RENAMED is intentionally unsupported by the native delta helper; not used).
|
|
|
|
## 5. Guardrails, approvals & destructive-sync assessment
|
|
|
|
- **Same-domain collisions:** none (`sameDomainActiveChanges: []`, `collisions: []`). The new
|
|
`service-instance-scoping` domain does not overlap the existing `web-ui`, `prometheus-charting`,
|
|
`service-storage`, or `service-credential-testing` canonical domains. No ordering decision was
|
|
needed.
|
|
- **Destructive sync:** **not applicable.** There are zero REMOVED requirements and zero large
|
|
MODIFIED blocks (new domain; everything is ADDED). No destructive-sync parent approval was
|
|
required for this sync beyond the explicit reconciliation instruction in the dispatch brief.
|
|
- **Legacy flat spec:** detected pre-sync; resolved by adding the domain delta spec alongside it
|
|
(the block condition is specifically "flat spec *without* domain specs"). The flat spec was left
|
|
in place as a planning artifact.
|
|
- **Canonical isolation:** the existing `openspec/specs/web-ui/spec.md`, `openspec/specs/prometheus-charting/spec.md`,
|
|
`openspec/specs/service-storage/spec.md`, and `openspec/specs/service-credential-testing/spec.md`
|
|
were **not modified** — verified untouched (see §6).
|
|
|
|
## 6. Validation / checks performed (file-backed, read-only)
|
|
|
|
Run from `/home/user/manage` (no source edits, no test re-runs — those are owned by verify and were
|
|
already green at `3bc7ce5`):
|
|
|
|
| Check | Command | Result |
|
|
|---|---|---|
|
|
| Canonical store populated | `ls openspec/specs/service-instance-scoping/spec.md` | present ✓ |
|
|
| Change-side domain spec present | `ls openspec/changes/per-instance-hook-scoping/specs/service-instance-scoping/spec.md` | present ✓ |
|
|
| Requirement-ID parity (flat ↔ delta ↔ canonical) | `grep -oE 'PI-[0-9]+'` all three files, `sort -u` | **21 == 21 == 21**, identical IDs PI-101…PI-121 ✓ |
|
|
| Body-text parity (delta ↔ canonical) | `diff` of the `### Requirement:` region of both files | **identical** ✓ |
|
|
| Delta is pure ADDED | count `## ADDED/MODIFIED/REMOVED/RENAMED Requirements` | ADDED=1, MODIFIED=0, REMOVED=0, RENAMED=0 ✓ (no destructive sync) |
|
|
| Other canonicals untouched | `git status --porcelain openspec/specs/{web-ui,prometheus-charting,service-storage,service-credential-testing}/` | empty (not modified) ✓ |
|
|
| No edits outside openspec | `git status --porcelain` (filtered) | only the three new OpenSpec files added; no source files touched ✓ |
|
|
| Markdown validity | write-time lint | all three files "Markdown clean" ✓ |
|
|
|
|
## 7. Carry-over items for the archive summary
|
|
|
|
These verify-phase findings are non-blocking for sync and should land in the archive summary:
|
|
|
|
1. **[CRITICAL-process, archive-only] Task-checkbox / apply-progress hygiene.** At verify time, 17
|
|
implementation task checkboxes were unchecked and `apply-progress.md` was missing. Per the
|
|
dispatch brief, `apply-progress.md` has been reconciled (native status now reports 17/17
|
|
complete); `sdd-archive` should re-scan the native status engine to confirm `apply: done` /
|
|
`applyProgress: present` and tick any remaining unchecked boxes before moving the change to
|
|
archive.
|
|
2. **[INFO, NB-1] Spec↔design wording mismatch on PI-109 / PI-110.** The flat spec literally lists
|
|
`fetchBackupDashboard` / `get_backup_dashboard` as in-scope for a new service param, while design
|
|
decision 5 and tasks 1.5/1.9 deliberately exclude them (dashboard widget path; PI-117 risk). The
|
|
implementation correctly follows the design. This delta/canonical preserved the flat spec text
|
|
**verbatim** (PI-109 / PI-110 still mention the dashboard variants) per the sync fidelity rule
|
|
(do not rewrite verified requirements during sync). If `sdd-archive` wants spec and design to
|
|
agree, it can amend in a follow-up change; no functional defect.
|
|
3. **[INFO, NB-2] Weak hook-test assertion (PI-121).** The `useBackups.test.ts` "different keys"
|
|
assertion (`expect(a).not.toBe(b)` on `renderHook` result refs) is tautology-prone. The wiring is
|
|
correct in source and the tab test is strong; recommend strengthening the hook test in a future
|
|
pass. Non-blocking.
|
|
4. **[INFO] Stale generated `.pi-map.md`** files still reference the pre-change signatures
|
|
(e.g. `list_backup_jobs(self)` without `service_id`). Generated artifacts, not deliverable source;
|
|
reconcile via `project_map_patch` / `project_map_validate` when convenient.
|
|
|
|
## 8. Next recommended phase
|
|
|
|
→ **`sdd-archive`** (clean). Confirm the native status re-scan reports `specs: done` / `sync: ready`
|
|
/ `archive: ready`, then move the change to
|
|
`openspec/changes/archive/YYYY-MM-DD-per-instance-hook-scoping`, carrying over the items in §7 into
|
|
the archive summary. Do **not** commit or push — the parent owns the commit with explicit paths.
|
|
|
|
---
|
|
|
|
### Appendix — Files written by this sync (OpenSpec only; no source code)
|
|
|
|
- `openspec/changes/per-instance-hook-scoping/specs/service-instance-scoping/spec.md` — **change-side
|
|
domain delta (`## ADDED Requirements`), 21 requirements PI-101…PI-121.**
|
|
- `openspec/specs/service-instance-scoping/spec.md` — **canonical spec (new domain), 21 requirements.**
|
|
- `openspec/changes/per-instance-hook-scoping/sync-report.md` — this report.
|