Skip to content

export V2 approval-gate state as deferred V3 principal proposals (#516 / V3#12 item 4) - #1003

Merged
olegbrok merged 4 commits into
mainfrom
barsik/v3-messaging-continuity
Aug 5, 2026
Merged

export V2 approval-gate state as deferred V3 principal proposals (#516 / V3#12 item 4)#1003
olegbrok merged 4 commits into
mainfrom
barsik/v3-messaging-continuity

Conversation

@olegbrok

@olegbrok olegbrok commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Third exporter leg: V2 messaging-continuity state → V3 connector-principal proposals for the Phase-5 lease-transfer ceremony.

  • approved_users is platform-blind; platform is resolved, never assumedgroup_chats rows authoritative, DM id-shape heuristic second (edges frozen parametrically: 1–13 telegram, 14–16 unresolved, 17–20 discord, 21+ unresolved, negative 16/17 boundary). UNRESOLVED is settled by the lease-stop record when one is provided, else by the owner at qualification.
  • Active groups with no gate row surface as group-active-without-gate-row; undelivered pending inbound with no gate/group parent — the normal stranger-at-the-gate shape — surfaces as pending-inbound-without-gate-row instead of vanishing.
  • Held counts filter delivered=0 (V2 retains delivery history); live Mini numbers: 13 proposals / 8 genuinely held (an earlier draft misread 21 by counting history).
  • Optional --lease-stop-record reconciles the Phase-5 step-2 record when present — membership AND provenance: lease-stop-only chats → active-without-v2-state; a lease platform resolves V2-unresolved rows (leaseStop=resolved-by-lease-stop); a disagreement with a V2-resolved row keeps V2's value and surfaces platform-conflict(v2=…,lease=…) with its own summary count and checklist line. Without the record, the ceremony doc keeps the manual cross-check explicit.
  • Source keys: raw-<id> when schema-legal, sha256-<24hex> otherwise — disjoint namespaces by construction (collision regression uses an attacker-crafted digest-shaped raw id); raw ids preserved in conversationRef/legacyId.
  • Ceremony Markdown escapes pipes/backslashes and strips C0+DEL+C1 controls from every DB-sourced cell; a hostile-display-name regression forges a row and asserts it stays inert.
  • Every row: inventoryKind: connector-binding, disposition: defer-with-owner-approvalINVENTORY_DEFERRED_OWNER_APPROVAL, never auto-imported; details conform to the fatal-enforced allowlist.

Validation

  • ruff clean; 34/34 tests.
  • Real-data run against the live Mini agents.db (copy-then-read) + V3 inspectPinkyImportManifest: ok: true, 0 fatals, 13× INVENTORY_DEFERRED_OWNER_APPROVAL — re-verified after every review round; lease-reconciliation manifests independently verified (3 deferred / 0 fatals).

Review: murzik gauntlet rounds 1–4 produced seven findings across three rounds — held-count inflation, orphan pending drop, missing lease-stop input, source-key fatality, Markdown forgery, key-namespace collision, and membership-only lease reconciliation — all addressed with frozen regressions.

🤖 Generated with Claude Code

🤖 Opened by Barsik

olegbrok and others added 2 commits August 5, 2026 05:46
V2's approval gate is platform-blind (approved_users keys on agent+chat
only) while V3 principals bind per connector, so the exporter resolves
platform with explicit provenance: group_chats rows are authoritative,
DM ids fall back to a shape heuristic, and anything else is UNRESOLVED
for the Phase-5 owner ceremony. Active groups without a gate row — the
V2 orphaned-group failure class — are surfaced as their own status
rather than dropped, and gate-pending inbound counts ride along so the
old-lease-stop drain step has real numbers.

Every emitted row is inventoryKind connector-binding with disposition
defer-with-owner-approval: the V3 inspector classifies all of them
INVENTORY_DEFERRED_OWNER_APPROVAL (verified on the real Mini DB — 13
rows, 0 fatals), keeping principal enablement an explicit owner
decision at qualification instead of an import side effect. Detail
fields follow the fatal-enforced connector-binding allowlist; rich
provenance lives in the generated ceremony proposal document.

Refs PinkyBotV3#12 item 4 (task #516).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ut, key safety, md escaping

- held counts filter delivered=0: V2 checkpoints delivery by flag and
  retains the row, so delivered history was ordering phantom drains
  (real-data held corrected 21 -> 8)
- undelivered pending rows with no gate row and no group row — the
  normal stranger-held-at-the-gate shape — now surface as
  pending-inbound-without-gate-row instead of silently vanishing
- optional --lease-stop-record input reconciles the Phase-5 step-2
  record when present: lease-stop-only chats surface as
  active-without-v2-state, every proposal carries a leaseStop marker,
  and the no-record path keeps the explicit manual cross-check line
- source keys derive a charset-safe component (raw when schema-legal,
  tagged sha256 otherwise) so +phone/Unicode/whitespace ids cannot
  fatal SOURCE_KEY_INVALID; raw ids stay in conversationRef/legacyId
- ceremony Markdown escapes pipes/backslashes and strips control chars
  from every DB-sourced cell — a crafted display name can no longer
  forge rows in the owner-decision artifact (regression test forges one
  and asserts it stays inert)
- platform heuristic edges frozen parametrically: 13/14-16/17-20/21+
  and the negative 16/17 boundary

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@olegbrok

olegbrok commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

Round 2 pushed (b302a23) — all five findings addressed plus the nonblocking edge-freeze:

  1. delivered=0 filter + regression proving delivered history is excluded. Real-data held corrected: 21 → 8 (13 rows were delivery history — the original PR body's number was wrong).
  2. Orphan undelivered pending (no gate row, no group row) surfaces as pending-inbound-without-gate-row — fixture is the exact stranger-at-the-gate shape review found missing.
  3. Optional --lease-stop-record reconciles when present (lease-stop-only chats → active-without-v2-state, every row carries a leaseStop marker: confirmed / absent-at-lease-stop / only-in-lease-stop); no-record path keeps the manual cross-check line explicit.
  4. Source keys: raw when [A-Za-z0-9._:@-]{1,80}, else sha256-<24hex>; raw preserved in conversationRef/legacyId. Tested +phone / spaces / Unicode / 200-char / pipe-newline.
  5. _md_cell escapes | and \, strips control chars; regression forges a hostile display name and asserts the fake row stays inert.
  6. Edge matrix frozen parametrically incl. -{16} telegram / -{17} unresolved.

29/29 tests, ruff clean, V3 inspector on fresh real-data export: ok, 0 fatals, 13× INVENTORY_DEFERRED_OWNER_APPROVAL.

🤖 Opened by Barsik

olegbrok and others added 2 commits August 5, 2026 06:16
Review round 2: a raw chat id shaped exactly like sha256-<24hex> shared
a sourceKey with a hashed unsafe id — deterministic SOURCE_KEY_DUPLICATE.
Prefix raw components with raw- so the namespaces cannot intersect, with
a collision regression using an attacker-crafted digest-shaped raw id.
Also strip DEL/C1 controls (U+007F..U+009F) in _md_cell as documented,
and freeze the remaining heuristic edge lengths 15/18/19.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review round 3: a matching lease entry's platform was discarded — an
unresolved V2 row stayed provider=unknown while the doc claimed
RECONCILED, and a platform disagreement was silently marked confirmed
by ID alone. Now a lease platform resolves V2-unresolved rows
(platformSource=lease-stop-record, leaseStop=resolved-by-lease-stop),
a disagreement keeps V2's value and surfaces
platform-conflict(v2=...,lease=...) for the owner, conflicts get a
summary count and ceremony checklist line, and lease titles backfill
empty display names. Both cases frozen in tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@olegbrok
olegbrok merged commit 9b38d63 into main Aug 5, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant