Development record
Four more host-payload ingests echo payload-chosen values into their refusals, cleaned but never redacted: the class iss-2609290043245353 and iss-2609290144116254 fixed in reading and intent consistency. (1) scribe ingest (internal/core/scribe/ingest.go) passes 21 values through its own echo(), which sanitises and caps but does not redact: the output's _type and run (177, 180), an undeclared key (343), a disposition's item id, state and free text (481-516), among them. (2) release changelog ingest (internal/core/release/ingest.go) quotes next_tag (328), an out-of-set section (532) and a malformed record id (560) through termsafe.Sanitize alone, and the section is uncapped. (3) Five strict decoders return encoding/json's message raw, which names an undeclared field by the payload's own key: ideate record.go:248, lifeboat graveyard_lessons.go:83, synthesis_pressrelease.go:157, synthesis_principles.go:217, synthesis_review.go:275 (release ingest.go:478 sanitises the same message). A token or a home path in any of them reaches the terminal and the transcript. Fix direction: per site, describe a closed-shape value (termsafe.DescribeRefused), redact a name the reader needs through the canonical scanner, keep a value abcd wrote. Detector: each payload carrying a marker and a home path in each field is refused without either in the error.
Four more host-payload ingests echo payload-chosen values into their refusals, cleaned but never redacted: the class iss-2609290043245353 and iss-2609290144116254 fixed in reading and intent consistency. (1) scribe ingest (internal/core/scribe/ingest.go) passes 21 values through its own echo(), which sanitises and caps but does not redact: the output's _type and run (177, 180), an undeclared key (343), a disposition's item id, state and free text (481-516), among them. (2) release changelog ingest (internal/core/release/ingest.go) quotes next_tag (328), an out-of-set section (532) and a malformed record id (560) through termsafe.Sanitize alone, and the section is uncapped. (3) Five strict decoders return encoding/json's message raw, which names an undeclared field by the payload's own key: ideate record.go:248, lifeboat graveyard_lessons.go:83, synthesis_pressrelease.go:157, synthesis_principles.go:217, synthesis_review.go:275 (release ingest.go:478 sanitises the same message). A token or a home path in any of them reaches the terminal and the transcript. Fix direction: per site, describe a closed-shape value (termsafe.DescribeRefused), redact a name the reader needs through the canonical scanner, keep a value abcd wrote. Detector: each payload carrying a marker and a home path in each field is refused without either in the error.
A sixth decoder site joins the list from the review of lane drainEcho: scribe.go:198, decodeStrict, reached from ingest.go:328, returns encoding/json's undeclared-field message raw for the scribe output, the parked context and the parked manifest, and its duplicate-key refusal names the repeated key the same way.
Grounds
- pursued: a scribe, release, ideate or lifeboat payload carrying a marker and a home path in any refused field or undeclared key is refused without either in the error, still naming the field; a refusal that still carries the marker or the path would show it wrong
Frontmatter
| id | iss-2609290218032954 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-2609290218032954-four-more-host-payload-ingests-echo.md
open on GitHub ↗ · commit history ↗
mentions5
- iss-2609290043245353The reading ingest's refusals echo payload-chosen values unredacted. echo() in internal/core/reading/ingest.go cleans a value (termsafe.CleanProseLine) and caps it at maxEchoedBytes (120), but runs no privacy redaction, and 17 call sites use it: the output's _type, run_id, manifest_sha256 and position among them, beside values the manifest (abcd-written) supplies. A reading output whose closed-set or id field carries a token or a home path is refused with up to 120 bytes of it in the error, which reaches the terminal and the transcript. Found on the sweep for iss-2609290033521472, which fixed the same shape in lifeboat review and intent audit with termsafe.DescribeRefused and the audit redactor. Fix direction: per site, describe a payload value (DescribeRefused) or route it through the reading's own payloadField redactor (redact.go), leaving manifest-sourced values as they are. Detector: a reading output carrying a sentinel in each quoted field is refused without the sentinel in the error.
- iss-2609290144116254The intent consistency ingest's refusals echo payload-chosen values unredacted. validateConsistency in internal/core/intent/consistency.go quotes the findings payload's _type with a bare %q (line 804, the same shape iss-2609290033521472 fixed in the audit ingest), and quotes a hash value (873), a finding's class and severity (938, 941), an end's path (993) and quote (1000) through oneLine, which cleans and caps but runs no privacy redaction. Each refusal returns to the surface, so a token or home path pasted into one of those fields reaches the terminal and the transcript. Found on the sweep for the audit.go _type fix (fix2-drainSec). Fix direction: describe a closed-set value (termsafe.DescribeRefused) and route path and quote through the verdict-prose redactor, deciding per site whether the echoed value is needed to find the fault. Detector: a findings payload carrying a sentinel in each quoted field is refused without the sentinel in the error.
- iss-2609290300462829The implement loop's lane receipt refusal returns the strict decoder's message raw, the class iss-2609290218032954 fixed in scribe, release, ideate and lifeboat. The receipt is written by the implementer agent, so it is a host payload, and internal/core/implement/loop/receipt.go:179 formats jsonstrict.Decode's error with %v: an undeclared field or a repeated key is named by the receipt's own spelling, and a token or a home path in that key reaches the terminal and the transcript. receipt_test.go:193 pins the raw key (unknown field "verdict"), so the fix updates that pin. Fix direction: pass the message through scanner.RedactRefusal with the repository root, failing closed to a description. The run state (state.go:274) is out of the class: the loop is its only writer. Detector: a receipt carrying an undeclared key with a home path in it is refused without the path in the error, still naming the key.
- iss-2609290300464268The memory page ingest echoes payload-chosen values into its refusals, the class iss-2609290218032954 fixed in scribe, release, ideate and lifeboat. A DistilledPage arrives host-produced (memory ingest --pages-json, memory ask --page-json), and internal/core/memory/schema.go quotes its values with %v or %q, sanitised at most and never redacted: a source class (154), an ingested_at (170), the declared classes (299), the undeclared keys themselves (425), type, domain and slug (436-442), and the assembled filename (491, 531). A token or a home path in any of them reaches the terminal and the transcript. Fix direction: describe a closed-shape value with termsafe.DescribeRefused, and name an undeclared key through scanner.RedactRefusal. Detector: a page carrying a marker and a home path in each field is refused without either in the error.
- iss-2609290411321963The memory writer's page-filename refusal quotes the token it refuses. judgeFilename (internal/core/memory/redact.go, called from writer.go at the write boundary) refuses a page whose host-chosen type, domain or slug carries a hard_fail secret, and its message names the whole filename raw: a slug of ghp_ and forty characters is refused with the token in the error, so it reaches the terminal and the transcript, the class iss-2609290218032954 and iss-2609290300464268 closed elsewhere. The echo is deliberate and pinned: TestWriteRefusesASecretShapedFilename and the separator-spelling cases in writer_filename_test.go assert the refusal names the page, because the filename is the write's identity and the operator needs to know which page to repair. scanner.RedactRefusal cannot square the two: an underscore is a word character, so a token joined behind topic_auth_ has no word boundary and is not redacted in the joined name, and a token can straddle the type, domain and slug separators. Found by lane drainEcho3's sweep for iss-2609290300464268. Fix direction: seal, byte for byte in the joined name, every span the hard_fail findings over filenameJudgeTexts matched, and keep the rest of the name. That keeps both requirements, the page named and the token not echoed, so it needs no ruling; describing the whole name would give up the identity the test pins. Detector: a page whose slug, or a spelling across the separators, is a well-formed token is refused, nothing is written, and the refusal names the page with the token sealed.