Skip to content

Proposal review workflow

Distillation creates private proposals. Review is the boundary that turns one proposal into an authoritative note in Hacking/Deadwire/; a proposal never becomes course material merely because a model produced Markdown.

1. Build the review queue

Run the index from the repository root:

deadwire review-index

The resulting .deadwire/distill-staging/review-index.json contains local draft paths, draft hashes, titles, canonical source references, and failure records. It does not contain source excerpts. proposed entries are current #chunk: drafts; legacy entries are pre-chunk experiments and are excluded from queue counts.

Each draft also carries non-blocking review_flags when the text contains a destructive command, shell-pipe execution, reverse-shell pattern, exploit-framework invocation, or public IPv4 literal. A flag is a prompt for a human scope check, not an automatic rejection; the reviewer records the decision and keeps the lab boundary explicit.

2. Inspect one proposal

For PDF drafts, create a private packet with copies of the selected drafts, their exact extracted text, source hashes, and physical-page/character locators. Write a JSON array of 1–30 filenames selected from review-index.json into .deadwire/review-selection.json, then run:

deadwire review-packet .deadwire/review-selection.json \
  --output .deadwire/review-packets/new-review-batch \
  --source-root "/path/to/Hacking"

Open the packet's README.md. The original PDF links stay local. Source bytes must match the recorded SHA-256; page lengths must resolve the exact extraction span; missing or changed sources fail the operation. The packet snapshots drafts so later processing cannot silently change the material under review. Choose a new output directory for a new batch: existing packets are never overwritten. Keep packets under the ignored .deadwire directory or another private location; they contain source excerpts and must not be committed or uploaded to Pages.

Locators use zero-based page_index and half-open page-local char_start:char_end. The UI also lists one-based physical PDF pages. These are not verified printed page labels or visual bounding boxes. Legacy chunks assume 4,000 characters and 200 overlap; verify these settings against the generating run. The original source hash proves revision identity, not OCR fidelity, correctness of a claim, or successful execution of a command. EPUB/text packet adapters remain pending.

First source spot-check

A private six-draft packet from three books was prepared on 2026-09-11. Fourteen page-local text slices matched fresh direct extraction from their original PDFs. This validates those locators, not human claim support. Machine review found unsupported commands, conflated protocol details, and expected outcomes written as actual evidence in several older drafts. All six decisions remain pending; five carry revision recommendations. The selection was purposeful and small, so these observations are not a corpus accuracy estimate.

The packet includes machine-review.md, draft-hash-bound findings, a source-check record, and one schema-valid service-host proposal with needs_review claims and an unverified command. A reviewer must assess the sources and corrections before changing its status. No note or course paragraph was approved by assembling it.

Open the referenced Markdown file on the local machine and check the source revision privately. The reviewer should answer each question before creating a proposal:

Check Pass condition Reject or quarantine when
Identity The source hash and locator resolve to the intended revision The file is missing, a placeholder, or the locator is ambiguous
Originality The explanation is an original synthesis; short command tokens are bounded A long verbatim span or copied table is present
Claims Every externally checkable claim has one or more source references A claim is uncited, contradicted, or presented as verified without evidence
Commands Syntax, tool, environment, and status are explicit A command is unsafe, unbounded, or silently normalized
Safety The exercise names authorization, scope, abort, and cleanup It targets a public or third-party system or disables controls
Merge The candidate is distinct from canonical concepts and related proposals Similarity is treated as permission to merge without human reasoning

Preserve rejected proposals and the reason for rejection. A failed model parse is not a missing concept and must never create a graph node.

3. Create a typed proposal

Revise a flagged draft first

For a packet with machine-findings.json, use the host Codex CLI to produce a new draft against the checked source excerpt and the recorded findings:

DEADWIRE_ALLOW_CODEX_EGRESS=1 deadwire revise-packet \
  .deadwire/review-packets/new-review-batch \
  --output .deadwire/revisions/new-revision-run --limit 1

The findings file has an entries array; each item names draft, draft_sha256, recommendation: revise, an issues array, and optional primary_sources. The hash must match the packet's snapshotted draft. The runner validates both draft and excerpt hashes before invoking gpt-5.6-luna, includes revision inputs directly in the prompt, and preserves original drafts. --draft FILENAME selects one particular item; --limit is bounded to 1–30. Use a new output directory for each run and finish any active generation queue first: revisions run sequentially.

run.json records the provider/model, feedback hash, old and new content hashes, and pending-review status. A model failure stops the run and records an error type without copying private provider stderr. Explicit source-unavailable responses are rejected; this narrow check is not proof of source grounding. Completed revisions still require human inspection. The runner never updates canonical notes, grants approval, or changes the original staging queue counts.

On 2026-09-11, a five-draft revision run removed several previously flagged unsupported commands and verification claims. One response reported unavailable source text and was retained for diagnosis, prompting direct excerpt delivery and a regression check. This purposeful spot-check is not a measured model accuracy improvement or an acceptance sample.

Use a stable immutable ID and retain the source revision. Titles may change later; IDs and provenance must not. A minimal synthetic example is:

{
  "schema_version": 1,
  "proposal_id": "proposal-trust-boundary-001",
  "immutable_id": "trust-boundaries",
  "title": "Trust boundaries",
  "definition": "A boundary where identity, privilege, or authorization changes.",
  "domain": "foundations",
  "prerequisites": [],
  "related": [],
  "contrasts": [],
  "claims": [{
    "claim_id": "claim-observation-001",
    "statement": "An open port is an observation, not proof that a service is exploitable.",
    "source_refs": [{"source_id": "sha256:fixture", "locator": "page:1"}],
    "support_status": "needs_review",
    "contradicts": []
  }],
  "commands": [],
  "difficulty": 0.2,
  "importance": 0.9,
  "source_refs": [{"source_id": "sha256:fixture", "locator": "page:1"}],
  "created_at": "2026-01-01T00:00:00Z"
}

Validate before publication:

deadwire validate-proposal reviewed-proposal.json

Validation rejects unknown fields, missing provenance, invalid IDs, and out-of-range scores. It does not replace human source review.

The example deliberately leaves the claim at needs_review. After inspecting the source, record source_supported for a supported statement or an explicit contradicted status and contradiction references where appropriate. Publication rejects needs_review and unsupported claims. Do not change the status simply to make validation pass; revise or reject an unsupported proposal.

Commands require their own source_refs, even when their source is also listed on the concept. Keep verification_status: unverified until a human has inspected lab evidence. For lab_verified, evidence_refs must name nonempty files relative to the vault, such as learning/2026-09-11/session.md. The file check cannot verify that the recorded experiment actually happened.

4. Publish with conflict protection

For a new concept, publish only after a named reviewer signs the decision:

deadwire publish-note reviewed-proposal.json \
  --reviewer "reviewer-id" \
  --canonical-root "/path/to/Hacking/Deadwire"

For an update, first hash the current canonical note and pass it as --expected-hash. A mismatch creates a conflict and leaves the handwritten or iCloud-edited note untouched. Approved merges preserve aliases and redirects; they do not erase proposal provenance.

5. Rebuild derived views

After publication, export the canonical notes directly from their Markdown metadata:

deadwire canonical-export "/path/to/Hacking/Deadwire" \
  --output .deadwire/canonical.json
deadwire graph-rebuild .deadwire/canonical.json

graph-rebuild requires the running Neo4j service and DEADWIRE_NEO4J_PASSWORD. The exporter validates complete metadata, rejects duplicate concept IDs, unresolved prerequisites and cycles, and reports eligible node and relationship counts. Legacy notes with incomplete frontmatter require explicit repair using their reviewed proposals; they are never silently dropped. The JSON snapshot stays private and is rebuildable from the notes.

The Markdown metadata preserves claims, commands, source/evidence references, aliases, proposal IDs, and prerequisite IDs through this round trip. Deterministic round-trip tests on synthetic notes are implemented; a real reviewed-vault/Neo4j recovery drill remains an acceptance gate. Rebuild embeddings separately once the reviewed corpus index is available. Only reviewed concepts with valid prerequisites may enter a student plan.

Student-facing rule

The published course may describe a technique as an idea or an unverified command. It may call a command verified only when a learner records authorized lab evidence with environment, scope, timestamp, output, and cleanup. Reading a proposal, approving a note, or passing a retrieval test is not practical mastery.