docs(canon): correct ADR-010 on divergence shapes, mechanism, and outcome
Three dated corrections, following the blockquote convention ADR-007 uses: - Decision 2's merge/refresh dichotomy is not exhaustive. Repository records took a third shape — cache-only records whose source exists and is reachable but was never introduced to central. Refreshing would have destroyed them. - The Context recorded the shared port but not why it was silent: an unbound ssh -L binds every loopback family, and ExitOnForwardFailure fires only when every bind fails. - A new Outcome section states that the ADR's own remediation never landed and the condition was still live seven weeks later. Refs CUST-WP-0067-T06 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
3c1e93186f
commit
563e7811b9
2 changed files with 91 additions and 1 deletions
|
|
@ -32,6 +32,20 @@ replica:
|
|||
Both listen on port 8000, separated only by IP family, so every tool defaulting
|
||||
to `127.0.0.1` reached the local instance while believing it was the primary.
|
||||
|
||||
> **Mechanism identified 2026-08-24 by `CUST-WP-0067`.** This ADR recorded the
|
||||
> shared port as the hazard but not why it was *silent*, which is the part that
|
||||
> let it persist. An `ssh -L` forward with no bind address listens on every
|
||||
> loopback family, and `ExitOnForwardFailure=yes` fires only when **every**
|
||||
> requested bind fails. The IPv4 bind lost to the local uvicorn, the IPv6 bind
|
||||
> succeeded, and the tunnel therefore reported success while serving an address
|
||||
> nothing resolved to by default. The collision was declared in
|
||||
> `~/.config/bridge/tunnels.yaml`, and `ops-bridge` guarded only tunnel against
|
||||
> tunnel, so a non-bridge listener was invisible to it.
|
||||
>
|
||||
> Fixed by pinning local forwards to `127.0.0.1`, so a contested port fails
|
||||
> loudly (`ops-bridge` commit `2213847`). A shared port is recoverable; a shared
|
||||
> port that reports healthy is not.
|
||||
|
||||
Measured divergence — 320 records exist locally but not on the primary:
|
||||
|
||||
```text
|
||||
|
|
@ -63,6 +77,23 @@ This replaces the peer-database arrangement. It is also why the divergence is
|
|||
tractable: a divergent database is a merge problem, a stale cache is a refresh
|
||||
problem.
|
||||
|
||||
> **Corrected 2026-08-24 by `CUST-WP-0067`.** Those two shapes are not
|
||||
> exhaustive, and repository records took a third one. Measured that day:
|
||||
> 122 repositories on the cache, 78 on central, **zero central-only**. A strict
|
||||
> subset in the cache's favour is neither a merge problem nor a refresh problem
|
||||
> — refreshing the cache would have *destroyed* the 44 extra records rather than
|
||||
> reconciling them, and central held no path to re-derive repositories it had
|
||||
> never been told existed.
|
||||
>
|
||||
> The third shape: **cache-only records whose authoritative source exists and is
|
||||
> reachable, but was never introduced to central.** Its remedy is re-derivation
|
||||
> from source — not refresh, not merge. Of the 44, 43 had a working copy, all 43
|
||||
> were pushed, and 34 carried a classification file; nothing was unrecoverable,
|
||||
> but nothing would have recovered itself either.
|
||||
>
|
||||
> Onboarding by date showed a clean break: central's repository registrations
|
||||
> stopped at 2026-07-08 while the workstation kept accepting them.
|
||||
|
||||
**3. Local work requires no hub at all.** Repository files are self-describing —
|
||||
identifier, status, tasks, all in frontmatter. Working in a repository requires
|
||||
reading files, not querying an index. A cache is an optimization for cross-repo
|
||||
|
|
@ -160,3 +191,42 @@ and by `hub-core` for hub-native records. Tracked under `RMGR-WP-0005`.
|
|||
- `RMGR-WP-0005` — registrar consolidation and deterministic identifiers
|
||||
- `STATE-WP-0068` — offline write buffer and edge relay (rescope candidate)
|
||||
- Divergence measurement, 2026-08-17: 955 local / 649 primary / 320 local-only
|
||||
|
||||
|
||||
## Outcome (2026-08-24)
|
||||
|
||||
> Added by `CUST-WP-0067`. This ADR read as though its remediation had landed.
|
||||
> It had not: the two-instance condition it measured on 2026-08-17 was still
|
||||
> live seven weeks later, and had continued to accumulate records the whole
|
||||
> time. An ADR that describes a fix in the present tense is easily mistaken for
|
||||
> a fix that happened — worth stating plainly for the ones that follow.
|
||||
|
||||
The peer-database arrangement is now resolved, by deletion rather than by
|
||||
reconciliation:
|
||||
|
||||
- **The local hub instance is retired.** Rather than making two instances
|
||||
coexist safely, the second one was removed. Exactly one process binds
|
||||
`127.0.0.1:8000` and it is the tunnel to central. Nothing remains that could
|
||||
impersonate the primary, and no call site needed editing — retiring the
|
||||
impersonator made the existing `127.0.0.1:8000` defaults correct.
|
||||
- **Decision 3 carried the argument.** Because local work requires no hub at
|
||||
all, and Repo Manager already maintains a file-derived index, the local
|
||||
instance was redundant rather than load-bearing.
|
||||
- **Repo Manager gained the write path it was already assigned.**
|
||||
`hub-record-authority.yaml` gives it `managed_repos` as `file-derived`, but it
|
||||
exposed no command for it; the only working path lived in the State Hub repo
|
||||
and defaulted to a local address. `rmgr repo-onboard` closes that, and refuses
|
||||
to onboard a repository whose backing file is uncommitted, unpushed, or has no
|
||||
upstream — a record whose source is only local cannot be re-derived, which is
|
||||
the failure this ADR exists to prevent.
|
||||
- **33 of the 44 were re-derived onto central**, taking it from 78 to 111
|
||||
repositories. The remaining 11 carry written dispositions rather than guessed
|
||||
values, per the orphan-disposition principle above.
|
||||
|
||||
One cause sat deeper than the topology: the hub resolved its classification
|
||||
allowed-values file from three hardcoded developer-workstation checkouts, so in
|
||||
a container every classification write failed. Repository classification could
|
||||
*only* be written from a workstation. That is a second instance of this ADR's
|
||||
own theme — authority that depends on where a process happens to run is not
|
||||
authority — and is why "central derives" had never been achievable for this
|
||||
record type.
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ only there.
|
|||
|
||||
```task
|
||||
id: CUST-WP-0067-T06
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "007bfcf1-3b17-5d4a-b16a-b80ebf273934"
|
||||
```
|
||||
|
|
@ -290,6 +290,26 @@ this record class and record the local-instance retirement as the outcome.
|
|||
Acceptance: ADR-010 revised with a dated superseding note linked to this
|
||||
workplan; `ops-bridge` and the port map documented as the structural fix.
|
||||
|
||||
**Done (2026-08-24):** three dated corrections added to `ADR-010`, following the
|
||||
in-file blockquote convention `ADR-007` already uses.
|
||||
|
||||
- **Decision 2** — the merge/refresh dichotomy is not exhaustive. Records the
|
||||
third shape: cache-only records whose authoritative source exists and is
|
||||
reachable but was never introduced to central, remedied by re-derivation
|
||||
rather than refresh or merge. Refreshing would have destroyed the 44.
|
||||
- **Context** — the ADR recorded the shared port but not why it was silent,
|
||||
which is the part that let it persist for seven weeks. An unbound `ssh -L`
|
||||
binds every loopback family and `ExitOnForwardFailure` fires only when all
|
||||
binds fail, so the tunnel reported success while serving an address nothing
|
||||
resolved to by default.
|
||||
- **Outcome section** — states plainly that the ADR's own remediation never
|
||||
landed, and that the condition it measured was still live seven weeks later.
|
||||
An ADR describing a fix in the present tense reads as a fix that happened.
|
||||
|
||||
Also records the deeper cause as a second instance of the ADR's own theme:
|
||||
the hub resolved its classification vocabulary from developer-workstation paths,
|
||||
so authority depended on where a process happened to run.
|
||||
|
||||
## Repoint the fleet's copied port map
|
||||
|
||||
```task
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue