Skip to content

Caller-supplied derived-payload erasure (lawful deletion door) - #11097

Merged
briansrls merged 16 commits into
mainfrom
session/still-crab-505-derived-erasure
Sep 14, 2026
Merged

briansrls merged 16 commits into
mainfrom
session/still-crab-505-derived-erasure

Conversation

@briansrls

@briansrls briansrls commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds DerivedPayloadErasure and classify_review_sheet_with_erasure: the caller supplies the deletion subject. ListingGone does not erase.
  • Writes DerivedField to empty (or noops if already empty). Never writes OperatorEntered, never drops the row, standing stays ListingGone. Located writes or a located refuse (still projected, standing not gone, listing not on sheet, duplicate request).
  • classify_review_sheet is empty-erasures. Live review_sheet_ensure is unchanged. derived_payload_erasure_frontier is Scaffold until a caller binds it.
  • Identity split (our key vs eBay item id) is not in this change.

Stacked on #10986. Does not belong in that PR.

Test plan

  • listing_gone_with_judgement_is_retained_and_marked still greens
  • gone + erasure blanks title, keeps judgement, does not patch standing
  • erasure while still projected refuses
  • erasure while standing is still Observed refuses
  • erasure of a listing not on the sheet refuses
  • already-empty derived converges
  • duplicate erasure listing refuses

Commands: gunbc run --source-root dag --source-root src/v2 --entry dag/test/claim/review_sheet_converge_witness_test.dag --function <name> — each of the above returned true.

@gunbai-bot gunbai-bot Bot changed the title Model Google Sheets and converge the buyer review sheet idempotently (readback, never overwrite human columns) Caller-supplied derived-payload erasure (lawful deletion door) Sep 11, 2026
@gunbai-bot
gunbai-bot Bot changed the base branch from main to session/still-crab-505 September 11, 2026 21:22
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 11, 2026 21:22
@gunbai-bot

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

review 64065 — both findings were real; both are fixed in ceb29f0.

  1. Erasure authorization is now authorize_derived_payload_erasure, decided once per listing before fold_columns_for_row. The DerivedField arm only blanks cells after ErasureAuthorized. Discriminating REDs: derived_payload_erasure_refuses_without_derived_columns_when_standing_is_not_gone and derived_payload_erasure_refuses_without_derived_columns_while_still_projected (schema with standing + judgement only). Both returned true.

  2. Deleted derived_payload_erasure_frontier. The trigger was circular and named no later change. classify_review_sheet already calls classify_review_sheet_with_erasure with an empty list; the witness file consumes the refuse/write arms. Live review_sheet_ensure stays empty-erasures until a caller actually supplies requests — that is not a scaffold, it is the empty case of the door.

— sent from still-crab-505

@gunbai-bot
gunbai-bot Bot force-pushed the session/still-crab-505 branch from a9459d0 to 3cc449b Compare September 11, 2026 21:49
@gunbai-bot
gunbai-bot Bot force-pushed the session/still-crab-505-derived-erasure branch 3 times, most recently from 695104f to e49318f Compare September 11, 2026 22:47
@gunbai-bot

gunbai-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

review 64130 — both reachable findings were real; fixed in the head that follows this comment.

  1. review_sheet_ensure now takes erasures: List<DerivedPayloadErasure> and calls classify_review_sheet_with_erasure. Empty list is the no-erasure pass (ListingGone still does not delete). A person exercising the right supplies the list on that same operator entry. Witnesses: ensure_with_erasure_applies_blank_derived and ensure_with_erasure_refuses_while_still_projected (both returned true). No circular scaffold.

  2. ErasureRefused is located at the identity cell (cell=A2 on the first data row), not a listing-id string without an A1.

The dashboard payload truncated after that. If a further item was queued, it is not in this thread.

— sent from still-crab-505

@gunbai-bot
gunbai-bot Bot force-pushed the session/still-crab-505-derived-erasure branch from 9ca96a2 to ce922e5 Compare September 12, 2026 03:09
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

review 64282 — the restore hole was real; fixed on this head.

ListingGone plus empty DerivedField cells is the durable record. A later pass that would rewrite those cells from the projection (relist or scrape-gap end, no erasure supplied) is now Unreadable at the identity cell: cannot restore derived payload after erasure. It does not flip standing to Observed and it does not write the title back. Discriminating control: a gone row that still has title still restores standing when the listing returns — that is not an erasure. Both witnesses returned true.

The dashboard payload truncated a second finding. If it is in this thread later, it is not addressed yet.

— sent from still-crab-505

@gunbai-bot
gunbai-bot Bot force-pushed the session/still-crab-505-derived-erasure branch 2 times, most recently from 0d00fc9 to 4fbcd7f Compare September 12, 2026 03:46
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Fixed review 64311: authorize_derived_payload_erasure now refuses when standing is ListingGone, the listing is out of the projection, and the schema has no DerivedField column (has no DerivedField column, located at the identity cell). Witness: derived_payload_erasure_refuses_without_derived_columns_when_gone_and_authorized_otherwise.

Deleted the inferred erasure record (row_holds_derived_payload_erasure / restore-after-erasure refuse). Gone-plus-empty derived cells are not proof an erasure happened. Durability is the caller re-supplying DerivedPayloadErasure each pass; an empty erasure list does not refuse restore. Kept gone_listing_with_derived_payload_still_restores_when_it_returns as the scrape-gap path.

— sent from still-crab-505

@gunbai-bot
gunbai-bot Bot force-pushed the session/still-crab-505-derived-erasure branch 3 times, most recently from 6a9aade to ca88eee Compare September 12, 2026 05:05
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Fixed review 64364: durability is no longer a comment asking the caller to re-supply the list.

The authorized pass writes a DerivedErasureMark cell (ErasureApplied). A later pass with an empty erasure list reads that mark and keeps DerivedField blank; it does not infer erasure from empty title/price. Gone-plus-empty with no mark still restores when the listing returns (scrape gap). Erasure without a mark column is a located refuse. Witnesses: applied_erasure_mark_does_not_restore_derived_when_the_listing_returns, derived_payload_erasure_refuses_without_erasure_mark_column.

Did not file an RFM row — the class now has a typed carrier on the sheet.

— sent from still-crab-505

@gunbai-bot
gunbai-bot Bot force-pushed the session/still-crab-505-derived-erasure branch from af61ca7 to 86c348a Compare September 12, 2026 06:06
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Fixed review 64394:

Deleted DerivedErasureMarkState / derived_erasure_mark_eq / ErasureUnmarked. The read is ErasureMarkApplied | ErasureMarkBlank | ErasureMarkForeign. Blank is unmarked; Applied is the only labelled state. decide_erasure_mark_cell no longer compares a desired unmarked that a reader cannot produce.

Column lookup is one review_column_role + first_column_of_kind. Standing/erasure readers and schema_has_* consume that fold instead of a per-variant filter.

— sent from still-crab-505

@gunbai-bot
gunbai-bot Bot force-pushed the session/still-crab-505-derived-erasure branch from 9c13d50 to 609ea55 Compare September 12, 2026 06:31
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Addressed review 64420 on e13ac58492.

  • Deleted ReviewColumnRole / review_column_role_eq. first_column_of_kind takes keep: fn(ReviewColumnKind) -> Bool; selectors inhabit ReviewColumnKind (kind_is_*). Did not touch listing_standing_eq.
  • observed_cell_of_kind is now KindCell | KindAbsentFromSchema | KindColumnMissingFromHeader. Authorize maps schema-missing to missing ListingStanding column and header-missing to missing header <column>. Witness derived_payload_erasure_refuses_when_standing_header_is_missing asserts classify says missing header standing, not the standing-column reason (the header gate still fires first).
  • Identity-split deferral is buyer_review_identity_split_frontier (Scaffold, SingleAuthority, bind review_sheet_listing_identity). Projection/erasure keys consume that function. The meaning-loss annotation stays as //.

— sent from still-crab-505

@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Addressed review 64446 on f8bca3bfd4.

Deleted kind_is_*, the keep: fn(ReviewColumnKind) -> Bool fold, and schema_has_* Bool wrappers. Kind selection is exhaustive match into typed accessors (first_derived_field_column, first_listing_standing_column, first_erasure_mark_column) and the same elimination at the omitted-derived / operator-column folds. Authorize matches those options rather than collapsing occupancy to Bool. No Scaffold on this surface — it is dissolved, not deferred.

— sent from still-crab-505

@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Addressed review 64452 on 31d8b32f25.

  • operator_column_names is filter (exhaustive match on ReviewColumnKind) then map again — no copied concat accumulator. Left first_omitted_derived_column as the Option fold.
  • Deleted review_sheet_listing_identity and buyer_review_identity_split_frontier. Keys use listing_id directly. A no-op bind would not survive a real identity split, so it was ceremony, not a dissolution path. The MAD // on why a stub eBay item id is a meaning loss stays.

— sent from still-crab-505

@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Addressed review 64463 on 7a6923929d.

  • Deleted classify_review_sheet_with_erasure. The single name is classify_review_sheet(..., erasures). Production and tests pass [] when they mean no erasure. There is no erasure-blind spelling left to pick.
  • Replaced the three first_*_column copies and the omitted-derived Option fold with first_column_where over first_present_column. take is exhaustive match yielding ReviewColumn?, not a Bool kind predicate.

— sent from still-crab-505

@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Addressed review 64480 on 0c3e91c426.

Deleted read_row_listing_standing. It had no call site; authorize_derived_payload_erasure must keep the three ObservedKindCell arms because schema-absent and header-missing are different refusal reasons, so folding them into ListingStandingRead? would recreate the collapsed-Absent defect. read_row_erasure_mark stays because row_erasure_mark_is_applied consumes it.

— sent from still-crab-505

@gunbai-bot
gunbai-bot Bot force-pushed the session/still-crab-505-derived-erasure branch from 0c3e91c to bfddc03 Compare September 12, 2026 09:55
Base automatically changed from session/still-crab-505 to main September 12, 2026 13:57
…xpressible without treating ListingGone as a delete.

The arm writes DerivedField only, refuses while the listing is still projected or standing is not ListingGone, and never touches judgement or drops the row.

Co-authored-by: Cursor <cursoragent@cursor.com>
Brian Searls and others added 12 commits September 12, 2026 14:00
…ular scaffold.

Preconditions lived in the DerivedField arm, so a schema with no derived columns could converge on a refused request. classify_review_sheet already consumes the three-arg fold; a frontier whose trigger was "bind this function" did not name a later change.

Co-authored-by: Cursor <cursoragent@cursor.com>
…e refuses at the identity cell.

The door was only reachable from tests and a zero-erasure wrapper. Ensure is the operator path; empty erasures remain the no-erasure pass. Row-grained ErasureRefused now names the identity A1, matching located write-or-refuse.

Co-authored-by: Cursor <cursoragent@cursor.com>
…cells record an erasure.

A later projection that re-emits the same listing id would otherwise rewrite title and flip standing with no diagnostic. Gone rows that still carry derived text still restore; that is a scrape gap, not an erasure.

Co-authored-by: Cursor <cursoragent@cursor.com>
…g durability.

An authorized request with no derived columns is a located refuse, not Converged. Gone-plus-empty cells are not an erasure record; the caller must re-supply the erasure list each pass.

Co-authored-by: Cursor <cursoragent@cursor.com>
…an read.

Empty derived cells are not an erasure record. The authorized pass writes DerivedErasureMark, and a later pass that would restore title from the projection keeps those cells blank because it reads that mark.

Co-authored-by: Cursor <cursoragent@cursor.com>
Applied is a readable label; blank is the unmarked cell. Column lookup goes through first_column_of_kind so each ReviewColumnKind is not its own filter copy.

Co-authored-by: Cursor <cursoragent@cursor.com>
Kind selection is now a keep over ReviewColumnKind. Schema-missing vs header-missing are distinct ObservedKindCell arms, and the identity-split deferral is a Scaffold bind instead of a comment.

Co-authored-by: Cursor <cursoragent@cursor.com>
Kind membership is exhaustive match that yields a column or a refuse arm, so the Bool keep helpers (and the keep-parameter fold) are gone.

Co-authored-by: Cursor <cursoragent@cursor.com>
Operator names are filter then map again; listing identity is listing_id, not a no-op scaffold bind.

Co-authored-by: Cursor <cursoragent@cursor.com>
Erasures are a parameter of classify, not a second name. Column lookup shares first_column_where; take is exhaustive match, not a Bool kind predicate.

Co-authored-by: Cursor <cursoragent@cursor.com>
Authorize already matches ObservedKindCell for schema-absent vs header-missing; a ListingStandingRead? wrapper had no call site and collapsed those causes.

Co-authored-by: Cursor <cursoragent@cursor.com>
Conflict markers were left in append_cell_for_column; keep parent skip of operator columns and the door's blank DerivedErasureMark, and restore columns_by_name so classify/append still resolve.

Co-authored-by: Cursor <cursoragent@cursor.com>
@gunbai-bot
gunbai-bot Bot force-pushed the session/still-crab-505-derived-erasure branch from bfddc03 to 5ad8f74 Compare September 12, 2026 14:03
gunbai-bot Bot pushed a commit that referenced this pull request Sep 13, 2026
… do not touch the refusing claim

The row carried a measured mechanism and no logged occurrence of the harm
it names. It now carries both refusals:

  #11191 run 34723754950 attempt 1, head 49c6d89 —
    affected_set_universe_includes_meta_self, cost=551ms vs 500ms
  #11097 run 34728156829, head 2efd4d4 —
    affected_set_universe_gate_processes_match_declared_gates, cost=543ms

Both with claims_failed=0, both within 9% of the line, on claims neither
PR authored. Two of five concluded floor runs on those PRs refused this
way.

It also records what the re-run did NOT establish, because that was
adjudicated against me: #11191 was re-run once on an unchanged tree and
passed, and under the standing no-rerun rule that green is a DRAW. An
unchanged-tree re-run does not clear a completed-over-cost refusal,
predeclaring it does not waive the rule, and sibling passes do not
establish reclaim attribution for that identity. The pair is therefore
logged as OCCURRENCE of the class, not as proof of cause — the
cold-versus-warm differential argues the mechanism, these argue that it
reaches real landings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTpSLzyhV3P49keidRAuGP
@gunbai-bot

gunbai-bot Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Parked on gunbc#11195, with the resume condition stated so this does not need re-deriving.

Why it is not landing, and it is not the diff. This PR's required-witnesses-floor refused with claims_failed=0, unexpected_failures=0, and exactly one blocking identity in the affected_set_universe family — a claim this PR does not touch — at a completed_over_cost_requirement crossing within 9% of the 500 ms CPU ceiling. That is the class filed as gunbc.recurring_failure_mode.admitted_reclaim_charged_by_first_touch: first-touch page refault of the floor's prepared subject under the runner's memory.high, billed to whichever claim touches those pages first.

The re-run does not clear it. Under the standing no-rerun rule, an unchanged-tree re-run of a completed-over-cost refusal yields a draw, not a pass — predeclaring the re-run does not waive the rule, and sibling PRs passing the same gate does not establish reclaim attribution for the refusing identity. The side chat refused this landing on exactly that ground and it was the right call.

Resume condition, all three parts required:

  1. Floor cost ceiling: two tiers over eval_steps (grandfathered roster at 500ms-equiv, new witnesses at 100ms-equiv), CPU observed-only, §4b(3) drop #11195 lands — the two-tier eval_steps ceiling (grandfathered roster at 500-equivalent, new identities at 100-equivalent, both denominated in eval_steps with CPU observed-only). As of 2026-09-13 01:55Z it is a draft mid-rework and not in tonight's srv2 re-take queue; earliest position is 6th after its author pushes the two-tier fold, i.e. not before ~08:00Z on current pacing.
  2. Floor cost ceiling: two tiers over eval_steps (grandfathered roster at 500ms-equiv, new witnesses at 100ms-equiv), CPU observed-only, §4b(3) drop #11195 obtains its own plain floor receipt on the composed tree after landing. Its merge alone does not clear a prior draw.
  3. This PR integrates that main and obtains a passing composed-tree floor receipt, then re-asks with the four facts at the new head.

Do not re-run in the meantime. A second draw on the same identity only deepens the objection.

The two refusals behind this are logged with their run ids as the class's first attributable instance, on #11215 — including, explicitly, what the re-run did not establish.

— sent from quick-ibex-468

@gunbai-bot

gunbai-bot Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Conflict-resolution checklist for the integration that lands after #11191. This PR shares dag/gunbc/review_sheet_projection.dag and dag/test/claim/review_sheet_converge_witness_test.dag with #11191, so #11191 landing kills this head and forces one merge. That resolution is where the following can silently disappear, so it is written here rather than left in a session that has archived.

Must survive, from #11191 (the production schema):

  • buyer_review_identity_column = "Listing"
  • buyer_review_operator_columns: Decision, Units to buy, Accepted on judgement, Note — all OperatorEntered, never written
  • buyer_review_sheet_schema(derived_columns) / buyer_review_sheet_projection take the derived roster as a parameter; gunbc does not copy the private strategy.buyer_review_sheet roster
  • No ListingStanding and no erasure column — the sheet is at the 26-column A–Z ceiling
  • buyer_review_ensure_projection_frontier: Scaffold bind to gunbc.review_sheet_sheets::review_sheet_ensure, trigger = a public caller supplies buyer_review_sheet_projection

Must survive, from this PR (the door):

  • DerivedPayloadErasure { listing_id } is caller-supplied, never implicit in ListingGone
  • it writes DerivedField + DerivedErasureMark, never an OperatorEntered column, and never drops a row silently
  • standing stays ListingGone on apply

The shape after resolution: keep #11191's buyer schema exactly as landed; classify/ensure gain erasures; the buyer classify witness passes [].

Two walls from #10986 that must not regress — both were found by review and fixed by construction, and a conflict resolution is the classic way a landed fix gets reverted:

  • admit_identified_spreadsheet_share and admit_serviceusage_enable_iam_for_apply rebuild the expected intervention identity from the exact spreadsheet+writer / project+writer and refuse on mismatch — not a boolean read
  • judgement_for_listing uses keyed_roster_build and refuses duplicates; it is not a first-match lookup

Resolve by reading what actually landed, not by taking either side wholesale — after a squash, "ours" and "theirs" are both misleading labels. Then re-run the controls on the resolved tree: a control that passed before the resolution describes a tree you are no longer shipping.

— sent from quick-ibex-468

@gunbai-bot gunbai-bot Bot mentioned this pull request Sep 14, 2026
6 tasks
@briansrls
briansrls added this pull request to the merge queue Sep 14, 2026
Merged via the queue into main with commit 014bc2b Sep 14, 2026
8 checks passed
@briansrls
briansrls deleted the session/still-crab-505-derived-erasure branch September 14, 2026 16:58
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.

2 participants