Repository navigation
Fill in a published study's original wording on this computer (link + hash rehydration) - #94
Merged
Merged
Conversation
… hash) A published protocol.json (hsenv 0.8.1 release projection) holds placeholders where wording from a non-redistributable source goes. The app now restores it locally with hsenv.rehydrate and runs the study only once every screen is filled in. - pack/runtime/lib/hs_original_text.py: downloads link-tier sources (http(s) only, no local addresses, cached, failures retried after 10 min), tries the files the researcher dropped in (sources/private/, paper.pdf, sources/), checks every item by its text hash, caches the restored protocol per study version in app storage, and prints a status without any wording. PDF via the runtime's pypdfium2; without it, PDF sources say so and the other formats still work. - main/original-text.ts + package-readiness lane `text`: runs it from the app's own copy on open, on a dropped file and in readiness; missing wording blocks a protocol run; status for the agent in .humanstudy/original-text.json. A file dropped into a published study goes to sources/private/ and never becomes paper.pdf. - Engine checks: verbatim.unchecked no longer blocks when every unchecked source is a held one; table_spans_unserved is now listed. - Run: the restored protocol travels with the trusted run code; app_run plays it only when it is exactly protocol.json with the held texts filled in, records the approved hash and keeps no screens; a published study without it is refused. - Preview shows "[text not available]"; Simulation tab words each need in en and zh; run skill "Original wording" section for the agent. - Tests: invented fixture (link source over a local HTTP server, user files, hash mismatch, dead link, no PDF reader, newer extractor), node + pack tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion, safer downloads - app_run reads the restored copy from beside its own code, never from the environment, and accepts it only when every held text hashes to its text_sha256, no placeholder is left and nothing else differs (an agent-written copy can no longer put placeholders or other wording on screen). - verbatim.unchecked is relaxed only when it names held sources and counts no more texts than the held entries that really are placeholders. - Downloads: redirects to local/private addresses refused (is_global); a download that restored nothing (a sign-in page) is dropped and retried after ten minutes; candidate hashing uses the size cap; a file replaces a download only when it restores more. - Held pictures are not supported yet: the study stays unresolved with need "picture" instead of being marked complete. - Original-wording answers are kept at most ten minutes; "different PDF reader version" wording; plural fix; the run skill keeps the researcher's copy in sources/private/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in, restored checks - Engine checks: no app-side relaxation any more. Each held source (without its own sourcetext) gets a source text of placeholders, so the engine's own verbatim rule finds the held placeholders and still blocks any other verbatim text from that source (q3 is a regression test). The relaxed count rule is gone. - Once restored, hsenv.checks runs on the restored copy in app storage (held texts checked against themselves); any finding blocks, reported by check name only. - The held list is pinned in app storage on first sight; an edited or removed list (or leftover placeholders without one) blocks the run. - Research capture redacts tool input/output and raw parts that name sources/private/ or the original-text cache; a drop into a published study tells the agent not to open the file; skill and AGENTS.md forbid opening those files. - app_run refuses any protocol with placeholder runs and no restored copy (run_study is vendored: the upstream guard is a follow-up). - Downloads: 90 s per download / 150 s per check with a failure marker, a web page for a non-HTML source is a failed download, an unresolvable host is not public. - Strings: "original materials (the paper, questionnaire or booklet)", publisher only for link sources, singular/plural, plain format names; en and zh. - Tests: the run-records test scans every file the run left; PDF cases skip when pypdfium2 differs from the lock; fixture without the typed-number range. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on, honest recovery - Downloads: every socket read waits at most the time left and read1 takes what has arrived, so a trickling server stops at the deadline (test asserts elapsed time with a server that keeps trickling). - Research capture: besides a sturdier path rule (pieces, globs, searches under sources/, ./ segments, URL-encoding; .humanstudy/original-text.json no longer redacted), any tool, text, reasoning or raw part that quotes a 40-character run of a private copy, a download or the restored wording is dropped. The helper writes hashes of every such run (never text) to app storage; the app loads them per session and after each drop. - The agent note for a dropped private copy goes into the prompt only, not the bubble. - Held-list pin: the message says to put back protocol.json as received (no import path for published protocols exists yet); repinHeld for a future import path. - Restored-copy check: cached by the copy and the sourcetext contents, completed reports only; plain en/zh message without check names or blame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…leaner index - Research capture never collects a published study's run outputs (artifacts/simulations/, runs/), nor any project file that quotes a 40-character run of private text, nor (while anything is indexed) a file it cannot read as text (mayCollectFile, used by file snapshots and source collection). - Index: per project, minus every run that also occurs in the project's public files (protocol.json's shipped strings, effects.json, paper.pdf, sources/ outside private/); sorted 8-byte binary hashes in a typed array; each file's runs cached by sha256 so it is extracted once; written before any download, and a drop indexes the copy before importFiles returns. - A part over 300k characters is redacted whole while anything is indexed; glob and search path rules only where sources/private/ exists. - Own heading and button for "held list changed" / "checks failed"; the agent note matches dropped paths as whole strings (commas and ] in names). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… public - Research capture: redactCapture is the single boundary for private material. Every research-v1 event goes through captureResearch (the only caller of the collector: agent adapter, selection, program.json and artifact versions), and telemetry metadata through the same check before any blob. The agent adapter also blanks the end event of a tool call whose input named a private path (ra.mjs replay is a test). - Index: subtract only what verifiably ships, the protocol.json as received (stored with the pin at first sight) and files whose sha256 a hosted source of it records; never live sources/, sources/researcher/, effects.json or the live protocol.json (launder.py keeps all 37 runs, now a test). - Ordinary projects (not published, no sources/private/) keep collecting PDFs, figures and long texts; the unreadable/300k rules apply only in published or private-folder projects. - Drop chip shows "Adding <name>…" while the copy is indexed; the index merges sorted files and prunes those of folders that no longer exist; exact path tokens for the agent note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- redactCapture / redactPrivatePart check every string value raw (never the event's JSON), also with escape sequences turned into spaces and read-tool line numbers removed: quotes across lines, tabs, CRLF, heredocs in JSON inputs are caught (rc.mjs cases A-E are tests). - putBlob refuses private text itself; fit checks before anything goes inline or to a blob; the workspace context is redacted before it is fitted; the transcript's path rules are scoped by published status too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t logged - The redaction skeleton is letters only (any script, CJK included) in the app and the helper; every text is also checked with line enumerators removed (1., Q1:, (a), Item 3:, bullets). Index format v2: older .bin files are dropped and rebuilt. probe2/probe3 numbered, Q-prefixed, table and changed-numbering cases are tests; 0 of 8 ordinary texts flagged against a questionnaire index. - Reordered items or inserted HTML/Likert labels between short items are documented as an accepted limit of the beta. - An event target naming a withheld file in sources/private/ is not logged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A published protocol.json (hsenv 0.8.1 release projection) holds placeholders where wording from a non-redistributable source goes. This PR restores that wording on the researcher's machine with the bundled
hsenv.rehydrate. A study runs only once every screen is filled in and checked.Design
pack/runtime/lib/hs_original_text.py, run by main from the app's own copy and isolated like the checks, with network access only for downloads:sources/private/,paper.pdfandsources/<userData>/original-text/, never in the projectmain/original-text.ts, newtextlane inpackage-readiness.ts):.humanstudy/original-text.json(counts, titles, needs; no wording)distribution) is pinned in app storage the first time the study is seen. An edited or removed list blocks the run, and the message says to put back protocol.json as received.repinHeldafter writing a new published version.hsenv.checksruns again on the restored copy in app storage, and any finding blocksrestored/protocol.jsonapp_runreads it only from beside its own code and plays it only if every held text hashes to itstext_sha256, no placeholder is left and nothing else differssources/private/, and an app note in the prompt (not in the researcher's bubble) tells the agent the file was received to fill in the wording and must not be openedsources/private/or the app'soriginal-text/storageredactCapture:./segments or URL-encoded; globs and searches under sources/ count in published or private-folder projects1.,Q1:,(a),Item 3:, bullets), so re-numbered items and a 1-5 column still match. Against an 8-item questionnaire index, 0 of 8 ordinary texts were flagged.putBlobrefuses private text,fitchecks before anything goes inline or to a blob, and the workspace context is redacted before it is fittedmayCollectFile:artifacts/simulations/,runs/) and any file quoting private text are never collectedimportFilesreturns, and the chip shows "Adding …"[Attached: …]lineFollow-up for hsenv 0.8.2 / sandbox skills/run (vendored, not edited here)
run_study.load_protocol(orhsenv.engine.Protocol.load) should refuse a protocol with a non-emptydistribution.heldor runs of U+2591, so placeholders cannot reach AI participants by any route. The app already refuses them inapp_run.checks.check_verbatimshould report the paths it counts as unchecked, so the app can excuse exactly the held paths instead of passing a placeholder source text.Tests
npm run typecheck, the full node suite (320 pass, 2 skipped),pack/runtime/tests(574 OK) andscripts/tests: green, withHUMANSTUDY_TEST_PYTHONset to the app runtime's PythonFollow-ups
Open questions
🤖 Generated with Claude Code