ArgMap authoring tutorial
ArgMap authoring tutorial
Audience: a person who wants to read or write .argmap argument maps.
Format version: v0.2 (syntax frozen 2026-07-09; the v0.3 slash-pair
extension is noted where relevant). Semantics: ratified D36 defaults.
Agent-facing companion: the argmap-author skill
(.claude/skills/argmap-author/SKILL.md) compresses this tutorial into
the working loop; agents load it via the Skill tool, humans can read it
as the cheat-sheet-plus. Since 2026-07-27 the skill is meant to be
sufficient on its own for authoring (it carries the idiom catalog,
the label/gloss and nesting discipline, the limitations and the lint
codes in compressed form), so the division of labour is: skill = the
pattern, this tutorial = the rationale, the history, the reading
chapter, and the worked example in Appendix A. A third tier,
examples/README.md, indexes the example corpus by idiom for when you
want to see a pattern in a whole file rather than as a fragment.
This tutorial distills the project’s design docs and the accumulated
authoring experience into one document. It never overrides them: on any
point of doubt, FORMAT_DESIGN.md (syntax), GRAMMAR_DRAFT.md (grammar),
SOLVER_SEMANTICS.md (semantics), and GLOSSARY.md (terminology) are
authoritative, and DECISIONS.md records why things are the way they are.
MATH.md is the readable account of the mathematics the semantics rests
on (what the numbers mean formally, what has been proved about them, and
what is still open), and is the right next stop after chapter 4.
AUTHORING_NOTES.md is the dated log this tutorial condenses; new
learnings continue to land there first.
Snippet convention: every .argmap block in this tutorial is either a
complete file that passes tools/argmap-lint.py as shown, marked
(complete, lintable), or an illustrative fragment whose first line is
# fragment - not standalone.
Contents:
- What ArgMap is
- Reading argmaps (self-contained; you can stop after this chapter)
- The format
- What the numbers mean
- From source text to map
- Labels and glosses
- Structural idioms
- Writing large maps
- Limitations
- Checking your map
- Appendix A: a complete worked example. Appendix B: cheat sheet.
1. What ArgMap is
ArgMap is a plain-text format plus an editor and viewer for making complex arguments explorable. Instead of reading a linear essay, a reader navigates the argument as a graph: the main claim and its support are visible at a glance, and every reasoning step can be unfolded to the depth the reader wants. The motivating use case is AI safety argumentation, where the arguments are long, branching, and full of objections that attack specific inference steps rather than conclusions. The flagship content is a comprehensive map of the book “If Anyone Builds It, Everyone Dies” (IABIED), deployed at p1graph.org.
An .argmap file describes a bipartite factor graph with two node kinds:
- Statements (written with the
@sigil) are variables: propositions that can be true or false, optionally annotated with the author’s credence that they hold. - Evidences (written with the
$sigil) are factors: reasoning steps that connect statements, optionally annotated with a reliability.
Roles such as premise, lemma, and conclusion are never declared; they are derived from the graph topology (a statement nothing points into is a premise, one nothing points out of is a conclusion). Attacks are not a separate primitive either: an objection is an ordinary evidence whose conclusion is a negated statement, and an attack on an inference (an undercut) is an evidence that references the attacked evidence itself. This uniformity is the core design idea: two node kinds and one reference mechanism express support, opposition, rebuttal, undercut, and refinement.
The text file is the single source of truth. The editor renders it as an outline and a graph, but everything those views show is derived from the text, and everything you author happens in the text.
The v0.2 syntax is frozen (DECISIONS.md D25 to D33). Anything this
tutorial shows is stable; future syntax changes arrive as versioned format
changes (the first is the v0.3 slash pair, gated by an explicit
argmap-version: 0.3 frontmatter declaration).
2. Reading argmaps
This chapter is for readers: people who explore existing maps in the viewer or query them from the command line. It does not assume or require anything from the authoring chapters.
2.1 The viewer
The editor/viewer at p1graph.org has three synchronized panes: the
text (the .argmap source), the outline (a collapsible tree of the same
content), and the graph. Reader and focus views present single nodes and
their neighborhoods in a more article-like form. The graph starts
collapsed: boxes with a fold control contain refinements, finer subgraphs
that replace a summary reasoning step when unfolded. Folding follows the
source structure, so what unfolds together is an authorial decision, not a
layout heuristic.
Conventions worth knowing when reading:
@nodes are claims;$nodes are reasoning steps between claims.- An evidence pointing at a claim supports it; an evidence pointing at a negated claim opposes it. An evidence that takes another evidence as an input attacks (or conditions on) that inference itself, not its conclusion.
- A number on a claim is the author’s asserted probability that it holds.
A number on a reasoning step is its reliability: roughly, how likely
the step is to actually carry when its inputs hold. A trailing
?marks a number as estimated rather than deliberately asserted. - In the flagship map, numbers derive from the book authors’ own confidence language through a fixed rubric (DECISIONS.md D39), so disagreements the display surfaces are audits of the source’s coherence, not the map maker’s opinions.
2.2 Implied values and tension
The viewer can compute what all the authored numbers jointly imply. Under
“Show what the map implies” (in the Controls popover; on by default
since D40, though an explicitly persisted opt-out still wins), an
in-browser solver treats every authored number as a constraint and finds
the maximum-entropy distribution that honors them. Each node then shows an
authored -> implied readout; the editor calls the computed number the
implied value, and the technical documents call the same number the
solved value. The gap between the two is called tension,
and the display tints it: a large gap on a node means the map’s stated
argument does not deliver the stated belief at that node. Some statements
carry a check credence (a displayed comparison value that does not
constrain the solve); the badge comparing it to the implied value has the
same meaning.
2.3 The headless readout
To query a map without a browser, use the CLI readout (from the repo):
cd experiments/solver-prototypes
python3 solve_map.py ../llm-extraction/iabied-comprehensive-en.argmap @shutdown '$link'
python3 solve_map.py ../llm-extraction/iabied-comprehensive-en.argmap --top 10
The first form prints, for each named node, the authored value and the
solved value. The second prints the ten largest gaps and tensions in the
whole map: the places where authored numbers and computed numbers disagree
most. --band adds the forced interval for a named statement (how far the
constraints actually pin it, as opposed to where the solver settled inside
the allowed range). Quote $id arguments so the shell does not expand
them. The solver needs python3 with numpy and scipy, and node on the PATH.
That is everything a reader needs. To write maps, continue.
3. The format
An .argmap file is plain text, UTF-8, with optional YAML frontmatter,
comment lines, node lines, and footnote definitions. Indentation is
spaces only; a tab is a parse error.
3.1 Statement lines
@id [short label] p: gloss
@iddeclares a statement. IDs use[A-Za-z0-9_-], are case sensitive, and share one namespace with evidence IDs:@xand$xcannot coexist. Prefer mnemonic IDs (@risk-unbounded, not@s17).[short label]is optional. For statements the label is the claim, phrased as a proposition. If no label is given, the gloss serves as the display label.pis optional: the author’s credence that the statement holds, a probability literal in [0,1]. A trailing?(as in0.7?) marks the value as estimated or unelicited rather than deliberately asserted.- Everything after the
:is the gloss: one logical line of free text giving depth, sourcing, or qualifications.
A statement is a variable, so its label must be a proposition, something that can be true or false. “Anyone builds it” is a statement; “the question of whether anyone builds it” is not. Conditionality lives in evidences, never in statement labels. Normative propositions (“X should happen”, “doing Y is impermissible”) are legal and ordinary statements; what chapter 9’s fact/norm caution forbids is not norms but future-fact nodes that would feed back onto their own antecedents.
3.2 Evidence lines
$id [label] strength <conclusion-expr> | <premise-expr>: gloss
$iddeclares an evidence: a reasoning step asserting that its premises bear on its conclusion.[label]is optional and carries the headline warrant: why the premises support the conclusion, in a phrase (chapter 6).strengthis optional: a bare probability literal, the evidence’s reliability (chapter 4 explains precisely what it means).?works as on statements.- The
|is the given bar and reads “given”:$e @c | @ais evidence about@cgiven@a. The conclusion side is a full expression, not just a single reference. - The
| <premise-expr>part may be omitted entirely. A premise-less evidence is an unconditional constraint factor: it asserts its conclusion expression with the given reliability, unconditionally. Example from the spec:$rivals ~@hyp-fluke OR ~@hyp-filter: rival explanations can't both hold.
3.3 Expressions
Premise and conclusion sides use the same grammar:
- References:
@idfor a statement,$idfor an evidence (see 3.6), each optionally negated with~(~@id). Negating an evidence reference (~$id) is forbidden: it parses, but the validator rejects it (error E3). To challenge an inference, write an undercut (3.6). ANDjoins linked premises: the step needs all of them.ORjoins convergent premises: any one suffices.- Mixing AND and OR requires parentheses:
(@a AND @b) OR @c. Unparenthesized mixing is a parse error; there is no silent precedence. - Unicode
∧ ∨ ¬are accepted as input aliases; the canonical form is ASCII.&is not a connective (the|character is taken by the given bar, soORcannot be written|either).
Note the graph-level route to convergence: two separate evidence lines with the same conclusion are independent factors, which is usually the right way to say “two independent reasons” (see 4.6 for when it is not).
3.4 Refinement (nesting)
Indentation always means “belongs to the line above”. What belongs
means is read off the parent line’s sigil: under @ and $ it is
refinement (this section); under :: it is membership in a
declared group (3.10). Everything below is the @/$ case.
An indented block under an evidence is a refinement: a finer-grained subgraph that models the same reasoning step at higher resolution. When a reader unfolds the evidence, the block replaces it; folded, the outer line serves as the coarse summary. One consistent indentation increase per level (two spaces recommended).
# fragment - not standalone
$syllogism @socrates-mortal | @socrates-human AND @humans-mortal: surface form
@intermediate [Socrates inherits mortality property] 0.99:
$inherit-1 @intermediate | @socrates-human AND @humans-mortal-property:
$inherit-2 @socrates-mortal | @intermediate:
A statement may also carry an indented block; that refines the implicit factor asserting the statement’s own marginal, and the statement itself remains.
IDs are document-global: a node declared inside a refinement can be referenced from anywhere, and forward references (using an ID before its declaration) are legal. Where you nest is a real authoring decision, not formatting: nesting determines what folds away together in every view (DECISIONS.md D22).
3.5 Glosses and continuation lines
A gloss is one logical line, but it can be hard-wrapped: any
deeper-indented line that does not begin with @, $, or # folds into
the gloss of the nearest preceding node line, joined with a space. This
is also how longer narrative passages attach to a node without costing
graph structure:
# fragment - not standalone
@human-precedent [Human intelligence transformed the planet] 0.9?: Nobels to humans, none to chimps
a parable: a council of beast-"gods" laugh at the Ape-god's newest
creature, frail and clawless. The Ape-god says only, quietly, "and yet."
The hazard: if you forget a sigil on a node line, the line silently becomes gloss text of the node above. The lint warns when a prose line looks like a node declaration (W3); take that warning seriously.
The inverse hazard has no warning, and cannot get one. A continuation
line that begins with @, $, #, :: or > is read as that
construct, not as prose, because line dispatch is a first-character
switch, and by the time anything could complain, the parser has built a
node and has no idea prose was intended. So never start a continuation
line with a sigil character: begin with a word, or rephrase. The exposure
is small because quote lines (3.12) cannot wrap and the corpus barely
uses continuation lines at all, but when it bites there is no
diagnostic: you find it by reading the rendered gloss.
Two lexical restrictions: a gloss cannot contain a # preceded by
whitespace (that always starts a trailing comment), and a label cannot
contain square brackets.
3.6 Evidences as premises: conditioning and undercuts
An evidence named in another evidence’s premise expression denotes that evidence’s activation (“this inference is in force”), not its conclusion. There are two uses.
The positive use is conditioning on an inference: $policy @act | $link
makes a conclusion depend on an implication holding, rather than on a
fact. This is rare and legal; the lint flags it (W1) because the same
shape is usually a polarity mistake, so when you do it deliberately, say
so in a comment.
The common use is the undercut. To attack the inference $E C | P
(rather than its conclusion), write:
# fragment - not standalone
$E-undercut ~C | <grounds> AND $E: why the inference fails
The conclusion negates $E’s conclusion; the premises conjoin the
grounds with $E itself. Conditioning on $E is exactly what makes this
an undercut rather than a rebuttal: if $E is itself disabled or
undercut elsewhere, the undercut lapses with it. Dropping the AND $E
turns it into a plain rebuttal, which fires regardless. Undercuts of
undercuts (reinstatement) are the same schema applied again.
3.7 Comments and comment-layer conventions
A line beginning with # is a comment; a whitespace-preceded # starts
a trailing comment. Comments are preserved by the parser and serializer.
Section headings in large maps are full-line comments by convention. Use
one when the heading is only for a human reading the source. When you want
the heading to be checked and drawn, a named box around those nodes,
use a declared group instead (3.11): no tool can see a comment.
Two trailing-comment conventions carry meaning to the solver tooling without being syntax:
# check: pon a statement line records the author’s all-things-considered credence for display against the computed value. It never constrains the solve. Chapter 4 explains when to use it instead of an authored marginal. A check value may carry the?marker like any other value (# check: 0.9?), and in a source-faithful map it should: there the check is the source’s own stated register for that conclusion (the D39 practice), not the extractor’s belief.# gate: q($id) >= 0.10 => @conclusionrecords a threshold audit: after a solve, if the left side clears, the named conclusion is expected to hold, and the display reports agreement or disagreement.
Both are conventions, not grammar; tools other than the solver readouts will treat them as ordinary comments.
3.8 Citations
Attach citations as Markdown-style footnotes: [^ref] in a gloss, and a
definition line anywhere at top level:
# fragment - not standalone
@p1 [Capabilities advance rapidly] 0.9: doubling times keep shrinking [^epoch2025]
[^epoch2025]: Epoch AI, "Trends in Machine Learning," 2025.
Footnote text is free text: author, title, venue, year, plain URL. Viewers autolink URLs; there is no inline link syntax. The lint checks that every used footnote is defined and every defined footnote is used (W4).
3.9 Frontmatter and file layout
Optional YAML frontmatter between --- fences carries metadata: title,
author, date, description, source, scope (what part of the
source the map claims to cover, checklist item 6), and argmap-version
(declare 0.3 if the file uses slash pairs or quote lines). Unknown keys
are preserved, which makes frontmatter the extension point for
provenance notes.
One key is tooling-visible: focus: [id, id] (D57) declares the map’s
focus nodes, the statements influence readouts measure deltas on. Omit
it and the tooling derives them from topology (statements concluded by
top-level evidence and premised by none). Declare it only when topology
misreads your intent: the known case is a goal guard, a world-layer
conjunct like ... AND @shutdown on strategy-advice lines, which makes
the goal premise-referenced without arguing from it. The list is
complete, not additive.
Top-level order is free; the graph defines the structure. Convention: put the document’s headline claim first, then work down its support.
3.10 v0.3: two-sided pairs (brief)
Since D52/D53 a file declaring argmap-version: 0.3 may write two-sided
values: on an evidence, $e 0.9/0.2 @c | @a adds an opposed floor toward
the negated conclusion in the same slab; on a statement, @s 0.8/0.1
bounds P(s) to [0.8, 0.9] instead of pinning a point. No whitespace
around the slash; ? binds per member; an omitted second member is 0 and
means exactly the v0.2 reading. New maps can ignore pairs until they need
to express “this consideration cuts both ways” or an interval-shaped
residual; details in FORMAT_DESIGN §3.1/§3.2 and SOLVER_SEMANTICS §1.9.
3.11 v0.3: declared groups (::)
A third sigil declares a group: a named box drawn around nodes.
::timelines [Capability timelines]: when transformative AI arrives
@agi-soon [Transformative AI within a decade] 0.4:
@compute-grows 0.9: frontier training compute keeps growing
$scaling 0.7 @agi-soon | @compute-grows: the trend argument
Its indented block is membership, not refinement (the one place the
indentation rule is keyed on the parent’s sigil, 3.4). Otherwise the head
reads exactly like a node line: required id, optional [label], optional
gloss, and the same continuation-line folding.
Three properties define it:
- No credence. There is no probability slot on a
::line, now or later. A number there is an error. - Not referenceable.
::idin any expression is a parse error. A group takes no part in inference: you cannot argue from it or against it. - Transparent. Deleting every
::line changes nothing about the map: same graph, same roles, same solve. A group is display only.
Use one to say “these nodes are one topic”. Before ::, the only way to
say that was a # ==== banner comment, which no tool could see, check,
or draw.
Groups and blocks. A block is derived: a connected component of the graph, a set of nodes that reach each other. A group is authored. They usually coincide, and the validator checks the relationship: a group equal to one block, or spanning several whole blocks (“two topics under one heading”), is silent. Two shapes warn, because your claim and the graph disagree:
- a group covering only part of a connected block (W12): edges cross its boundary, so the layout distorts and the box cannot fold;
- one block split across two groups (W13): usually an accidental cross-topic premise silently merged two topics while your headings still assert they are separate. This is the mistake worth catching.
Only document-level groups are checked. A group nested inside another group, or inside a refinement, is subdividing its parent, not claiming a block.
Folding. A closed group, one where no edge crosses its boundary, folds to a card showing its label and member counts. A non-closed group does not fold; the control stays visible but disabled, with the reason. (Folding it would mean redrawing the crossing edges as summary edges, at which point the box starts standing in for its members, which is what refinement does, with none of the authored meaning that makes refinement safe.)
Groups are allowed anywhere: any depth, inside each other, inside refinements. Membership does not suppress the isolated-statement note: a context shelf of standalone facts still reports each one as isolated.
3.12 v0.3: source quote lines (>)
A line beginning > under a node carries a verbatim span from your
source, plus the footnote locator it came from:
# fragment - not standalone
@no-honor [Honor is a contingent evolved hack an AI won't carry] 0.9?: honor is
an evolutionarily contingent shortcut, not a convergent feature of minds
> a specific weird hack that humanity stumbled into [^supp-ch5]
> quite skeptical that gradient descent will happen to stumble across the
(the last line is shown truncated only for the page width, see “no wrapping” below.)
The gloss goes back to being a claim a reader can parse cold; the quotes
sit under it as its evidence. Before >, a quote could only live inside
the gloss, where no tool could see it. That meant no display affordance,
and, in a translated map, nothing stopping a paraphrase from being
presented as verbatim.
Rules, all short:
- The text is verbatim. Never paraphrase it, never silently repair it. If you need to trim, trim at the ends.
- Always give a locator.
[^ref]at the end of the line, defined at top level like any footnote (3.8). A quote without provenance is almost always an authoring slip, and the lint says so (W15). Locators are as coarse or fine as your source allows: a chapter ([^epub-ch7]), a supplement page ([^supp-ch5-promises]), a transcript timestamp ([^t001734]). - Only a locator at the very end of the line counts. Everything else
on the line is verbatim text, including a
[^…]in the middle of it (W16 flags that as a probable stray or doubled ref). - No trailing
#comment, the one line kind that has none. Source text cannot be reworded to dodge the comment splitter, so a real ` # ` in a quote would be silently truncated; instead the whole line is verbatim and the lint warns if it spots ` # ` inside one (W17). Put per-quote notes on an annotation comment instead (below). - No wrapping. A quote is exactly one line, however long; the editor soft-wraps it.
- Placement is positional. A quote attaches to the node above it and
must be indented deeper. It has to sit in that node’s annotation
block, the span before the node’s first child. A
>at top level, or after a child node, is an error (E9), not a re-attachment to some outer node. Order quotes after the gloss prose; interleaving parses, but the lint prefers the canonical order (W18) and the serializer rewrites to it anyway. - Declare
argmap-version: 0.3in a file that uses>(W19).
Which quotes become > lines: the three-way test. Ask: is this the
node’s own wording, or support for it?
- Supporting quote: a fragment stacked next to the claim as
evidence for it. Lift it to a
>line. This is most of them. - Load-bearing inline fragment: a verbatim phrase that is a
grammatical constituent of the gloss sentence (
Kelvin's "infinitely beyond…" fell to DNA). Leave it in the gloss, in plain quotation marks: it is the node’s own phrasing, borrowing the source’s words. When the provenance is worth keeping, add an echo, a>line carrying the full verbatim sentence and its locator, while the gloss keeps its fragment. - The quote is the claim: the gloss is nothing but the quote.
Degenerate case of 2: write the gloss in plain marks and echo the
verbatim on a
>line.
The echo pattern also keeps translations honest: a translated gloss
renders the fragment as ordinary quoted prose (claiming nothing about
verbatimness), while the > line stays in the source language.
Quotes are never translated. In a multilingual map set the whole >
line (sigil, indent, text, locator) is byte-identical across all
language versions, and tools/translation-parity.py enforces that. A
translated “verbatim” quote is false on its face and destroys the tie
back to the source.
Annotation comments (#[…]). Per-quote side data goes on a full-line
comment of the form #[key: …] (no space between # and [) on the
line above the quote, at the same indent:
# fragment - not standalone
#[de: schwer, der Schlussfolgerung zu entgehen]
> hard to avoid the conclusion [^supp-ch5]
To the parser this is an ordinary comment. Two things make the form
worth using rather than a plain #: the parity tool treats #[…] lines
as free per file (every other comment must match byte-for-byte across
translations), and it is the reserved surface for real attributes in a
later format version, so today’s convention promotes without a rewrite.
Its current tenant is the parked translation of a quote, waiting for a
real translation field.
4. What the numbers mean
The numbers are the part of the format most worth getting right and the part where intuition most often misleads. The ratified semantics (DECISIONS.md D36, full treatment in SOLVER_SEMANTICS.md) reduce to a small set of rules an author can hold in their head.
This chapter gives those rules operationally: what to write, and why it
behaves as it does. If you want the model underneath them (what the map
compiles to, why the solve is a maximum-entropy problem, and which of
these rules are theorems rather than conventions), that is MATH.md,
published as The mathematics behind ArgMap. Nothing here depends on
reading it.
4.1 Evidence strength
Elicit an evidence’s strength by asking: assume the premises hold; how likely is the conclusion? That prompt is the whole elicitation procedure. Formally the number is the unconditional in-force rate of the rule (how often this kind of inference actually carries), a property of the rule itself, independent of whether its premises happen to be true. The two readings coincide numerically by construction, so you can elicit with the conditional prompt and reason with either picture.
Practical consequences:
- The strength isolates the inference. Whether the premises are true is carried by the premises’ own numbers, elsewhere in the map. Do not discount a strength because you doubt the premises.
- Contraposition is not a rewrite.
$e 0.8 @c | @aand$e2 0.8 ~@a | ~@care different claims; the given bar is directional. When extracting or translating, preserve the direction the source actually asserts. - A strength of 1 is legitimate for deductive steps: the line becomes a pure constraint (“a proved implication has no reliability coordinate”). A strength of 0 is almost never what you want; the unstrengthed line is the exact “structure only” form (the lint suggests this, W11).
- An evidence with no strength at all contributes structure to the display but nothing to the solve. This is a deliberate, useful state: sketch the shape of the argument first, commit numbers later.
- Do not condition on a near-certain premise. The floor semantics constrain both slabs (given the premise, and given its negation), so when the premise expression is nearly a tautology (for example the OR of four of five partition members), the negated slab is almost empty and the constraint cannot be honored there; the solve shows a large spurious tension on that line. Condition on the informative complement instead (in the partition case, on the negation of the one remaining member), or drop the premise part entirely.
4.2 The drift tax, and when to counter it
Asserting a conditional lowers its antecedent. If the only line in a map
is $imp 0.8 @c | @a, the solved P(@a) comes out near 0.36, not 0.5.
This is principled (a rule that mostly holds makes worlds where its
premise holds and its conclusion fails rare), but it surprises authors.
Two remedies, both ordinary authoring:
- Author a value on the antecedent. Any authored value on
@arestores the intuitive reading exactly (the slab lemma: asserting P(a) pins the antecedent without touching the conditional). - If the source itself asserts the converse (“no build, no doom”), write
it as a second evidence in the other slab:
~@c | ~@a. This cross-slab converse pair cancels the drift and, more importantly, keeps the claim on the map where it can be attacked. The flagship map’s$no-doom-otherwiseis the worked example.
Do not confuse that with the same-slab pair (@c | @a opposed by
~@c | @a, or the v0.3 slash pair), which expresses two-sided evidence
inside one slab and compounds the drift rather than canceling it.
4.3 Statement values and the residual authoring rule
A statement’s authored value is a floor-style constraint, and the single most important discipline in the whole system applies to it:
Author only the evidence for or against a statement that is not already contained in the rest of the map.
- Frontier roots (statements with no incoming evidence in the map) keep their authored values. Their number is the map’s interface to everything unmapped; that is what roots are for.
- Derived statements (concluded into by mapped evidence) should normally carry no authored value. Their probability is the output of the solve. If you author one anyway, you are counting the mapped support twice.
- If you disagree with what the solve delivers for a derived statement,
you have three honest moves, in order: fix the argument (structure or
strengths); add the missing evidence as a new, named line (a
premise-less evidence is fine, but it must say what the evidence is);
or record your number as a check credence,
# check: p, and let the displayed badge show the disagreement.
The check credence is the designated home for “all things considered I believe 0.85 even though the mapped argument delivers 0.48”. It is displayed, compared, and never constrains the solve. Wanting to force a derived statement to a number is precisely the situation the rule exists to catch.
One explicit anti-pattern: a statement line carrying both an authored
value and a # check: comment. On a concluded-into statement the pin
double-counts the mapped support and, worse, fights the very evidence
you authored against it (the pin holds the solved value where the
counter-evidence should have moved it), while the check silently
disagrees with the pin. Concluded-into statements take a check or
nothing; only frontier roots take pins. The lint and the editor both
flag the pair as W23 since 2026-08-08, on any statement line,
because it is wrong wherever it appears: one extraction wrote both on
28 nodes, and the only visible symptom was that the gaps looked
suspiciously small.
The rule is topological and does not change inside refinement boxes. A hinge statement that sibling lines inside a refinement conclude into is a concluded-into statement like any other: check, not pin, even when the source asserts it at a clear register and the mapped internal support delivers less. That under-delivery is an audit finding about the source, not a display problem to pin away. When the source asserts the hinge directly, over and above the arguments it gives for it, that assertion is itself evidence and has a named home: a premise-less, attributed evidence line at the source’s register (the direct-assertion pattern, 7.13). It accumulates with the argued routes instead of clamping over them, and it is visible and criticizable in a way a pin never is. Under v0.3, a floor pair is the interval-shaped variant.
The distinction that keeps this straight: a statement’s own indented block explicates its number (the block refines the implicit factor asserting the marginal, and the statement keeps it, 3.4); sibling lines concluding into the statement replace it (the value becomes the solve’s output, and the author’s number moves to a check).
Also: inference through the map is not evidence you authored. If an
evidence about @a -> @c moves the solved P(@a) (drift, modus tollens),
do not “correct” @a’s authored value for it; that effect is already
contained in the map.
4.4 Independence, and what to do when it fails
Separate evidence lines are treated as independent mechanisms; their premise-less masses accumulate like independent reasons (noisy-OR). That is what makes two convergent lines mean “two independent reasons”. When the grounds actually overlap, independence double-counts. Three repairs, in increasing order of structure:
- Merge the lines into one evidence if they are really one argument.
- Name the shared source as a statement and condition both lines on it; the dependence is then authored in the world layer where it belongs.
- Complementary partition: make an “even if” explicit by conjoining
the negation of the other route, as in
$mwb-time ... | @wont-solve-in-time AND ~@align-hard(the two routes then partition the worlds instead of overlapping).
Two boundary clarifications. First, the discipline applies to lines converging on the same conclusion; one statement legitimately feeds premises of several different conclusions, and that needs no declaration. Second, genuinely independent routes stacking a hub high (noisy-OR takes four 0.85 routes past 0.99) is not by itself an error: if the source really asserts four independent sufficient reasons, the high number is what the source’s own logic delivers, and a lower check credence on the hub turns the difference into a visible audit finding (the source claims less than its own arguments compound to). Before accepting that reading, check whether the routes share an unnamed latent (repair 2); several “distinct” failure modes of one mechanism usually do.
4.5 Undercut strength
An undercut (3.6) carries the defeater’s operative rate: granted the grounds, how often does the targeted inference actually fail? The grounds’ own plausibility is carried by the guard statements, so do not pre-discount the undercut for it. Likewise, do not pre-discount a defeater because a response to it exists; author the response as its own undercut of the undercut and let the graph do the discounting. q’ = 0 is inert, q’ = 1 eliminates the target in context, values between interpolate.
An undercut does not, however, push its own conclusion. This paragraph said the opposite until 2026-07-27, when the skill-only sufficiency eval authored a cluster on the strength of it and produced a 0.61 statement gap; the claim is wrong and the correction matters for authoring. An undercut-shaped line compiles as a pure inhibitor of its target: per the factored-A compile (SOLVER_SEMANTICS §1.2), “inhibitors carry no zero-set of their own”, so the negated conclusion the line names receives no independent floor from it. Measured on the ratified defaults: an undercut whose target is unstrengthed leaves its conclusion at 0.500, exactly as if the line were absent; and an undercut of a rebuttal recovers the claim monotonically toward the value it would hold with the rebuttal absent (0.500 → 0.866 against a rebuttal-free 0.898), never past it, which is what T13’s “recovers monotonically to ≈p” records.
The authoring consequence: when the source both raises an objection to an inference and asserts the fact that objection rests on, the undercut carries only the first. If you want the fact to bear on the claim as well, give it its own ordinary evidence line beside the undercut. That is not double-counting (the inhibitor acts on the inference, the plain line acts on the claim), and without it the fact the source actually reports is silently absent from the solve.
4.6 Solved values, tension, and 0/1 pins
The display is computed-first: the solved value is the primary number, authored values remain the constraint set, and tension is the per-line gap between them. Since D36 a tension badge means “your stated argument does not deliver your stated belief”, which is information about the argument, not an error to be tuned away. The flagship map deliberately keeps several badges because they are audit findings about the source.
Authored 0 and 1 on statements delete possible worlds outright (“world-killers”, SOLVER_SEMANTICS P3) and are a smell; if you mean “very confident”, write 0.97, or give an interval with a v0.3 pair. The honest wide statement is cheap; the false point is not.
5. From source text to map
This chapter is the workflow that produced the flagship map, distilled from the re-authoring passes logged in AUTHORING_NOTES.md (2026-07-16 through 2026-07-24). It assumes you are extracting an argument from a source (a book, an essay, a debate); mapping your own argument works the same way with yourself as the source.
5.1 Pass 1: skeleton
Extract structure only. Statements, evidences, refinement nesting, labels, glosses, citations; no numbers (unstrengthed lines are legal and compile-inert).
Work in three sub-passes, in this order, because the two extraction directions fail differently: pure top-down invents structure (hub statements the source never asserted, which then solve near-tautologous), while pure bottom-up extracts each section faithfully and never authors the connective tissue: a buried spine (W21) and shared grounds double-counted across clusters. The 2026-08-03 He-essay extraction hit both in one day.
- Spine first, top-down: transcribed, never invented. If the source
draws its own overview (a section-2 diagram, an abstract’s roadmap, a
title conditional), transcribe it: the top tier, the declared foci
(
focus:), the region list and prefix scheme, recorded as the manifest comment (chapter 8). Where the source asserts its own structure (“this is not a conjunction”, “either route suffices”), that assertion is quotable content and belongs to this sub-pass, not to your judgment. Genre flip: a debate or interview asserts no overview up front; there, extract bottom-up first and write the spine once the meta-shape emerges (usually in the wrap-up). Never fake a spine the source did not assert: an invented spine is the top-down failure mode wearing a checklist. - Regions bottom-up, in source order. Local links under local
conclusions, each step citing its sentence; this is where source
fidelity lives. The decisions to make deliberately:
- Statement granularity: what gets to be a claim. A statement label must be a proposition. If a source item is not a premise-to-conclusion step (a meta-principle, a design artifact, pure framing), keep it as a folded gloss or one node with a comment, not as a conjunct in the inference chain.
- Linked vs convergent:
ANDonly where the step genuinely needs all conjuncts (test: does the inference fail if this conjunct alone is false?). Independent routes are separate evidence lines. If a comment says “independent paths” and the factor saysAND, one of them is wrong. - What each objection targets. For every objection ask: which
inference does this grant, and which does it deny? An objection
to an inference is an undercut conditioning on that
$id; an objection to a claim is a rebuttal concluding~@id. Mis-typing this is the most common structural error in first passes. - Objections travel with their answers. A response cites its
objection, never the reverse, so a map loses rebuttals more easily
than it loses attacks: skim extraction, later trimming, and source
prose itself (objections are stated loudly, answers quietly) all
bias toward attacks left standing unanswered, and the solve then
prices an unanswered attack at its full authored strength. Measured
on the settled-question benchmark (the H. pylori map,
experiments/solver-prototypes/GROUND_TRUTH_PROBE-2026-08-13.md): deleting map lines at random flipped the known-true conclusion in a majority of orders, and the flips were driven by responses dying before their objections. So when you record an objection, hunt for the source’s answer with the same diligence you gave the objection, and when you must cut for scope, cut the objection and response as a pair rather than the response alone. The answered-attack audit (argmap-query, reference inmvp/README.md) lists every attack and who answers it. - Nest each cluster’s internal traffic (grounds, caveats, objection pairs) under its target.
- Reconcile: where the real work is. Shared grounds are discovered in sub-pass 2, not planned in 1; promote each to the home the burial test picks, which is the nearest container covering every consumer, not blindly the document top (a ground consumed only inside one case block homes at that block’s top rank). Merge or partition lines that turn out to share grounds (chapter 7’s overlap repairs). Set the tier per chapter 8’s spine test: the source’s disclosure order is the guide (the He map’s depth 0 is its abstract, depth 1 its section-2 overview, depth 2+ its detail sections), with cross-tier edges kept visible as top-level evidences or coarse hulls. Then run the lint, and the nest-audit readout for fold candidates you missed.
5.2 Pass 2: numbers, blind, by rubric
The numbers should reflect the source’s confidence, not your own and not what makes the map solve nicely. The discipline that keeps this honest (pre-registered for the flagship map as D39):
- Fix a verbal-to-probability rubric before assigning anything: a table from the source’s confidence language to values. The flagship rubrics (AUTHORING_NOTES 2026-07-19) map, for example, categorical repeated assertions to 0.93, flat unhedged entailments to 0.9, “by default” claims to 0.85, “could well” to 0.7; grants of an opposing point take the conceder’s register. Keep two tables, one for statement registers and one for inference-step language (the flagship’s statement classes vs R-STEP), even if the values happen to coincide. Where the source is silent, a role default applies: a value your rubric assigns to a structural role rather than to any phrase (a default for an unhedged asserted step, one for an objection the source raises to deflect, and so on); define these in the rubric itself, because you will need them. Convention: the rubric lives in a comment block immediately after the frontmatter.
- Assign all values before the first solve, and do not move them afterwards. If the solve surprises you, the finding is about the argument (or the rubric), and it should be recorded, not tuned away.
- Mark provenance. Every rubric-derived number carries
?. A bare number is reserved for values the source states as a credence or probability (“ten to twenty-five percent extinction odds”). A stated frequency or rate (“below one fatal accident per twenty million flight hours”) is not a credence: keep it in the gloss and derive the statement’s value from the assertion’s register as usual. A stated number on a derived statement goes in a trailing# check:comment, never a pin (rule 4.3.2). - The composition rule when hedges stack: the outermost hedge governs. When two readings are defensible, author the weaker and log both. The same rule covers a source that asserts one proposition in two places at two registers: author the weaker register, note the stronger in the gloss or log.
5.3 Pass 3: review
The seven correction classes that were actually needed, in review- checklist form (every one was discovered as a correction, not foreseen; AUTHORING_NOTES 2026-07-19):
- Strength provenance. Does every strength trace to source
confidence language through the rubric? Is
?on everything rubric-derived? - Undercut target typing. Per objection: which inference does this grant, and which does it deny? (Policy objections wearing implication-undercut shape were the flagship’s most instructive mis-typing.)
- Overlap double-counting. For every same-polarity convergent pair: merge, factor out the shared span, reroute an instance-of to the shared ground, or leave independent and say so in a comment (silence is indistinguishable from an unaudited pair).
- Connectivity. Every non-headline statement should feed some evidence. Dangling sub-conclusions are usually missed links. A norm the source argues for should not stand unargued in the map.
- Nesting. First passes come out flat. Fold clusters under their local conclusion; keep cross-cluster shared ground at top level.
- Coverage. Do a full-source pass before calling the map faithful; record the source’s scope in the frontmatter. Summarizing from memory under-extracts.
- Mechanical smoke. Run the lint, the real parser (open the file in the editor), and a headless solve (chapter 10) before calling it done.
Two additions from later passes:
- Defeat presupposition. For every response/rebuttal: which epistemic state does its ground presuppose? If a response only works while X is undemonstrated, conjoin the statement that says so (a guard), so the defeat lapses in worlds where X is demonstrated.
- Multi-voice overlap. When two speakers concur non-diametrically, do not give them independent convergent lines. Full concurrence is one line at the weaker register; a subset relation is the shared span plus a residual increment elicited conditional on it; an instance supports the shared ground, not the downstream conclusion; genuinely disjoint mechanisms stay independent with a comment saying so.
5.4 Quoting and citation discipline
Keep verbatim spans to at most one sentence, roughly 25 words, normally one per node; never alter a quote silently; never reproduce a self-contained creative unit (a parable, a poem) whole; retell and compress instead. Whole-map verbatim budget from any single work: low hundreds of words, and for a short source proportionally less (a tenth of the source is far too much regardless of the absolute count).
Where the span goes is the 3.12 test. A quote that supports the claim
belongs on its own > line with a [^ref] locator; a verbatim phrase
that is a grammatical part of the gloss sentence stays in the gloss in
plain double quotes, optionally echoed by a > line carrying the full
sentence. The budget above counts both. (The older convention of marking
in-gloss quotes ~"…" is retired, and W20 flags any survivors.)
6. Labels and glosses
Statement labels and evidence labels do different jobs.
- A statement label is the claim itself, a proposition, and may be a full sentence. Statement labels are not length-linted.
- An evidence label is the headline warrant: why the premises bear on the conclusion, in a phrase. Evidence labels crop at about 56 characters in the graph (lint W5), so distill; the depth goes in the gloss. Not every evidence needs a label: structural connectors (an obvious deductive step) are better left unlabeled than given a filler label. In the flagship corpus about half the evidences carry labels.
- The gloss is the depth tier: the full reasoning, qualifications, asides, source voice, quotes. Glosses are never length-linted.
The three-job test for evidence gloss text, from the corpus survey that
motivated evidence labels (AUTHORING_NOTES 2026-06-12): gloss content is
either (a) a role tag (“undercut of …”), which is derivable from
topology and should be deleted; (b) the warrant, which belongs in the
label; or (c) format-meta commentary, which belongs in a # comment.
What remains after the test is the genuine depth tier. Job order matters
even inside a gloss: put the substantive point first, because displays
crop from the end.
Two further conventions from the accessibility passes:
- Plain-first, technical-nested: write the gloss in plain language; move a technical restatement to a folded continuation line beginning “technical reading: …”.
- Rubric provenance is not reader content. Elicitation citations
(“R-STEP S2: …”) go in a trailing
#comment on the node line, not in the gloss. Reader-valuable quotes and footnote refs stay in the gloss. - In multi-speaker maps, prefix evidence labels with a speaker tag (“A:”, “L:”, “AL:”); IDs are invisible at graph junctions, so the label carries attribution.
7. Structural idioms
The patterns below carry most of the flagship map
(experiments/llm-extraction/iabied-comprehensive-en.argmap; line
numbers are as of 2026-07-25 and may drift, so each entry also names the
anchor to search for). Excerpts are trimmed; open the real file for the
full context. All excerpts are fragments, not standalone files.
The same catalog appears in compressed form in the skill’s
## Structural idioms section, numbered to match these subsections
(7.1 = idiom 1, and so on). For a pattern in a complete small file
rather than as a fragment, examples/README.md maps each example to the
idioms it demonstrates.
7.1 The objection/response triple
The workhorse. An objection statement (the hope or doubt), an objection evidence concluding against the target, and a response undercutting the objection evidence:
# fragment - not standalone (flagship ~line 628, anchor "@c11-readthoughts")
@c11-readthoughts [We'll read the AI's thoughts and catch bad plans] 0.15?:
$c11-readthoughts-obj 0.2? ~@wont-solve-in-time | @c11-readthoughts:
$c11-readthoughts-resp [punishing visible bad thoughts hides them] 0.85? @wont-solve-in-time | @steering-finds-subversion AND $c11-readthoughts-obj: training against legible bad thoughts selects for concealment, not for good ones
FAQ-shaped sources map one-to-one onto rows of these. The -obj/-resp
ID suffixes are a mnemonic convention, not syntax.
7.2 The undercut ladder, including second-order undercuts
Rebuttal, undercut, response, and undercut-of-undercut are one schema applied repeatedly (flagship ~line 283, anchor “$uc-counting”):
# fragment - not standalone
$uc-counting [this argument form fails in ML contexts] 0.3? ~@fragile | @nn-generalize AND @sgd-bias AND $fragile-count:
$uc-uc-counting [the ML rescue may not transfer to alignment] 0.7? @fragile | @gen-not-values AND $uc-counting:
The second line reinstates @fragile exactly to the extent the first
line’s rescue fails.
7.3 Linked and convergent, side by side
One hub with both shapes (flagship ~line 269, anchor “$fragile-ev”):
# fragment - not standalone
$fragile-ev 0.9? @fragile | @orth AND @contingent AND @fragility:
$fragile-count 0.7? @fragile | @counting: lottery-ticket prior over goal-space
The first is a linked three-conjunct rule (all needed); the second is an independent convergent sibling on the same conclusion. The test for linked: neither conjunct alone suffices. The flagship’s cleanest statement of that test (anchor “$spread-ev”): “neither end alone shows disagreement; together they are the spread”.
7.4 Convergent siblings instead of a false AND
When a source presents overdetermined routes (“any one of these suffices”), write separate evidences, not one conjunction (flagship ~line 170, anchor “$adv-speed-ev”):
# fragment - not standalone
$adv-speed-ev [speed alone breaks the human range] 0.9? @ai-advantages | @adv-speed:
$adv-copy-ev [copyability alone breaks the human range] 0.9? @ai-advantages | @adv-copy:
$adv-selfimp-ev [self-improvement alone breaks the human range] 0.75? @ai-advantages | @adv-selfimp:
The flagship originally had these as a four-way AND; the repair note in the file records why that was wrong (the book is explicit that no single advantage is necessary).
7.5 Coarse summary plus refinement
The whole book’s case is one coarse line whose refinement holds everything (flagship ~line 261, anchor “$link “):
# fragment - not standalone
$link [the book's claim as one coarse implication] 0.93? @everyone-dies | @if-built: unfolds below into the full case
The coarse strength on a refined line is not a solver input (the refinement replaces it); it is the evidence-side check, displayed against what the refinement delivers. Recommended practice: author the coarse strength as your holistic judgment of the whole implication before trusting the steps; the comparison is a free audit.
A layout-driven special case is the coarse hull (see the spine test, 8): when the fine conjunction mixes one cross-region premise with hubs that belong inside the region’s fold, condition the coarse line on just the cross-region premise. The refinement holds the fine line and the local clusters; the collapsed view keeps the cross-region edge.
7.6 The complementary partition (“even if”)
Two routes that would overlap are made disjoint by conjoining the negation of the other route (flagship ~line 638, anchor “$mwb-time”):
# fragment - not standalone
$mwb-hard [the hardness route] 0.9? @misaligned-when-built | @align-hard:
$mwb-time [the timing route, in the solvable worlds] 0.9? @misaligned-when-built | @wont-solve-in-time AND ~@align-hard:
The ~@align-hard conjunct is the source’s own “even if alignment were
solvable” made explicit; without it the two routes double-count.
7.7 The balancing evidence
A conditional is vacuous outside its slab, so a map whose every evidence
on @c conditions on @a says nothing about the ~@a worlds. If the
source asserts the converse, name it (flagship ~line 254, anchor
“$no-doom-otherwise”):
# fragment - not standalone
$no-doom-otherwise [no build, no doom] 0.9? ~@everyone-dies | ~@if-built: the book's own converse of the title conditional
This is the cross-slab converse pair of 4.2: it cancels the drift tax and keeps a contested base-rate claim on the map, right of a given bar, instead of hiding it in a prior.
7.8 Conditioning on an inference (the designed W1)
A policy conclusion that hangs on an implication, not on a fact (flagship ~line 770, anchor “$shutdown-ev”):
# fragment - not standalone
$shutdown-ev [if built means everyone dies, no one may build] 0.93? @shutdown | $link:
Conditioning on @everyone-dies instead would be subtly wrong: doom
that were unconditional would justify no ban. This is the rare positive
evidence-as-premise; the lint fires W1 by design, and the file says so
in a comment.
7.9 The shared latent conjunct (one doubt, many hopes)
When k objections are expressions of one underlying doubt, name the
doubt as a statement and conjoin it into every member; elicit its prior
once, family-holistically (flagship ~line 435 onward, anchor
“$hope-care”; the shared conjunct is ~@no-right-care):
# fragment - not standalone
$obj-cheap 0.7? ~@not-preserved | @cheap-keep AND ~@no-right-care: a sliver of care plus a negligible bill would get paid
$resp-cheap [it would need a reason to pay ours] 0.9? @not-preserved | @needs-motive AND $obj-cheap:
Prefer as the latent the statement the support side already denies, so attack and support quantify over the same worlds. This was the only structure (of six probed) that stayed stable as hopes were added.
7.10 The epistemic-fact reification (norms and credal thresholds)
“A risk no one can bound justifies a ban” is a threshold argument over a credence, which the solver cannot represent directly (facts about credences are not world facts). The pattern: reify the evidence-state as a first-order statement, state the norm as its own statement, and let a near-deductive step combine them (flagship ~line 793, anchor “@risk-unbounded”):
# fragment - not standalone
@risk-unbounded [No one can currently bound the extinction risk below the actionable threshold]: a fact about what has been demonstrated, not about anyone's opinion
@no-gamble [Running a risk no one can bound below the threshold is impermissible] 0.93?: the norm, stated where it can be attacked
$shutdown-fine [unbounded risk + the norm license "don't build"] 0.9? @shutdown | @risk-unbounded AND @no-gamble:
$bounded-escape [a demonstrated bound would dissolve the case] 0.9? ~@shutdown | ~@risk-unbounded:
Note $bounded-escape: the author naming the condition under which
their own conclusion lapses. A self-declared off-ramp is both honest and
persuasive. The wrong shapes (conditioning on the chance itself, an OR
over world-types) are documented as fixture
examples/edge-cases/e15-reified-chance.argmap.
7.11 Rebuttal guards (which epistemic state does the defeat presuppose?)
Seven flagship responses only work while the risk is undemonstrated, so
each carries the guard conjunct @risk-unbounded AND ... (flagship
~line 688, comment anchor “risk-conditional rebuttal guards”). Structure
only, no new numbers: in worlds where the risk is demonstrated bounded,
the defeats lapse and the objections revive. Ask this of every response
you author (checklist item 8).
7.12 Exclusive alternatives and authored abduction
Rival explanations that cannot both hold are a premise-less constraint
factor plus an authored abductive step
(examples/09-exclusive-causes.argmap, the pattern catalog):
# fragment - not standalone
$who [an eaten cake means one of the two ate it] 1.0 @alice OR @bob | @cake: the abductive step, stated as a contestable rule
$notboth [they would not both have eaten it] 1.0 ~@alice OR ~@bob: premise-less unconditional constraint factor
The lesson recorded there: abduction is authored, not free. Pinning the effect gives the causes no diagnostic lift by itself; “it must have been one of them” is a premise, and making it a visible, attackable node is the point.
7.13 The direct-assertion pattern (spoken and debate sources)
A flat spoken assertion with no stated grounds becomes an attributed
premise-less evidence (experiments/llm-extraction/debate-tang-shapira.argmap):
# fragment - not standalone
$a-blur [A: attention is a blur of what causes what] 0.9? @opaque: the quadratic self-attention transformer "literally is a blur of what causes what" [^t005008]
Sixteen of these carried the debate map. Related: a refusal to give a number (“P(doom) is not assignable”) needs no special syntax; leave the marginal blank and, if the refusal is itself argued, map that argument as an undercut cluster against assignability.
7.14 The parable at zero depth
Narrative belongs in folded gloss continuation lines, not in nodes (flagship ~line 165, anchor “a parable”): a whole illustrative story attaches under one statement, costs no graph structure, and folds away. Use this for the source’s most persuasive prose, which is usually exactly the material that does not decompose into premises.
8. Writing large maps
The flagship map holds roughly 200 statements and 270 evidences at depth 5. The disciplines that made that possible (AUTHORING_NOTES 2026-06-18 onward):
- Width, not depth. Every new objection cluster is a sibling under its target, never a deeper chain. When a sub-debate wants an eighth level, promote the deep node to a shared top-level node instead. Node count can triple while max depth stays flat.
- A manifest comment block at the top, past about 150 nodes: the
coarse spine drawn in ASCII, every shared node listed with its home
region and consumers, and the region-prefix scheme stated
(
@c5-trade,$c5-trade-obj,$c5-trade-resp). Build in dependency order; lint after every region. - Reuse shared grounds aggressively, and annotate each reuse site with a comment naming the home region; otherwise later editors bury cross-references. A handful of high-traffic shared nodes is what keeps maximal coverage finite.
- Home shared nodes above the clusters that use them. An evidence folded inside a refinement contributes no edges while folded, so the spine and shared grounds must not be buried inside clusters. A node declared inside a cluster whose every edge leaves it is a “stranded node” (validator W6); re-home it with its consumer.
- Folding is a source-structure decision. Where you nest is where readers’ fold boundaries are. Author clusters as refinements under their target; keep shared material outside.
Nesting discipline
Nesting looks like an art but is mostly a mechanical review pass. Real
arguments cluster on their own; first drafts nevertheless come out flat
(checklist item 5), typically with the clusters already visible as #
section-heading comments. Treat that as the diagnostic: section
headings are nesting debt. A divider comment organizes the text file;
only indentation organizes the reader’s view. If you felt the need for a
# ---- divider, the argument just told you where a fold boundary is.
Three tests turn the debt into structure:
- Fold-unit test. Would a reader want to collapse this sub-debate to one line? Then give it a wrapper evidence whose refinement holds the cluster (7.9’s hope-battery shape), and author the wrapper’s coarse strength as your holistic judgment of the cluster’s net force; the refinement-vs-coarse comparison then audits you for free (7.5). Smaller version: a statement’s grounds and their evidences nest under the statement.
- Burial test. Anything referenced from outside the cluster moves up out of it. A shared ground homed inside one cluster still works, but it renders as a cross-reference burial and, in the worst case, a stranded node (W6). Home shared nodes above every cluster that uses them.
-
Spine test. The collapsed view must already show the argument’s shape: a folded evidence contributes no edges, so a buried spine disappears from it, and the validator says so (W21, with the linking evidences to lift named in the message). But do not over-correct into lifting every sub-conclusion to top level: that trades a wall of disconnected cards for a crowded one (the He extraction did both in one day: first zero top-level evidences, then fifty top-level cards). Author the top tier deliberately, and keep it coarse: the headline, the sinks, the major route hubs, and the shared grounds the burial test already forces up, roughly 15-30 cards on a large map; every statement hub consumed only within its own region lives one fold down, inside that region. If the source draws its own overview map (a section-2 diagram, an abstract’s roadmap), the flat view should be that overview.
The mechanics rest on a folding asymmetry: a statement block folds to nothing, an evidence refinement folds to a visible coarse line with its edges intact (7.5). So an edge between two top-level statements must never sink into a statement block. When all its premises are top-level, the evidence simply stays top-level. When it mixes one cross-region premise with region-local hubs (the shape that otherwise forces those hubs to stay top-level and crowds the tier), write it as a coarse hull: a coarse line conditioning on just the cross-region premise, with the fine conjunction and the local clusters in its refinement (
$takeover-ev @takeover-doom | @unaligned-asiin the He map, fine five-way conjunction one level down). The spine edge stays visible collapsed, the detail unfolds in place, and the solve runs on the fine line while the hull becomes a spectator readout (D38), whose coarse-vs-delivered gap is then an audit of the summary, not an error to tune away.Quick checks:
grep -c '^\$'returning zero on a multi-statement map means no spine at all (W21 fires); a top rank past ~40 cards means the tier is set too fine (nothing fires; this one is on you). The ~40 bound assumes one argument. If the map is an atlas, several blocks with::groups organizing them, read the bound per group: a table of contents is wide on purpose, andnest-auditsays so rather than calling it a crowd. One or two free-standing exhibit nodes beside a visible spine are fine (W21 stays silent then); fifteen are not a view, they are a deck of unshuffled cards.Run
argmap-query nest-auditonce the skeleton stands, and again after any restructuring pass: it counts the top tier for you, names the boxes whose opened view is a wide and deep wall, and lists the statements whose support cone is ready to fold, each with the edges that block the fold (reference inmvp/README.md). It counts a cone by what still stands at the statement’s own tier, so once you fold part of a cone under one of its own members the suggestion goes quiet instead of repeating itself. It is advice, not a check: nothing it prints is a diagnostic, and declining a fold it proposes is a normal outcome.
Sometimes all three tests fail and the heading is still real. That
happens when the section is a topic, not a fold unit: two arguments
that share a file but not a single premise, or a shelf of background
facts. Nesting them under a wrapper evidence would be a lie: there is
no inference there to summarize. That is what a declared group is for
(3.11): write ::id [Label] and indent them under it. The heading stops
being debt and becomes a checked, drawn box, and the validator will tell
you if the topics you claim are separate have quietly grown a shared
premise.
A useful smell figure: the flagship map holds 431 nodes at depth 5. A hundred-node map at depth 1 is under-nested even if every individual line is well-formed; its reader meets a wall of top-level nodes and the fold control does nothing.
9. Limitations
What the format and semantics currently cannot express, with the standing workarounds. None of these block parsing or display; they bound what a solve can mean.
- Scope conditionals (FORMAT_DESIGN Q8). “Aligned in the current
regime, degrades at superhuman scale” has no first-class form.
Marginals capture partial truth, not the conditioning scope; nesting
is a partial workaround whose limits fixture
e06documents. The intended direction (D14) is partitioning statements into substatements; undesigned. Until then, statement granularity is the author’s burden. - Undercut fan-out. An undercut names one target. Class-level methodological objections (“this is all unfalsifiable”) attack a family of inferences and end up structurally under-stated as one representative undercut. Mitigations: give the family a shared gate premise and rebut that once; or make the objection a shared Tier-1 ground feeding several undercuts.
- No statement re-opening (D33). You cannot declare a statement and attach its refinement later in the file; refinement is physical indentation. Workaround: declare nodes at their refinement site and forward-reference them (IDs are document-global).
- Statement-level provenance.
?marks numbers as estimated, but who asserts a claim has no in-format home beyond footnotes and ID prefixes. In multi-source maps this makes scope policing (“does this node belong to this map’s source?”) a manual discipline. - Binary statements only (S8). Categorical or continuous claims must enter through threshold-gate statements (“X exceeds T”).
- Credal links are second-order (S12). Nothing computes “if the
probability of X exceeds t then Y”; the epistemic-fact reification
(7.10) plus a
# gate:comment audit is the pattern. - Facts, norms, and future scenarios mix by convention only (S13). The flagship keeps policy conclusions as “should” statements and has no “will X happen” node whose truth would feed back onto its own antecedents. If you add scenario nodes, index them explicitly or the map becomes self-referential.
- Independence is assumed (P2) and dependence must be authored (4.4). There is no correlation annotation.
- Solver cost grows with treewidth (P5). The corpus solves in seconds at treewidth about 7 to 9; a much more entangled map may not. Width-not-depth authoring also keeps treewidth down.
- Comment-layer slots are conventions.
# check:and# gate:are invisible to tools other than the solver readouts, and nothing validates them structurally. - Cross-map ID reuse is unchecked. Reusing an ID across maps is
string coincidence; verify the propositions match before treating
them as the same claim (a debate’s “prepare an off-button” is weaker
than the book’s
@shutdown). - Authoring cost is real (RISKS §2). Mapping is slower than prose. The mitigations that exist today are LLM extraction with human steering, and the rubric discipline that keeps the numbers honest (RISKS §4); neither removes the labor, they redistribute it toward review.
10. Checking your map
Three mechanical gates, in order: lint, parse, solve.
10.1 The lint
python3 tools/argmap-lint.py path/to/your.argmap
Zero errors is mandatory. The codes (full table in tools/README.md):
| Code | Meaning | Author action |
|---|---|---|
| E1 | duplicate ID (one namespace across @/$) |
rename |
| E2 | dangling reference | fix the ID |
| E3 | ~$id |
rewrite as an undercut (3.6) |
| E4 | probability outside [0,1] | fix |
| E5 | v0.3 pair without argmap-version: 0.3 |
declare the version |
| E6 | malformed pair (0.9/, /0.2) |
write both members |
| E7 | ::id in an expression (3.11) |
a group takes no part in inference; reference a member |
| E8 | a probability on a :: line (3.11) |
groups have no credence slot; delete the number |
| E9 | > outside an annotation block (3.12) |
move the quote under its node, before that node’s first child |
| E10 | > with no quote text |
write the quote or delete the line |
| W1 | evidence-in-premise, not undercut-shaped | usually a polarity slip; legitimate only for deliberate conditioning-on-an-inference (7.8), then say so in a comment |
| W2 | directed cycle | usually fine (mutual rebuttal); check it is not a zero-negation support cycle |
| W3 | prose line resembling a node | you lost a sigil; fix it |
| W4 | footnote used/defined mismatch | fix |
| W5 | evidence label past ~56 chars | distill the warrant; depth to the gloss |
| W7 | pair sums > 1 | declared two-sided conflict or infeasible residual; confirm intended |
| W8 | pair 0/0 |
drop it |
| W9 | pair entangled with undercut shape | check what the opposed side actually asserts |
| W11 | authored 0 strength | you probably mean an unstrengthed line |
| W15 | quote line with no [^locator] (3.12) |
add the locator; provenance is the point |
| W16 | leftover [^ inside quote text (3.12) |
only a trailing ref is the locator; fix the stray or doubled one |
| W17 | ` # ` inside quote text (3.12) | quote lines have no trailing comment; move the note to a #[…] line |
| W18 | quotes before the end of the gloss prose (3.12) | reorder: gloss first, then quotes |
| W19 | > under a declared version below 0.3 |
declare argmap-version: 0.3 |
| W20 | retired ~"…" still in a gloss (3.12) |
migrate it: > line, plain marks, or the echo pattern |
| I1 | stats; isolated statements | connect or delete isolates |
Two caveats: the stranded-node check (W6) lives only in the TypeScript
validator (visible in the editor), not in this lint; and on
expression-valued conclusions (@a OR @b left of the given bar) the
lint’s undercut-shape family (W1/W9 and same-slab W7) deliberately stays
single-ref, so near-misses there are the editor validator’s job (see
tools/README.md, update 2026-07-25).
Warnings are advisory and some are load markers on purpose: the flagship map ships with two deliberate W1s. The discipline is not “zero warnings”; it is “every warning has an explanation you could put in a comment”.
10.2 The parser
Open the file in the editor (or run the parser test suite if you work in
the repo). The editor shows diagnostics inline, including the
validator-only warnings (W6 stranded node, W10 version gate). Without
the editor (a standalone tool bundle), a successful solve_map.py run
doubles as the parse gate: it loads the file through the real parser.
10.3 The solve
cd experiments/solver-prototypes
python3 solve_map.py path/to/your.argmap --top 10
Read the three sections: statement gaps (authored or check value vs solved), evidence tensions (authored strength vs achieved), spectator gaps (coarse summaries vs what their refinements deliver). Then query the nodes you care about, with the forced interval:
python3 solve_map.py path/to/your.argmap @headline '$main-step' --band
(--band needs the optional band_probe.py next to solve_map.py, and
--influence needs influence_probe.py; the plain readout needs
neither.)
Interpreting what you see:
- A large statement gap: the mapped argument does not deliver the authored or checked belief. Revise structure or strengths if the argument is misstated; add named missing evidence if real support is unmapped; otherwise keep the badge, it is a finding.
- A large evidence tension: the constraint set cannot honor that authored strength; look for an overlooked conflict with neighboring lines.
- A spectator gap: the refinement delivers something different from its coarse summary (“steps outrun summaries”, or the reverse at the spine). Decide which side is wrong; both states occur in practice.
- Numbers never move to make badges disappear (5.2.2). Structure moves, named evidence is added, or the badge stays and means something.
The solver needs numpy, scipy, and node. If it is unavailable, lint plus parse still validate everything structural.
For translated maps, python3 tools/translation-parity.py BASE TR
verifies the translation touches only free-text spans.
Appendix A: a complete worked example
The file below is complete and lints clean as shown (zero errors, zero
warnings). It exercises: convergent
routes, a linked conjunction, a refinement with an evidence-side check,
an undercut, a reinstating undercut-of-the-undercut, a rebuttal, check
credences, ? discipline, and a footnote.
---
argmap-version: 0.2
title: "Protected bike lanes and cyclist safety"
description: "AUTHORING_TUTORIAL.md Appendix A: worked example."
date: 2026-07-25
---
# Headline first (convention). Derived statement: no authored marginal,
# a check credence instead (residual authoring rule).
@lanes-safer [Protected lanes reduce cyclist injuries per trip]: the headline claim # check: 0.8
# Route 1: observational. The coarse line refines into the per-trip
# reading; its 0.7? is the evidence-side check against the refinement.
@study-drop [Injury rates fell after protected-lane installation] 0.9?: city-level before/after counts [^lusk]
$obs-route [before/after data carries the claim] 0.7? @lanes-safer | @study-drop: unfolds into the per-trip reading below
@exposure-ok [The drop is not explained by reduced cycling] 0.8?: ridership rose over the same period, so per-trip risk fell
$obs-fine [per-trip injuries fell while ridership rose] 0.8? @lanes-safer | @study-drop AND @exposure-ok: linked - both facts are needed for the per-trip reading
# Route 2: mechanism. Convergent sibling of $obs-route (independent
# routes, so separate lines, not an AND). Independence audited: the
# mechanism does not rest on the before/after data.
@separation [Physical separation removes the main collision type] 0.9?: most serious urban cycling injuries involve motor vehicles
$mech-route [the design removes the dominant injury mechanism] 0.75? @lanes-safer | @separation:
# The objection: grants the data, denies the inference from it
# (an undercut of $obs-route, not a rebuttal of the claim).
@confound [Cities add lanes where cycling is already safest] 0.5?: selection: lanes go where streets are calmest
$uc-obs [selection could explain the before/after drop] 0.6? ~@lanes-safer | @confound AND $obs-route:
# The response: an undercut of the undercut (reinstatement). The
# selection story predicts no drop at quasi-random sites.
@natural-exp [Some installations were sited quasi-randomly] 0.7?: construction-driven and court-ordered sitings
$resp-uc [quasi-random sites show the same drop] 0.8? @lanes-safer | @natural-exp AND $uc-obs:
# A rebuttal (attacks the claim itself, so no $-conjunct).
@risk-comp [Riders take more risks when they feel protected] 0.4?: the risk-compensation hypothesis
$rebut [risk compensation could offset the design gain] 0.3? ~@lanes-safer | @risk-comp:
[^lusk]: Lusk et al., "Risk of injury for bicycling on cycle tracks versus in the street," Injury Prevention 17, 2011.
What to notice:
@lanes-saferis derived, so it carries# check: 0.8and no authored marginal.- Frontier roots (
@study-drop,@separation,@confound, …) keep authored values, all?-marked as estimates. $uc-obsconditions on$obs-route(undercut);$resp-ucconditions on$uc-obs(reinstatement);$rebutconditions on neither (rebuttal).- The refinement under
$obs-routemakes its 0.7? a displayed check against what$obs-finedelivers, and$uc-obsre-aims onto the refinement’s delivery line when unfolded.
The actual solver readout for this file (solve_map.py, D36 defaults, 2026-07-25), abridged:
appendix-a.argmap: 7+5 vars, width=3 | 0.0s, conv=True
largest statement gaps (authored/check -> solved):
@lanes-safer 0.80 -> 0.818 |d|=0.018
@separation 0.90 -> 0.893 |d|=0.007
...
largest spectator gaps (authored coarse ~> delivered by refinement):
$obs-route:delivered-by-refinement p=0.70 ~> q=0.837 |gap|=0.137
Reading it: the check credence 0.8 on the headline is nearly met by the
mapped argument (solved 0.818), so the map delivers the stated belief.
The sub-0.01 gaps on the roots are ridge softness, not tension. The one
real finding is the spectator row: the refinement of $obs-route
delivers 0.837 where the coarse line was authored 0.7, a miniature
“steps outrun summaries”. The honest responses are to accept the
refinement’s number (the coarse 0.7 was too conservative) or to notice a
missing qualifier in the fine model; nothing is tuned silently either
way.
Appendix B: cheat sheet
@id [label] p?: gloss statement; p optional, ? = estimated
$id [label] s? CONCL | PREM: gloss evidence; s optional; | optional
$id s ~@x OR ~@y: gloss premise-less constraint factor
~@id negation (never ~$id: E3)
AND / OR linked / convergent; parens to mix
::id [label]: gloss declared group; no credence, never in an expr
indented node lines under @/$: refinement (replaces parent unfolded)
under ::: membership in the group
indented prose folds into the gloss above
> verbatim text [^locator] quote line; one line, no trailing comment
# comment full-line or trailing
#[key: ...] annotation comment (per-file free in parity)
# check: p display-only credence (derived stmts)
# gate: q($e) >= t => @c threshold audit (comment layer)
[^ref] ... [^ref]: source footnote citation
---: argmap-version: 0.3 required for slash pairs (s+/s-, p+/p-) and > lines
Number rules: elicit as “assume the premises; how likely is the
conclusion?”; ? on rubric-derived values, bare only for source-stated
numbers; derived statements get checks, not pins; no authored 0/1; fix
arguments, not numbers, after the first solve.
Undercut schema: $u q ~C | grounds AND $target. Ask: which inference
does this objection grant, and which does it deny?
Review checklist, one line each: provenance traced; undercut targets typed; overlaps merged/factored/partitioned or declared; no dangling sub-conclusions; clusters nested, shared grounds top-level; full-source coverage pass; lint + parse + solve smoke; defeat presuppositions guarded; multi-voice overlaps deduplicated.
Check: python3 tools/argmap-lint.py FILE, then
cd experiments/solver-prototypes && python3 solve_map.py FILE --top 10.