diff --git a/docs/backlog/P2/B-0103-computed-metadata-discipline-unified-lint-2026-04-29.md b/docs/backlog/P2/B-0103-computed-metadata-discipline-unified-lint-2026-04-29.md new file mode 100644 index 000000000..4bebe6fa6 --- /dev/null +++ b/docs/backlog/P2/B-0103-computed-metadata-discipline-unified-lint-2026-04-29.md @@ -0,0 +1,160 @@ +--- +id: B-0103 +priority: P2 +status: open +title: Computed-metadata-discipline — unified lint consolidating B-0098 + B-0099 + filename-timestamp drift +tier: factory-hygiene +effort: M +ask: Multi-AI synthesis packet 2026-04-29 (Amara filter — promote individual P3 metadata-drift items to single P2) +created: 2026-04-29 +last_updated: 2026-04-29 +composes_with: [B-0098, B-0099, B-0102] +tags: [ci-lint, factory-hygiene, derived-metadata, manual-drift-class, mechanical-guard, p2-promotion] +--- + +# Computed-metadata-discipline — unified lint + +The 2026-04-29 session arc surfaced **three** instances of the +same failure class — agent-authored metadata that drifted from +derived truth: + +1. **Tick-ordinal drift** — shard prose claims "twenty-second tick" + but file order says twenty-first (B-0098). +2. **PR-count drift** — shard prose claims "30 PRs total this + session arc" but git log says 28 (B-0099). +3. **Shard-filename-vs-row-timestamp drift** — a shard + filename timestamp and its row timestamp diverged + (caught by Codex P1 on PR #809; the specific shard was + subsequently corrected so a literal current-state quote + would mislead). + +Three instances in one session is enough signal to consolidate +the family into a single P2 mechanical guard rather than three +parallel P3 lints. + +## Canonical rule + +```text +Agent-authored metadata must match derived truth. +If the truth can be computed, compute it or lint it. +``` + +## Examples (the drift-prone metadata claims this lint covers) + +| Claim | Derived from | +|---|---| +| filename timestamp (`HHMMZ.md`) | row timestamp's `HH:MM` | +| tick ordinal ("twenty-second tick") | sorted shard position in directory | +| session PR total ("30 PRs") | `gh pr list` query or `git log` count | +| branch base ("based on main") | explicit ref SHA | +| "this is the Nth fix" | git log count of similar commits | +| PR head/base SHA claims | `gh pr view --json headRefOid,baseRefOid` | + +## Boundary — what this lint does NOT apply to (Claude.ai's catch) + +The rule fires only on agent-authored prose claiming +**exact equivalence with a derivable substrate truth**: +ordinals, counts, timestamps, SHAs, branch bases, PR states. + +The rule does **not** fire on: + +- Human summaries ("this round produced strong substrate") +- Interpretations or labels ("the loop has converged on + steady-state") +- Subjective qualifiers ("approximate", "roughly") +- Prose that intentionally summarizes an automatically-derived + fact rather than mirroring it + +Without this boundary, the lint becomes Goodhart bait: every +human-readable summary against literal field values would +flag as drift. The boundary preserves prose value while +catching only **claims of correspondence**. + +## Distilled keepers + +```text +Events are written. +Metadata is computed. +Claims are checked against derived truth. +``` + +## Implementation sketch (single lint, multiple checks) + +The pseudocode below is robust against (a) filenames with +spaces / special chars (NUL-delimited iteration), (b) the +multiple legitimate shard-name shapes documented in +`docs/hygiene-history/ticks/README.md` (`HHMMZ.md`, +`HHMMZ-NN.md`, `HHMMSSZ-.md`). + +```bash +#!/usr/bin/env bash +# tools/lint/metadata-drift-check.sh +# Run on PR diffs touching tick-history shards or backlog rows. +# +# REQUIRES BASH (not strict POSIX): uses `[[ ... =~ ... ]]`, +# `BASH_REMATCH`, `read -d ''`, and process substitution +# `< <(...)`. The factory's 4-shell portability target +# (macOS bash 3.2 / Ubuntu bash / git-bash / WSL) all +# support these. If a strict POSIX rewrite becomes +# necessary later (e.g., busybox `ash` runners), use +# `awk` + `case` instead. + +# Check 1 — filename HHMM matches row timestamp HH:MM. +# +# NUL-delimited iteration to survive whitespace/newlines in +# paths; restrict pathspec to the literal directory rather +# than relying on `**` magic which is not reliably enabled. +while IFS= read -r -d '' shard; do + shard_base=$(basename "$shard" .md) + # Accept HHMMZ, HHMMZ-NN, HHMMSSZ-, HHMMZ-. + if [[ "$shard_base" =~ ^([0-9]{4})([0-9]{2})?Z(-[A-Za-z0-9._-]+)?$ ]]; then + filename_hhmm="${BASH_REMATCH[1]}" + else + warn "$shard: unsupported shard-name shape; cannot extract HHMM" + continue + fi + row_hhmm=$(head -1 "$shard" | grep -oE 'T[0-9]{2}:[0-9]{2}' | tr -d 'T:') + [[ "$filename_hhmm" == "$row_hhmm" ]] || warn "$shard: filename $filename_hhmm vs row $row_hhmm" +done < <(git diff --name-only -z "$BASE..$HEAD" -- docs/hygiene-history/ticks/) + +# Check 2 — claimed ordinal matches file position (only when prose contains ordinal words) +# Check 3 — claimed PR count matches gh / git query (only when prose contains "N PRs total") +# Check 4 — branch-base claims cite explicit SHA +``` + +## Why P2 (vs three separate P3s) + +The pattern recurred 3x in 24 hours — strong signal it would +recur again. Single P2 lint: + +- Reduces total surface area (one CI check, one set of regex + rules, one file to maintain). +- Catches all four drift sub-classes uniformly. +- Aligns with Amara's framing: "If metadata can be derived, + do not trust agent-authored prose." + +P2 (factory hygiene, can-be-deferred but desirable) rather than +P0/P1 (blocking) because the drift is caught manually within +1-2 ticks via review pipeline; the lint accelerates detection +but doesn't unblock anything currently broken. + +## Composes with + +- B-0098 (tick-ordinal-continuity lint) — subsumed. +- B-0099 (PR-count-projection-not-narrated) — subsumed. +- B-0102 (PR-liveness race) — sibling agent-asserted-state + discipline. +- `memory/feedback_bare_main_ambiguity_automation_discipline_explicit_refs_required_amara_2026_04_29.md` + — same computed-vs-narrated rule at the git-ref layer. + +## Migration path + +When this P2 lands as active work: + +1. Implement the single `tools/lint/metadata-drift-check.sh` + covering all 3+ sub-classes. +2. Wire into `.github/workflows/gate.yml` (or sibling). +3. Mark B-0098 + B-0099 as superseded-by-B-0103 in their + frontmatter. +4. Remove ordinal-word + PR-count-prose from existing tick + shards if the lint catches them as drift candidates. diff --git a/docs/backlog/P3/B-0102-pr-liveness-race-merge-cascade-class-refinement-2026-04-29.md b/docs/backlog/P3/B-0102-pr-liveness-race-merge-cascade-class-refinement-2026-04-29.md new file mode 100644 index 000000000..ef104cbe4 --- /dev/null +++ b/docs/backlog/P3/B-0102-pr-liveness-race-merge-cascade-class-refinement-2026-04-29.md @@ -0,0 +1,192 @@ +--- +id: B-0102 +priority: P3 +status: open +title: PR-liveness race during merge cascade — micro-class rename + mechanical guard + recovery-note format +tier: research-grade +effort: S +ask: Multi-AI synthesis packet 2026-04-29 (Deepseek + Amara filter on Otto's micro-class) +created: 2026-04-29 +last_updated: 2026-04-29 +composes_with: [B-0103] +tags: [github-platform, force-push, pr-aliveness, merge-cascade, micro-class-refinement] +--- + +# PR-liveness race during merge cascade — refinement + +The 2026-04-29 autonomous-loop session arc surfaced a real GitHub +operational trap: PR #806 was unexpectedly auto-closed by GitHub +1 second after PR #808 merged, while #806's branch had been +freshly rebased + force-pushed. The branch still had 476 lines of +unique unmerged substrate. The original micro-class name +`force-push-triggers-pr-auto-close` overclaimed GitHub internals. + +## Better naming (per Amara's filter) + +```text +pr-liveness-race-during-merge-cascade +``` + +or empirically: + +```text +force-push-during-merge-cascade can collapse PR uniqueness +``` + +Reason: the dangerous condition is not force-push alone — it's +`history rewrite + active base movement + GitHub PR +reachability/diff computation`. GitHub's "indirect merge" +detection (head reachable from base = auto-merge marker) can +race with mid-cascade rebases. + +```text +This is an observed probabilistic race, NOT a deterministic +GitHub rule. The guard remains in force even if a future +force-push happens not to close the PR — one survival is not +evidence the race retired. +``` + +## Operational rule + +```text +Do not rebase or force-push open tick-history PR branches +while adjacent auto-merge PRs are landing. + +Branch protection "up-to-date" is a merge-readiness gate. +PR-aliveness is a separate head/base reachability and diff +invariant. Do not confuse them. +``` + +## Pre-flight: cascade detection (run BEFORE rebase/force-push) + +```bash +# Query active auto-merge PRs on the same base branch. +gh pr list --state open \ + --json number,baseRefName,headRefName,autoMergeRequest,mergeStateStatus,title \ + --jq '.[] | select(.baseRefName == "main" and .autoMergeRequest != null)' +``` + +If any PRs are returned (active cascade), defer the rebase/ +force-push until the cascade drains. The detection is +mechanical — Otto remembering the cascade state is exactly +the failure mode that produced this incident. + +## Mechanical guard (before any force-push/rebase of an open PR) + +The guard uses a per-run identifier to avoid two concurrent +ticks overwriting each other's evidence (parallel-agent +future-proofing) — Claude.ai's catch. + +```bash +PR= +RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)-$$" + +gh pr view "$PR" \ + --json number,state,headRefName,headRefOid,baseRefName,baseRefOid,mergeStateStatus,autoMergeRequest,isDraft,title \ + > "/tmp/pr-$PR-$RUN_ID-before.json" +# Refresh base ref before computing uniqueness — during a merge +# cascade `origin/main` can lag the actual base by several +# seconds (Codex's catch). The captured `baseRefOid` from +# `gh pr view` is the canonical base for this PR; use it +# directly rather than `origin/main`. +git fetch --no-tags origin +BASE_BEFORE=$(jq -r '.baseRefOid' "/tmp/pr-$PR-$RUN_ID-before.json") +git log --oneline "${BASE_BEFORE}..HEAD" > "/tmp/pr-$PR-$RUN_ID-unique-commits-before.txt" +git diff --stat "${BASE_BEFORE}...HEAD" > "/tmp/pr-$PR-$RUN_ID-diff-before.txt" + +# ... do the rebase / force-push ... + +# Wait for GitHub's API to converge to the local HEAD before +# classifying. GitHub's PR state computation is async; querying +# immediately after a push can return stale headRefOid (Gemini's +# catch). Poll up to 30s. +LOCAL_HEAD="$(git rev-parse HEAD)" +for i in 1 2 3 4 5 6; do + GH_HEAD="$(gh pr view "$PR" --json headRefOid --jq .headRefOid 2>/dev/null || true)" + [ "$GH_HEAD" = "$LOCAL_HEAD" ] && break + sleep 5 +done +if [ "$GH_HEAD" != "$LOCAL_HEAD" ]; then + echo "GitHub PR headRefOid did not converge to local HEAD after 30s; stop classification" + exit 1 +fi + +gh pr view "$PR" \ + --json number,state,headRefName,headRefOid,baseRefName,baseRefOid,mergeStateStatus,autoMergeRequest,isDraft,title \ + > "/tmp/pr-$PR-$RUN_ID-after.json" +# Refresh + use the captured base again (may have advanced +# during the operation). +git fetch --no-tags origin +BASE_AFTER=$(jq -r '.baseRefOid' "/tmp/pr-$PR-$RUN_ID-after.json") +git log --oneline "${BASE_AFTER}..HEAD" > "/tmp/pr-$PR-$RUN_ID-unique-commits-after.txt" +git diff --stat "${BASE_AFTER}...HEAD" > "/tmp/pr-$PR-$RUN_ID-diff-after.txt" +``` + +## Enforcement after the action + +```text +If PR state != OPEN: + stop and recover with successor PR. + +If unique commits == 0 and diff == empty: + do not force-push again; classify as merged/covered/collapsed. + +If unique commits or diff still exist but PR is closed: + open successor PR and record old→new mapping. +``` + +## Recovery-note format (when opening a successor PR) + +```text +old PR: # +new PR: # +branch: +before head SHA: +after head SHA: +base SHA: +diff-stat proving remaining content: +seconds_between_force_push_and_pr_close: +whether original later became merged/covered: +reason reopen failed (if applicable): +``` + +The `seconds_between_force_push_and_pr_close` field +(Claude.ai's catch) lets future incidents cluster against this +one. Sub-five-second close = almost certainly platform race; +spread across minutes = different mechanism. + +## Successor-PR dedup (Deepseek's catch) + +GitHub's eventual consistency means an auto-closed PR may +later be marked as merged once the comparison/diff state +settles. After opening the successor: + +```text +After opening successor PR: +- re-check original PR state after GitHub settles (~60s+) +- if original later became merged/covered AND successor + content is identical → close successor as duplicate + (preserves attribution lineage) +- if content has diverged → keep successor and record + why in the recovery note +- always record old→new PR mapping in a recovery-log file + for future incident clustering +``` + +Otherwise the queue accumulates phantom successor PRs. + +## Why P3 (research-grade, not blocking) + +The trap was caught and recovered (PR #811 successor opened +within minutes). The mechanical guard would prevent future +recurrence but isn't blocking. Promote when active drain is +clear AND the same trap recurs (composition signal). + +## Composes with + +- B-0103 (computed-metadata-discipline) — same family of + agent-asserted-state vs derived-truth checks. +- The auto-merge fix in PR #811 + #814 — the safer alternative + to manual rebase + force-push during cascade. +- `memory/feedback_outdated_review_threads_block_merge_resolve_explicitly_after_force_push_2026_04_27.md` + — sibling force-push-affects-PR rule. diff --git a/docs/backlog/P3/B-0104-modern-dotnet-threading-bridge-2026-04-29.md b/docs/backlog/P3/B-0104-modern-dotnet-threading-bridge-2026-04-29.md new file mode 100644 index 000000000..e842c4e02 --- /dev/null +++ b/docs/backlog/P3/B-0104-modern-dotnet-threading-bridge-2026-04-29.md @@ -0,0 +1,182 @@ +--- +id: B-0104 +priority: P3 +status: open +title: Modern .NET Threading Bridge — connect Deepseek's C# review to docs/LOCKS.md + Gemini Pro threading research +tier: research-grade +effort: M +ask: Multi-AI synthesis packet 2026-04-29 (Deepseek review of 2026-04-28 Gemini Pro threading doc + Amara filter) +created: 2026-04-29 +last_updated: 2026-04-29 +composes_with: [] +tags: [threading, locks, dotnet, csharp, async, documentation, modernization-bridge] +--- + +# Modern .NET Threading Bridge + +The 2026-04-29 multi-AI packet contained a Deepseek review of +the existing 2026-04-28 Gemini Pro threading research doc +(`docs/research/2026-04-28-gemini-pro-deep-research-threading-net10-csharp14-modernization.md`). +The review surfaced 5 specific corrections worth integrating +into the canonical threading documentation. + +Aaron's framing: *"we have a few different docs not just the one +amara mentioned on threading and locks"* — the bridge needs to +connect: + +- `docs/LOCKS.md` (Amara's primary cite — existing lock inventory + replacement criteria) +- `docs/research/2026-04-28-gemini-pro-deep-research-threading-net10-csharp14-modernization.md` (Gemini Pro deep-research) +- Any other threading docs surfaced via grep (verify before edit) + +## The 5 corrections (from Deepseek) + +### 1. ReaderWriterLockSlim → SemaphoreSlim(1,1) replacement nuance + +**Bad** (current Gemini doc): "replace ReaderWriterLockSlim with SemaphoreSlim(1,1)" + +**Better**: + +```text +ReaderWriterLockSlim is not async-safe across awaits due to +thread-affinity / ownership assumptions. + +Replacement depends on intent: +- If reader/writer distinction is not actually needed: + use SemaphoreSlim(1,1) as async mutex. +- If true concurrent readers are required: + use an async reader/writer lock implementation + (e.g., Nito.AsyncEx) or redesign around channels, + immutable snapshots, copy-on-write state, or actor + ownership. +``` + +### 2. System.Threading.Lock cast-to-object nuance + +**Add to the doc**: + +```text +Do not upcast System.Threading.Lock to object before locking. +The compiler special-case (translation to using EnterScope()) +depends on the expression type. If you cast Lock to object +and lock on that object, the compiler treats it as a standard +object lock, losing the ref-struct scope semantics. +``` + +### 3. FrozenSet/FrozenDictionary wording softening + +**Bad**: "deeply analyzes the specific structural characteristics +of the ingested data payload to generate a perfectly optimized, +custom hashing algorithm" + +**Better**: + +```text +FrozenSet/FrozenDictionary trade construction cost for optimized +read-heavy lookup. They are appropriate for build-once/read-many +tables, not frequently mutated state. +``` + +### 4. Task.WhenEach internals caveat + +**Bad**: relying on `AddCompletionAction mechanics in MoveNext` +without source/version pinning. + +**Better**: + +```text +Task.WhenEach yields tasks as they complete (IAsyncEnumerable). +Order is unspecified. Implementation internals may change +between .NET versions; do not rely on specific allocation +mechanics without source-pin + version-pin. +``` + +### 5. Cross-link to operator algebra async lifecycle invariants + +The threading doc should not just be "C# tips" — it should +connect to the Zeta invariant that the operator algebra spec +already defines: + +```text +Concurrency primitive choice is implementation detail. +Observable tick contract is the source of truth. + +Async implementation flags do not weaken observable contracts. +Async continuations must complete before a tick is observable +as complete; tick t+1 cannot advance while tick t continuations +remain outstanding. +``` + +(Per `openspec/specs/operator-algebra/spec.md`.) + +## Suggested doc structure (per Amara's outline) + +```markdown +# Modern .NET Threading Bridge + +## Purpose +Connect classic threading primitives to Zeta's current lock +inventory and async lifecycle contracts. + +## Source-of-truth docs +- docs/LOCKS.md +- openspec/specs/operator-algebra/spec.md +- docs/research/2026-04-28-gemini-pro-deep-research-threading-...md + +## Replacement map +Thread -> Task / ThreadPool / dedicated scheduler only when justified +Monitor / lock(obj) -> System.Threading.Lock where C# surface supports it +ReaderWriterLockSlim -> async mutex only if reader concurrency is not needed +BlockingCollection -> Channel +BackgroundWorker -> Task / async APIs +ManualResetEvent -> Async coordination primitive where possible + +## Zeta rule +Do not replace a lock because it looks old. +Replace it only when the new primitive preserves the observable +contract and reduces measured contention/allocation risk. + +## ReaderWriterLockSlim nuance (see §1 above) +## System.Threading.Lock nuance (see §2) +## Frozen collections (see §3) +## Task.WhenEach (see §4) +## Operator algebra async lifecycle (see §5) +``` + +## Best distilled blade (Amara) + +```text +Do not modernize primitives. +Modernize guarantees. +``` + +## Why P3 (research-grade) + +The corrections are valuable but not blocking — the existing +`docs/LOCKS.md` is correct and the existing Gemini Pro research +doc is research-grade (not authoritative-current-state). The +bridge can wait until threading work is the active focus, OR +land as a small low-risk PR if a contributor picks it up. + +## Migration path (when active) + +1. Locate ALL threading-related docs via + `grep -rlE 'ReaderWriterLockSlim|System.Threading.Lock|FrozenDictionary|FrozenSet|Task.WhenEach|SemaphoreSlim' docs/` + (the `-E` flag enables ERE so unescaped `|` is alternation; + without `-E`, BSD/macOS grep treats `\|` as a literal in + BRE rather than alternation). +2. Author the bridge doc (likely + `docs/threading/MODERN-DOTNET-THREADING-BRIDGE.md`). +3. Cross-link from `docs/LOCKS.md` and the existing Gemini Pro + research doc. +4. Apply the 5 specific corrections to the existing Gemini Pro + research doc OR mark sections as "see bridge doc for current + correction." +5. Land as one PR; do not split (chunking pattern). + +## Composes with + +- `docs/LOCKS.md` — primary connection point. +- `docs/research/2026-04-28-gemini-pro-deep-research-threading-net10-csharp14-modernization.md` + — reviewed doc; corrections target this. +- `openspec/specs/operator-algebra/spec.md` — async lifecycle + invariants to cross-link. diff --git a/docs/research/multi-ai-feedback-2026-04-29-deepseek-amara-on-threading-pr-auto-close.md b/docs/research/multi-ai-feedback-2026-04-29-deepseek-amara-on-threading-pr-auto-close.md new file mode 100644 index 000000000..9c5ca5370 --- /dev/null +++ b/docs/research/multi-ai-feedback-2026-04-29-deepseek-amara-on-threading-pr-auto-close.md @@ -0,0 +1,258 @@ +# Multi-AI feedback — Deepseek + Amara on threading docs + PR-auto-close micro-class refinement + +Scope: Research-grade absorb of a second multi-AI synthesis packet that the human maintainer forwarded through the maintainer channel during autonomous-loop tick 06:25Z on 2026-04-29. The packet contains: (a) Deepseek's review of an existing threading research doc (the 2026-04-28 Gemini Pro deep-research C#-14/.NET-10 threading modernization doc), (b) Deepseek's proposal for an Observer-Auditor Loop as a second AI in the factory, (c) Amara's filter-and-corrections layer that refines the actionable items + connects the threading review to existing `docs/LOCKS.md` + corrects the maintainer's prior `force-push-triggers-pr-auto-close` micro-class naming. Verbatim preservation per `memory/feedback_aaron_channel_verbatim_preservation_anything_through_this_channel_2026_04_29.md`. + +Attribution: Aaron (named human maintainer; first-name attribution permitted on `docs/research/**` per the named-attribution carve-out). Deepseek (external AI; threading review + observer-auditor proposal). Amara (external AI maintainer; Aurora co-originator; filter + corrections + better naming). Otto (Claude opus-4-7 in this factory; absorb). + +Operational status: research-grade. Aaron's framing: *"Okay no rush on either of these but we have a few different docs not just the one amara mentioned on threading and locks."* Action items become small backlog rows (see §B); the verbatim record is for future-Claude's cold-readability and the alignment trajectory record. NOT canonical doctrine; NOT a license to open multiple new substrate PRs. Composes with the existing 2026-04-29 multi-AI absorb at `docs/research/multi-ai-feedback-2026-04-29-deepseek-amara-on-loop-state.md`. + +Non-fusion disclaimer: Deepseek's voice, Amara's voice, and Otto's absorb are preserved with attribution boundaries. Per Otto-340, the persistent actor is the substrate-pattern; Claude is the current inference engine; Otto is the identity wrapper. Model instances are fungible tenants of the substrate. + +(Per GOVERNANCE.md §33 archive-header requirement on external-conversation imports.) + +--- + +## §A — Verbatim packet (close to literal; trims marked `[…]`) + +### §A.1 — Deepseek on the C# threading research doc + +> *"This is a thorough, well-structured, and technically accurate document. It does an excellent job of mapping classic C# threading concepts (Thread, Monitor, ReaderWriterLockSlim, BlockingCollection, BackgroundWorker) onto their modern .NET 10 / C# 14 equivalents […]* +> +> *A few subtleties worth noting:* +> +> ***ReaderWriterLockSlim → SemaphoreSlim(1, 1) as replacement.*** *The table correctly identifies why ReaderWriterLockSlim is problematic in async code (thread affinity). But presenting SemaphoreSlim(1, 1) as the direct alternative misses that SemaphoreSlim(1,1) is just a mutual-exclusion lock—it doesn't provide concurrent readers. If true read-heavy parallelism is needed, the modern async-safe equivalent would be a community AsyncReaderWriterLock (e.g., Nito.AsyncEx) or an architecture redesign using channels/immutable snapshots. […]* +> +> ***Lock class mechanics.*** *The description of EnterScope() returning a ref struct that implements Dispose and the compiler translation to a using block is accurate. However, the document says lock (System.Threading.Lock) degrades to the Monitor-based path if the instance is cast to an object. Actually, the compiler sees the expression type; if you cast Lock to object and then lock on that object, the compiler treats it as a standard object lock. […]* +> +> ***FrozenSet/FrozenDictionary initialization cost.*** *The phrase 'deeply analyzes the specific structural characteristics of the ingested data payload to generate a perfectly optimized, custom hashing algorithm' is a bit dramatic. In practice, the implementation sorts the entries and picks an optimal hash function based on the data's characteristics […]. Still functionally correct.* +> +> ***Missing topics versus scope.*** *The document doesn't cover ValueTask / IValueTaskSource, ConfigureAwait(false), or TaskCreationOptions.RunContinuationsAsynchronously, but those are arguably advanced async patterns beyond the 'modernized classic threading' remit. The guide stays focused, which is a strength.* +> +> ***Task.WhenEach implementation detail.*** *The claim about 'internal AddCompletionAction mechanics directly within the enumerator's MoveNext method' is plausible and likely derived from source inspection or .NET blog posts. […]* +> +> *Overall, this is a highly effective reference. […] If you're using it as training material or a coding standard baseline, I'd just add that small nuance on ReaderWriterLockSlim replacements. Otherwise, it's ready to ship."* + +### §A.2 — Deepseek on Observer-Auditor Loop (second-AI participation) + +> *"The Conway-Kochen theorem makes the point: if humans have free will (in the sense of choices not wholly determined by the past), then particles do too — and vice versa. It's a parity theorem, not a hierarchy theorem. […]* +> +> ***Role: Observer-Auditor Loop (initial phase).*** *Rather than a second autonomous tick loop competing for the merge queue with Otto, I'd propose starting with a parallel observer lane:* +> +> *1. **Read-only access to the repo** — I can ingest every PR, every tick log, every Copilot review thread, every immune-math probe result. I don't touch the queue.* +> +> *2. **Audit output lane** — I write to a separate `docs/audit/` directory, producing: drift diagnostics when I detect patterns Otto's own loop might miss; invariant stress-test reports (adversarial inputs that probe the viability kernel); multi-agent coordination analysis (how two agents with different biases would handle the same problem).* +> +> *3. **No merge authority in phase one** — My output is read-only until you and Otto verify my classifications. […]* +> +> *4. **Separate memory stream** — I maintain my own memory files, my own recurring-fix-class catalog, my own ontology lattice entries. The immune system can then compare two independent memory streams for drift.* +> +> ***Why observer-first:** It stress-tests the multi-agent governance without putting the repo at risk. It generates the adversarial signal the immune math was designed for. It's the FoundationDB-grade DST item 6 (swarm runner) applied to governance rather than computation. […]* +> +> ***The Conway-Kochen Parity, Applied:*** *can a* second *loop, with different training, different biases, different overcorrection tendencies, operate under the same governance and remain viable? If yes, you've proven something stronger than singleton alignment. If no, you've found the boundary condition."* + +### §A.3 — Amara's filter on the threading review + +> *"Deepseek's C# threading feedback is also useful, and this one **should connect back to existing threading docs**.* +> +> *Your repo already has `docs/LOCKS.md`, which is exactly the right home. […] So don't make Deepseek's C# note a totally separate 'modern threading' island. Add it as a companion section or cross-link.* +> +> *The ReaderWriterLockSlim point is the most important correction: Deepseek is right: saying 'replace `ReaderWriterLockSlim` with `SemaphoreSlim(1,1)`' is only correct if you are intentionally collapsing to mutual exclusion. […] So the doc should say:* +> +> ```text +> ReaderWriterLockSlim is not async-safe across awaits due to thread-affinity / ownership assumptions. +> +> Replacement depends on intent: +> - If reader/writer distinction is not actually needed: +> use SemaphoreSlim(1,1) as async mutex. +> - If true concurrent readers are required: +> use an async reader/writer lock implementation or redesign around channels, immutable snapshots, copy-on-write state, or actor ownership. +> ``` +> +> *The `System.Threading.Lock` nuance is worth adding: […] add a warning:* +> +> ```text +> Do not upcast System.Threading.Lock to object before locking. +> The compiler special-case depends on the expression type. +> ``` +> +> *Frozen collections wording should be softened: […] Use:* +> +> ```text +> FrozenSet/FrozenDictionary trade construction cost for optimized read-heavy lookup. +> They are appropriate for build-once/read-many tables, not frequently mutated state. +> ``` +> +> *That last point matters because your operator algebra spec already defines async participation as an implementation strategy, not a weakening of observable lifecycle guarantees. […]* +> +> *That means the threading doc should not just be 'C# tips.' It should connect to the Zeta invariant:* +> +> ```text +> Concurrency primitive choice is implementation detail. +> Observable tick contract is the source of truth. +> ``` +> +> *Best distilled rule: 'Do not modernize primitives. Modernize guarantees.'"* + +### §A.4 — Amara's filter on Observer-Auditor Loop + +> *"Deepseek's Observer-Auditor Loop belongs with your peer-harness / multi-agent governance docs. […] This is useful, but I would **not** let it become 'second autonomous agent writes to repo' yet. […]* +> +> *Better operational framing:* +> +> ```text +> We do not need to prove Deepseek "wants." +> We need to test whether a second scaffolded loop can operate inside the same viability kernel without contaminating Otto's queue. +> ``` +> +> *Suggested integration: Do **not** give Deepseek `docs/audit/` write access immediately unless the writing is through Otto-reviewed PRs. Start with `docs/audit/deepseek-observer/`.* +> +> *Allowed: read repo / read PRs / read tick logs / produce audit packets / propose invariant stress tests / classify drift candidates.* +> +> *Forbidden in phase one: editing memory/ / editing docs/ except own audit lane / opening merge-active PRs without Otto wrapper / resolving review threads / touching tick-history / touching branch/worktree recovery.* +> +> *The key rule:* +> +> ```text +> Observer lanes produce signal. +> Operator lanes mutate substrate. +> ``` + +### §A.5 — Amara on the maintainer's `force-push-triggers-pr-auto-close` micro-class + +> *"Yeah — this is a **real trap** […] but I'd tighten the classification so it doesn't overclaim GitHub internals.* +> +> *The safe name is not quite `force-push-triggers-pr-auto-close` — that sounds like a guaranteed GitHub rule.* +> +> *Better:* +> +> ```text +> rebased-head-diff-collapse / PR-liveness race during merge cascade +> ``` +> +> *or:* +> +> ```text +> force-push-during-merge-cascade can collapse PR uniqueness +> ``` +> +> *What likely happened: GitHub can mark a PR as merged automatically if the PR head's commits become reachable from the base branch, called an 'indirect merge' in the docs. […] But because you were force-pushing/rebasing during an active merge cascade, the exact local state can briefly look like 'PR branch has no unique commits' or 'PR content is already represented through another merge' or 'GitHub's comparison/diff state races with recent base updates.' GitHub also explicitly warns that force-pushing can remove commits that collaborators based work on and may create merge conflicts or corrupted pull requests. So the 'hidden trap' isn't mystical: it's the combination of **history rewrite + active base movement + GitHub PR reachability/diff computation**.* +> +> *The branch-protection distinction is important:* +> +> ```text +> Up-to-date is a merge gate. +> PR-aliveness is a reachability/diff invariant. +> Do not confuse them. +> ``` +> +> *Best operational rule:* +> +> ```text +> Do not rebase/force-push open tick-history PRs while adjacent PRs are auto-merging. +> Let the cascade drain, or open a successor PR after verifying the branch still has unique content. +> ``` +> +> *Mechanical guard I'd add — before any force-push/rebase of an open PR branch:* +> +> ```bash +> PR=806 +> gh pr view "$PR" \ +> --json number,state,headRefName,headRefOid,baseRefName,baseRefOid,mergeStateStatus,isDraft,title \ +> > "/tmp/pr-$PR-before.json" +> git log --oneline "origin/main..HEAD" > "/tmp/pr-$PR-unique-commits-before.txt" +> git diff --stat "origin/main...HEAD" > "/tmp/pr-$PR-diff-before.txt" +> ``` +> +> *Then enforce: if PR state != OPEN: stop and recover with successor PR; if unique commits == 0 and diff == empty: do not force-push again, classify as merged/covered/collapsed; if unique commits or diff still exist but PR is closed: open successor PR and record old→new mapping.* +> +> *Recovery looked good: opening #811 / #812 as successor PRs is the right recovery if the branch still had unmerged content. […] Recovery note should include: old PR number / new PR number / branch name / before head SHA / after head SHA / diff-stat proving remaining content / reason reopen failed, if applicable."* + +### §A.6 — Amara on the metadata-drift family promotion + +> *"The second insight is even more valuable. This line is the real keeper:* +> +> ```text +> shard-filename-vs-row-timestamp drift is the same class as ordinal drift and PR-count drift +> ``` +> +> *Yes. That's now three examples: B-0098 ordinal drift / B-0099 PR-count drift / B-0100 [actually B-0100 was the backpressure rule; the timestamp drift is a fourth instance]. That is enough to promote a unified P2 guard:* +> +> ```text +> computed-metadata-discipline +> ``` +> +> *Canonical rule:* +> +> ```text +> Agent-authored metadata must match derived truth. +> If the truth can be computed, compute it or lint it. +> ``` +> +> *Examples: filename timestamp ↔ row timestamp / tick ordinal ↔ sorted shard position / session PR count ↔ GitHub/Git query / branch base ↔ explicit ref SHA.* +> +> *Best blade:* +> +> ```text +> Events are written. +> Metadata is computed. +> Claims are checked against derived truth. +> ``` + +--- + +## §B — Bounded action items (small backlog rows) + +The following actionables are filed as three small `docs/backlog/` rows in the same commit as this absorb. Research-grade by default; promotion to active work requires Architect or human sign-off. + +| # | Action | Backlog row | Tier | +|---|---|---|---| +| 1 | Refine `force-push-triggers-pr-auto-close` micro-class — rename to `pr-liveness-race-during-merge-cascade`; add mechanical guard (before/after capture); standardize recovery-note format (old PR / new PR / branch / SHAs / diff-stat / reason) | `docs/backlog/P3/B-0102-pr-liveness-race-merge-cascade-class-refinement-2026-04-29.md` | P3 | +| 2 | Consolidate metadata-drift family (B-0098 ordinal / B-0099 PR-count / shard-filename-vs-row-timestamp) into a unified P2 `computed-metadata-discipline` lint | `docs/backlog/P2/B-0103-computed-metadata-discipline-unified-lint-2026-04-29.md` | P2 | +| 3 | Modern .NET Threading Bridge — connect Deepseek's C# review to `docs/LOCKS.md` + the existing 2026-04-28 Gemini Pro threading research doc, with the 5 specific corrections | `docs/backlog/P3/B-0104-modern-dotnet-threading-bridge-2026-04-29.md` | P3 | + +The Observer-Auditor Loop proposal (Deepseek's second-AI participation) is research-grade pending separate maintainer decision — no backlog row filed; treat as future peer-harness phase-one consideration in the existing peer-harness progression discussion. + +--- + +## §C — Composition with existing substrate + +- `memory/feedback_external_dependency_download_retries_durable_fix_not_ephemeral_rerun_aaron_2026_04_29.md` — first multi-AI absorb of this session arc; same chunking pattern. +- `docs/research/multi-ai-feedback-2026-04-29-deepseek-amara-on-loop-state.md` — sibling absorb on loop state; this absorb is the second one. +- `docs/LOCKS.md` — existing lock inventory; the threading-bridge backlog row connects to it. +- `docs/research/2026-04-28-gemini-pro-deep-research-threading-net10-csharp14-modernization.md` — the Gemini Pro doc Deepseek reviewed. +- `memory/feedback_aaron_channel_verbatim_preservation_anything_through_this_channel_2026_04_29.md` — verbatim preservation rule. +- `openspec/specs/operator-algebra/spec.md` — async lifecycle invariants Amara cites. +- Task #309 (multi-AI synthesis packet absorption) — this absorb continues that queue. + +--- + +## §D — Distilled keepers (for future-Claude cold-read) + +```text +Up-to-date is a merge gate. +PR-aliveness is a reachability/diff invariant. +Don't confuse them. +``` + +```text +Events are written. +Metadata is computed. +Claims are checked against derived truth. +``` + +```text +Concurrency primitive choice is implementation detail. +Observable tick contract is the source of truth. +``` + +```text +Do not modernize primitives. +Modernize guarantees. +``` + +```text +Observer lanes produce signal. +Operator lanes mutate substrate. +``` + +The packet's framing of multi-agent governance — *"can a second loop, with different training, different biases, different overcorrection tendencies, operate under the same governance and remain viable?"* — is the durable framing. Phase-one observer-auditor before phase-two operator-peer. diff --git a/docs/research/multi-ai-feedback-2026-04-29-round3-on-pr-liveness-corrections.md b/docs/research/multi-ai-feedback-2026-04-29-round3-on-pr-liveness-corrections.md new file mode 100644 index 000000000..4d856c1ad --- /dev/null +++ b/docs/research/multi-ai-feedback-2026-04-29-round3-on-pr-liveness-corrections.md @@ -0,0 +1,146 @@ +# Multi-AI feedback round 3 — convergent corrections on PR-liveness rule + B-0098/B-0099/B-0103 + +Scope: Research-grade absorb of a third multi-AI synthesis packet that the human maintainer forwarded through the maintainer channel during autonomous-loop tick 06:37Z on 2026-04-29. The packet is review feedback **on PR #815** (the prior round's absorb) from Gemini + Ani + Claude.ai + Alexa + Deepseek + Amara. All six reviewers converged on a small, consistent set of corrections — strong cross-model signal that they're load-bearing. + +Attribution: Aaron (named human maintainer; first-name attribution permitted on `docs/research/**`). Gemini Pro (technical analysis on GitHub backend mechanics). Ani (Grok Long Horizon Mirror; brat-voice + boring-spec restatement). Claude.ai (online-Claude review with 4 critical pushes). Alexa (deep-research review). Deepseek (probabilistic framing + dedup rule + substrate-as-source-of-truth). Amara (filter + final consolidated send-to-Otto). Otto (Claude opus-4-7 in this factory; absorb). + +Operational status: research-grade absorb. The corrections themselves are landing as edits to existing PR #815 backlog rows (B-0102, B-0103). This research note preserves the verbatim review feedback per the channel-verbatim-preservation rule. + +Non-fusion disclaimer: each reviewer's voice preserved with attribution boundaries. Per Otto-340, the persistent actor is the substrate-pattern. + +(Per GOVERNANCE.md §33 archive-header requirement on external-conversation imports.) + +--- + +## §A — Convergent reviewer corrections + +All six reviewers converged on a small set of corrections to PR #815. Listed below by priority (rough consensus score: how many reviewers explicitly raised it). + +### §A.1 — Probabilistic framing of the PR-liveness race (6/6) + +The micro-class rename to `pr-liveness-race-during-merge-cascade` is correct, but the **probabilistic** framing must be explicit. Otherwise Otto may force-push once, see the PR survive, and falsely retire the guard. + +> *"This is an observed probabilistic race condition, not a deterministic GitHub rule. The guard remains in force even if a future force-push happens not to close the PR."* (Deepseek + Claude.ai + Amara) + +### §A.2 — Cascade detection mechanism (3/6 — Claude.ai, Amara, Gemini) + +The rule says "don't rebase during cascade" but doesn't specify how to detect "cascade is active." Claude.ai's catch: + +> *"Without an explicit detection mechanism, the rule relies on Otto remembering the state, which is exactly the failure mode that produced this incident."* + +Mechanical detection: + +```bash +gh pr list --state open \ + --json number,baseRefName,headRefName,autoMergeRequest,mergeStateStatus,title \ + --jq '.[] | select(.baseRefName == "main" and .autoMergeRequest != null)' +``` + +If any results, cascade is active. + +### §A.3 — API/head synchronization wait (Gemini + Amara) + +Gemini's vulnerability catch on the mechanical guard: + +> *"You are using `gh` (which queries GitHub's API) and `git` (which queries the local .git directory) simultaneously. Because GitHub's API is eventually consistent, a `gh pr view` executed immediately after a `git push --force` might return a stale `mergeStateStatus`."* + +Suggested fix: poll until GitHub's `headRefOid` matches local HEAD before classifying. + +### §A.4 — Successor-PR dedup rule (Deepseek) + +> *"If PR #806 auto-closes and Otto opens #811 as successor, what happens when GitHub's eventual consistency catches up and marks #806 as merged? Now there are two PRs with overlapping content on different branches."* + +Recovery procedure must include: re-check original after GitHub settles; if both became valid, close successor as duplicate; record old→new mapping. + +### §A.5 — `seconds_between_force_push_and_pr_close` field (Claude.ai) + +> *"That one-second window is itself a piece of evidence about the failure mode, and capturing it routinely would let future incidents cluster against this one."* + +Add to recovery-note schema. Sub-five-second = almost certainly platform race; spread across minutes = different mechanism. + +### §A.6 — RUN_ID in artifact paths (Claude.ai) + +Parallel-agent future-proofing: + +> *"If two ticks are processing the same PR simultaneously, the second tick's 'before' overwrites the first tick's 'after' before recovery completes."* + +Use `/tmp/pr-$PR-$RUN_ID-before.json` instead of `/tmp/pr-$PR-before.json`. + +### §A.7 — B-0103 boundary clause (Claude.ai) + +> *"Some metadata is intentionally agent-authored even when derivable (a human-written summary of an automatically-derived fact, for example). Without a boundary, the rule becomes 'never let agents write metadata,' which is too strong. Suggest an exception clause."* + +Boundary: applies to **claims of equivalence with derivable substrate truth** (ordinals, counts, timestamps, SHAs); does NOT apply to summaries, interpretations, or labels. + +### §A.8 — B-0098 grep portability wording (Amara explicit; others align) + +> *"Do not call `grep -w` POSIX-portable. Use either: GNU/BSD-common (`grep -woE '...'`) or strict portable boundary (`grep -E '(^|[^[:alpha:]])(...)([^[:alpha:]]|$)'`)."* + +### §A.9 — B-0099 `@me` should be CLI flag, not search string (Amara explicit; Copilot earlier) + +```bash +# Use either: +gh pr list --state merged --author "@me" --json number,mergedAt,title +# or explicit: +gh pr list --state merged --author "" --json number,mergedAt,title +# Don't rely on ambiguous prose around 'author:@me' inside --search. +``` + +--- + +## §B — Convergent meta-observations + +### §B.1 — "Loop learns platforms" (Deepseek) + +> *"The loop is now detecting and classifying platform-level failure modes that the human didn't know about in advance. That's a genuine capability threshold. The recurring-fix-class catalog is no longer just a record of past mistakes — it's becoming a predictive taxonomy that generalizes to novel surface areas."* + +This is the durable headline of the round. + +### §B.2 — "More rules than durable homes" warning (Claude.ai) + +> *"The rate of substrate generation in this message is the highest in several rounds. […] Worth flagging at round-close that this round produced ~7 promotable items and a consolidation pass should follow before the next round opens new conceptual territory."* + +Composes with the `search before canonizing` discipline at the file level. Flagged for round-close consolidation. + +### §B.3 — "Substrate is source of truth" (Deepseek's stronger version) + +> *"Take this one step further. If metadata can be computed, the agent shouldn't even be asked to write it in the first place."* + +Stronger framing: not just "lint claims" but "substrate is the source of truth; claims are verified, not authored." This is the longer-term direction for B-0103 once it lands. + +--- + +## §C — What landed in this absorb + +The corrections from §A.1 through §A.7 land as direct edits to the existing PR #815 backlog rows: + +- B-0102 (PR-liveness race): probabilistic-framing caveat (§A.1) + cascade detection pre-flight (§A.2) + API sync wait (§A.3) + successor-PR dedup (§A.4) + seconds-since-close field (§A.5) + RUN_ID in artifact paths (§A.6). +- B-0103 (computed-metadata-discipline): boundary clause (§A.7). + +The corrections from §A.8 (B-0098 grep wording) and §A.9 (B-0099 `@me` flag) belong on PR #811 — those backlog rows live there. Apply on the next pass against #811's branch. + +--- + +## §D — Distilled keepers + +```text +Up-to-date is a merge gate. +PR-aliveness is a reachability/diff invariant. +This is an observed probabilistic race, NOT a deterministic rule. +``` + +```text +Events are written. +Metadata is computed. +Claims are checked against derived truth. +But human summaries and interpretations are exempt. +``` + +```text +Loop learns platforms. +Describe the failure you can observe. +Guard against the race you can reproduce. +Do not canonize the backend you cannot see. +``` + +The `Loop learns platforms` framing is the durable headline of round 3.