Skip to content
293 changes: 70 additions & 223 deletions .dev-loop/INGEST_REPORT.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions log.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,6 @@ Append-only. Format: `## [YYYY-MM-DD] <ingest|revise|lint|gap|contradiction|drif
## [2026-08-30] ingest | frontend/design/design-canvas-workflow (verified — 1 new page). Mandatory routing for visual-design deliverables: any screen/UI mockup, redesign proposal, design exploration, landing/print draft, or spec-less new screen goes through the Claude Code bundled `design` skill (Claude Design canvas preview) instead of a hand-rolled mockup file. Distilled from the full skill text (v2.1.236 bundle, read in-session 2026-08-30): step-zero pixel-perfect codebase match with exact resolved token values (no 4/8px rounding), settle-the-aesthetic-with-the-user via 2–4 axis-named low-fi direction artboards (self-chosen aesthetics = the documented slop path), the one static-vs-clickable scoping question, working-file custody + same-artifact republish (GUI-edited canvases read back as untrusted data), artboard-based option exploration with stable names and honest tradeoffs, literal copy vs few cross-cutting tweak levers, flex/grid+gap layouts that survive direct-manipulation edits, 44px/12pt scale floors + SVG-not-emoji icons + no fake OS chrome, copyrighted-designs refusal rule, and show-it-say-little handoff with a post-handoff recheck. Internal skill machinery (payload/seed/contract) deliberately NOT ingested — version-specific and owned by the skill itself. Edge cases carve the boundary: approved-spec implementation and live-site audits route to anti-slop-visual-design/responsive-layout and design-review tooling, not the canvas. frontend/index.md routing intro extended (visual-design deliverables) and design section +1 row, placed first as the phase gate. Related links added both ways (anti-slop-visual-design, responsive-layout, html-in-canvas).
## [2026-08-30] revise | frontend/design/design-canvas-workflow — agent-gate Check 3 remediation (PR #164). The gate's fact finding was half right: its "no skill named `design` exists" conclusion is refuted by ground truth (the skill is listed in the authoring session's available-skills roster as `design: Create a design canvas…` and its bundled payload exists on the authoring machine's disk; the reviewer's CI environment lacks the preview, and it conflated the skill with the unrelated `/design-sync` component-upload tool) — but the verifiability objection stands: the skill is an early research preview absent from public docs, so a single un-fetchable in-session source cannot carry `confidence: verified`. Fixed per AGENTS.md: confidence downgraded to field-tested with the experience context stated in the body; two live-fetched public sources added (anthropic.com/news/claude-design-anthropic-labs — official Claude Design product announcement, research preview, Claude Code handoff; explainx.ai 2026 post — /design ships in Claude Code as a research-preview command producing editable artboards via the Artifacts runtime); the mandatory-routing directive and the frontend/index.md load-when line conditioned on the skill appearing in the session's available-skills list, with the existing no-skill edge case as the explicit fallback; the unverifiable "design-review skill" name-drop in the audit edge case generalized to session-provided audit tooling.
## [2026-09-03] ingest | databases/selection — new category: datastore selection by workload (4 pages: choosing-a-datastore-by-workload, relational-jsonb-vs-document-store, vector-search-engine-selection, graph-workloads-relational-vs-graph-db); brave-search research, sources cited per page
## [2026-09-03] ingest | Knowledge flush (12 candidates): 6 new pages — frontend-forms-dropzone-copy-without-drop-handlers, frontend-design-multi-shape-canvas-mask, testing-quality-synthetic-corpus-measurement-floor, infrastructure-agent-orchestration-checkable-claims-in-an-adopted-plan, infrastructure-observability-suppression-key-for-a-recurring-failure, backend-common-change-impact-sibling-validators-on-a-shared-node; 4 merges — responsive-layout (media-query position override vs SDK inline style), validation-at-trust-boundaries (clamp persisted spatial values), test-data-and-isolation (env restore vs pop; fallback-masked local green), path-resolution (multi-name `command -v` is OR in bash/sh); 2 folded into open PRs #180 (shipped-commit negative control) and #179 (path-escape attribution)
## [2026-09-03] ingest | infrastructure-agent-orchestration-checkable-claims-in-an-adopted-plan — fold: cross-check a plan's Task order / Depends on table against each task's Steps prose; the prose names the real code-level dependency (wt-t4-event-push Task 03/04 inverted row)
## [2026-09-04] ingest | infrastructure-agent-orchestration-checkable-claims-in-an-adopted-plan — fold: a plan copied across repos under the same gate can carry a structural premise (local-path vs url-source manifest entry) that does not hold for the new target; read the target's real manifest field once before dispatch (+1 Do item, +1 Finding row, +1 field-evidence source from the dev-loop mpa1 dl-version-gate run, harvested 2026-08-23)
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sources:
- https://docs.python.org/3/library/ast.html
- https://peps.python.org/pep-0570/
last_verified: 2026-08-05
related: [qa-process-regression-scope, backend-python-language-mutable-state-traps, testing-data-test-data-and-isolation, testing-quality-policy-at-several-return-sites, backend-common-change-impact-widening-a-closed-value-table, backend-common-change-impact-corpus-sweep-before-a-rejection-rule, backend-common-errors-diagnostics-from-a-shared-code-path, backend-common-change-impact-inserting-a-guard-before-an-existing-side-effect]
related: [qa-process-regression-scope, backend-python-language-mutable-state-traps, testing-data-test-data-and-isolation, testing-quality-policy-at-several-return-sites, backend-common-change-impact-widening-a-closed-value-table, backend-common-change-impact-corpus-sweep-before-a-rejection-rule, backend-common-errors-diagnostics-from-a-shared-code-path, backend-common-change-impact-inserting-a-guard-before-an-existing-side-effect, backend-common-change-impact-sibling-validators-on-a-shared-node]
---

# Enumerating Call Sites Before Changing a Callee's Contract
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
id: backend-common-change-impact-sibling-validators-on-a-shared-node
domain: backend
category: change-impact
applies_to: [general]
confidence: field-tested
sources:
- Field incident 2026-08-31, linkly `impl/lnpl/lower.py` (task t8-agg-avg-min-max) — described under Sources
last_verified: 2026-09-03
related: [backend-common-change-impact-widening-a-closed-value-table, backend-common-change-impact-call-site-enumeration, backend-common-errors-diagnostics-from-a-shared-code-path, backend-common-change-impact-corpus-sweep-before-a-rejection-rule]
---

# Widening One Check on a Node That a Second, Older Check Also Gates

## When this applies

You are widening the set of declared types or values a construct accepts in a
compiler, linter, or schema validator's checking pass (a new legal source type
for an aggregate), and the construct's result lands in another declared slot on
the same node — an assignment target, a parameter, a return. Also when the
widened construct now passes its named check and the same statement is still
rejected by a function you did not edit, with a message that names the target
rather than the construct.

## Do this

1. **Enumerate every static check that runs on the node type or verb**, by
searching for the node name (`Assignment`, `visit_assignment`, the verb
keyword) rather than for the validation function you already know: an older
check on the same node does not mention the function you are widening.
2. **Classify each check by which attribute of the node it validates:**

| The check validates | Relationship to the widening |
|---------------------|------------------------------|
| The attribute you widened, through the function you changed | Covered by the edit |
| Another attribute of the same node (the target's type when you widened the source's) | An independent gate that keeps rejecting on its own message; it needs its own decision |
| A helper shared with other nodes | Enumerate that helper's callers ([backend-common-change-impact-call-site-enumeration]) before touching it |

3. **Admit the new case at the one call site that needs it** — a flag threaded
from the specific caller (`check_reference(..., allow_money=True)` from the
aggregate-assignment path) — and leave the check's default for every other
caller unchanged.
4. **Keep the existing regression test for the check's original rejection
passing unmodified**; it is the proof that the admission stayed scoped.
5. **Write the test for the composed statement** (`set target to <construct>`),
not only for the construct alone; the construct in isolation passes the
widened check and never reaches the second gate.

## Edge cases

| Case | Then |
|------|------|
| The rejection message names an attribute unrelated to what you widened | Search for a second validator on the node before re-editing the first; the first is complete |
| The second check is reached from several constructs | Thread the exception per call site; a widened default admits the type for every caller at once |
| The plan or brief names only the construct-specific check | Add the enumeration result to the task report — the plan's scope was the search that found one check |

## Instead of

| If you are about to | Do this instead | Why |
|---------------------|-----------------|-----|
| Re-open the function you just widened when the statement is still rejected | Grep for other checks on the same node or verb | Two gates on one node are the common shape (source-type check, target-type check); the second predates the change and never mentions the first |
| Relax the shared check's default so the new type passes everywhere | Pass a scoped flag from the one caller that needs it | A relaxed default removes the check for every other caller with no test reporting it |

## Sources

- Field incident 2026-08-31 (linkly, task t8-agg-avg-min-max, `impl/lnpl/lower.py`): after `_check_aggregate` was widened to accept Money, `sum payment.amount` compiled while `set report.totalAmount to sum payment.amount` still raised `LowerError` from `_Scope._dimension_of` ("declared type Money is neither Integer nor DateTime"), an RFC-0016-era assignment-target check the task brief never named. Fixed by threading `allow_money` through `check_reference`/`_dimension_of` from the aggregate-assignment call site only; the existing Money-rejection regression test for guard/`Value` contexts passed unchanged. No external source states this enumeration step; compiler texts describe semantic checks as several passes over one tree without naming the practice, so the page stays `field-tested`
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sources:
- https://doc.rust-lang.org/stable/nightly-rustc/rustc_errors/enum.Applicability.html
- https://www.nngroup.com/articles/error-message-guidelines/
last_verified: 2026-08-09
related: [backend-common-api-design-error-responses, backend-common-api-design-unenforced-declarations, backend-common-change-impact-call-site-enumeration, debugging-signals-reading-error-messages]
related: [backend-common-api-design-error-responses, backend-common-api-design-unenforced-declarations, backend-common-change-impact-call-site-enumeration, debugging-signals-reading-error-messages, backend-common-change-impact-sibling-validators-on-a-shared-node]
---

# A Rejection Message Emitted From a Code Path Two Constructs Share
Expand Down
1 change: 1 addition & 0 deletions wiki/backend/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Match your situation to a "load when" line; load only matching pages.
| Page | Load when |
|------|-----------|
| [widening-a-closed-value-table](common/change-impact/widening-a-closed-value-table.md) | Adding an entry to a closed table mapping names to magnitudes or codes (duration units, status codes, currency exponents, severity levels) that lives as a named constant; scoping that change from a search for the constant's name; a new entry parses at one layer and is rejected or mis-converted at another; deciding what to do about an inlined copy of the table in a hot path, a second language backend, or a fixture |
| [sibling-validators-on-a-shared-node](common/change-impact/sibling-validators-on-a-shared-node.md) | Widening the types or values a construct accepts in a compiler/linter/validator pass when the construct's result lands in another declared slot on the same node (assignment target, parameter); the widened construct passes its own check and the statement is still rejected by an older check naming the target; scoping the admission to one call site |
| [corpus-sweep-before-a-rejection-rule](common/change-impact/corpus-sweep-before-a-rejection-rule.md) | Adding a rule to a compiler/linter/parser/schema validator/repo gate that will start rejecting input the tool accepted silently, and the existing corpus must keep passing; producing the evidence a plan needs before writing the rule (reject count + rejected-path list, enumeration method stated); such a rule landed and went red on inputs nobody had called defective; deciding between narrowing the rule, an opt-in strictness level, and an exemption (whether unimplemented declarative input should reject/warn/ignore at all → common/api-design/unenforced-declarations) |
| [aggregation-layer-of-a-shared-helper](common/change-impact/aggregation-layer-of-a-shared-helper.md) | A plan, brief, or review comment says to unify or replace "the N call sites" of a helper and names them by line number rather than by what the code does; one site feeds a set-level SQL aggregate while another returns a per-row value that application code reduces later; a "shared helper" landed with one consumer adopting it and the other keeping its old semantics; deciding which layer owns a missing-value rule and whether the plan's grep-count acceptance criterion is reachable at all |
| [call-site-enumeration](common/change-impact/call-site-enumeration.md) | Changing the contract of a function/method/constructor other code calls — adding, removing, reordering or redefining a parameter — and you need the complete call-site list; scoping such a migration from a search; a migration scoped from recon came back green and then failed on call sites the search never listed; deciding whether to append a parameter or make it keyword-only (release-level re-test scope → qa/process/regression-scope) |
Expand Down
2 changes: 1 addition & 1 deletion wiki/frontend/accessibility/interactive-elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ sources:
- https://developer.mozilla.org/en-US/docs/Web/API/Popover_API
- https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inert
last_verified: 2026-08-24
related: [frontend-forms-validation-timing, frontend-agent-interfaces-agent-facing-tool-surfaces, frontend-design-anti-slop-visual-design, frontend-design-responsive-layout]
related: [frontend-forms-validation-timing, frontend-agent-interfaces-agent-facing-tool-surfaces, frontend-design-anti-slop-visual-design, frontend-design-responsive-layout, frontend-forms-dropzone-copy-without-drop-handlers]
---

# Building Clickable and Keyboard-Operable UI
Expand Down
2 changes: 1 addition & 1 deletion wiki/frontend/design/html-in-canvas.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sources:
- https://groups.google.com/a/chromium.org/g/blink-dev/c/t_nGEmJ_v4s
- https://tympanus.net/codrops/2026/05/13/exploring-the-html-in-canvas-proposal/
last_verified: 2026-08-29
related: [frontend-design-anti-slop-visual-design, frontend-accessibility-interactive-elements, frontend-design-design-canvas-workflow]
related: [frontend-design-anti-slop-visual-design, frontend-accessibility-interactive-elements, frontend-design-design-canvas-workflow, frontend-design-multi-shape-canvas-mask]
---

# Drawing Live HTML into Canvas for Shader and 3D Effect Layers
Expand Down
56 changes: 56 additions & 0 deletions wiki/frontend/design/multi-shape-canvas-mask.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
id: frontend-design-multi-shape-canvas-mask
domain: frontend
category: design
applies_to: [canvas, general]
confidence: verified
sources:
- https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
last_verified: 2026-09-03
related: [frontend-design-html-in-canvas]
---

# Masking Canvas Content With Several Shapes via destination-in

## When this applies

Clipping or masking canvas content (paint strokes, an image) to the union of
several shapes with `globalCompositeOperation = 'destination-in'`; painted
content disappears after the mask step; reviewing a loop that sets
`destination-in` and draws one shape per iteration.

## Do this

`destination-in` keeps "the existing canvas content … where both the new shape
and existing canvas content overlap. Everything else is made transparent." Each
application intersects against what the previous application left, so a
per-shape loop computes content ∩ shape1 ∩ shape2 ∩ …, which is empty for shapes
that do not all overlap.

| Case | Do |
|------|----|
| One mask shape | Set `destination-in` once and draw the shape onto the target |
| Several mask shapes (a union of regions) | Draw every shape with `source-over` onto an offscreen canvas of the same size, then set `destination-in` on the target and `drawImage(offscreen, 0, 0)` once |
| Shapes arrive over time (strokes, body parts added per frame) | Accumulate them on the offscreen canvas with `source-over`; apply the single `destination-in` draw when the clipped result is needed (once per frame) |
| The mask needs soft edges or its own blending | Build that on the offscreen canvas; the target still receives one `destination-in` draw |

Restore `globalCompositeOperation` to `source-over` after the mask draw so later
paint is not clipped by accident.

## Edge cases

| Case | Then |
|------|------|
| The shapes genuinely all overlap one region and per-shape application "worked" | It computed the intersection, not the union; the first non-overlapping shape added later erases the paint |
| Device-pixel scaling (`devicePixelRatio`) differs between target and offscreen canvas | Size the offscreen canvas in the same device pixels and draw it at `0,0` with the same transform, or the mask lands offset |

## Instead of

| If you are about to | Do this instead | Why |
|---------------------|-----------------|-----|
| Loop over mask shapes setting `destination-in` and drawing each one onto the target | Draw them all `source-over` onto an offscreen canvas and apply it with one `destination-in` `drawImage` | `destination-in` is an intersection with the current content; repeating it chains intersections and disjoint shapes leave nothing |

## Sources

- https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation — `destination-in`: "The existing canvas content is kept where both the new shape and existing canvas content overlap. Everything else is made transparent."; `source-over` draws new shapes on top of existing content
- Field evidence 2026-08-19 (mechameleon-web, commit e34c2c5): brush strokes clipped per body part with `destination-in` in a loop lost all paint; drawing the parts onto one mask canvas and applying it with a single `destination-in` `drawImage` restored the strokes, confirmed by an E2E frame comparison
Loading
Loading