The Law of Artifacts: Handoffs Are Never Chat
The first mistake most teams make with multiple agents is social. They assume more conversation means more intelligence. In practice, it usually means more compression. The Researcher paraphrases an interview. The Mapper paraphrases the paraphrase. The Critic then reviews a derivative story rather than the thing that actually happened. After three hops, the original evidence is gone. ASD forbids that pattern at the contract level. A role may explain itself in a host interface, but the durable handoff is always a typed artifact written through the store.
This matters because ASD is not a chat choreography layer sitting above a hidden database. It is one canonical practice contract and one runtime registry projected into twelve targets. The CLI, MCP server, coding-agent packs, BUZZ Persona Pack, and DeepSeek Harness Studio all touch the same underlying ideas: 10 roles, 80 shipped skills from 81 sources, 30 sd_* tools, 228 resources, 10 role prompts, 38 registered artifact-kind contracts, 39 vocabulary rows, 7 authored templates, and 12 emitted targets. The human-friendly artifact vocabulary lives in Appendix A. The command and tool surfaces live in Appendix B. In this chapter I stay on the write path itself.
The role contract is deliberately boring. That is a feature. A role runs a registered method, writes the method's declared output kind, and only then can another role consume it. If a handoff needs a condition, ASD records one. If a handoff names an artifact kind, that pointer must resolve inside the same project. No invisible context. No magical side channel. No "trust me, the previous agent covered it."
## 1. Handoffs are artifacts, not chat
1. Role A completes a registered method and writes its declared typed artifact.
2. The Orchestrator presents the gate and records the human decision through asd phase-advance.
3. Role B consumes the artifact; it never reconstructs the work from conversation.
4. Everything shown to a model must be reconstructable from the store.
5. Parallel work is explicit; writes still serialize through the project store.
Once I adopt that rule, the rest of the platform gets sharper. The Researcher does not hand the Mapper a speech about what riders felt. The Researcher hands over an insight-set or a journey-map draft with evidence pointers that can be inspected, reviewed, vetoed, replayed, and exported. The Orchestrator does not quietly decide that the team is ready for the next phase. The Orchestrator prepares the gate record, then a human authorizes it with an approval receipt. Even the Critic does not shout into the void. It writes rows.
| Question | Chat-native answer | ASD answer |
|---|---|---|
| What does one role hand to the next? | A summary in prose. | A typed artifact plus resolvable evidence references. |
| How do I know what the model actually saw? | I usually cannot prove it. | The store, log, artifact, and evidence must tell the same story. |
| How does parallel work stay coherent? | Thread memory and goodwill. | Explicit orchestration plus a single serialized write path. |
| How is a gate crossed? | Someone says we are done. | A human records an approval receipt through asd phase-advance. |
Evidence Registers and Content Addressing
The artifact rule only works because artifacts do not float free. They stand on a register, and the register is closed. ASD allows exactly three evidence kinds: quote, telemetry, and document. That small vocabulary does more work than a bloated ontology ever could. Quotes preserve verbatim human voice. Telemetry preserves measured operational facts. Documents preserve written institutional context: field notes, rosters, policies, notices, screenshots captured into prose, and the dull paperwork that usually kills overconfident ideas.
Each evidence row is content-addressed. The id is the SHA-256 of (source, kind, body). Same source, same kind, same body, same id. Different body, different id. Re-import a transcript twice and you do not get duplicate truth; you get the same row. That property is what lets me cite an evidence id in a journey node, in a Critic defect row, and later in a traceability report without inventing a second naming scheme.
asd evidence-add --projectId lighthouse-transit-f7e5f8a2 --source call-821004 --kind quote --body "Told to wait 15 min for next bus; nobody held the tram."
asd evidence-add --projectId lighthouse-transit-f7e5f8a2 --source avl-extract-2025-11 --kind telemetry --body "Route 41 weekday OTP 71 percent; peak-shoulder misses cluster 16:00-19:00."
asd evidence-add --projectId lighthouse-transit-f7e5f8a2 --source rosters-07 --kind document --body "Eleven routes cannot hold a 3-minute connection under current roster rules."
If I try to smuggle in an observation kind, the CLI rejects it. Good. An observation is not a fourth primitive truth type in ASD. It becomes either a quote or a document, depending on what it actually is. That distinction sounds fussy until the first time somebody tries to promote a designer's interpretation into ground truth. The platform says no before the meeting gets confused.
| Kind | What it captures | Typical service-design use |
|---|---|---|
quote |
Verbatim human words. | Interview lines, complaint excerpts, diary snippets, frontline speech. |
telemetry |
Measured operational or behavioral data. | Queue times, no-show rates, completion rates, usage extracts, ticket volumes. |
document |
Written context and institutional constraints. | Policies, rosters, field notes, consent forms, service standards, notices. |
One more boundary matters here. Appendix A lists the platform's artifact vocabulary and its aliases; the register is not that catalog. Evidence rows are smaller and blunter than artifacts on purpose. I want the raw facts to stay primitive so the design layer above them can be checked mechanically.
Acceptance Rules, Failed Writes, and the Draft Lane
Most systems do something unhelpful at write time. They either accept too much and hope review catches it later, or they reject too hard and leave no record of what almost got in. ASD takes a better path. Every method manifest names an acceptance contract, and failed writes persist as draft with machine-readable failures attached. That means the platform tells the truth twice: it tells the truth that the artifact exists, and it tells the truth that the artifact is not yet good enough.
The acceptance vocabulary is intentionally tiny: min-nodes, min-evidence-per-node, and field-non-empty. Some methods add a narrow extra rule such as forbid-field-values, but the platform's core posture is still compact. A chapter like this one can explain the whole thing because there are not thirty hidden validators. For example, contextual-inquiry demands at least 3 nodes, at least 1 evidence row per node, and a non-empty theme field. transcript-mining tightens the evidence floor to 2 and the node floor to 4. behavioural-personas requires 2 evidence rows per persona, a non-empty goal, and rejects demographic description as a defining basis. The manifest is the contract. The write path enforces it.
{
"accepted": false,
"status": "draft",
"artifact": {
"id": "2f537689386e439abd3ae43769ab710c",
"kind": "journey-map",
"methodId": "journey-from-transcripts",
"status": "draft",
"check": {
"pass": false,
"failures": [
{
"rule": "min-nodes",
"message": "expected at least 3 nodes, found 1"
},
{
"rule": "min-evidence-per-node",
"nodeId": "transfer",
"message": "node \"transfer\" cites 0 evidence refs, needs 1"
},
{
"rule": "field-non-empty",
"nodeId": "transfer",
"message": "node \"transfer\" field \"touchpoint\" must be non-empty"
}
]
}
},
"failures": [
"expected at least 3 nodes, found 1",
"node \"transfer\" cites 0 evidence refs, needs 1",
"node \"transfer\" field \"touchpoint\" must be non-empty"
]
}
The subtle point is the status line. Even a structurally accepted artifact remains draft until the review gate is cleared. So ASD really has three observable moments even though it exposes two statuses: a failed draft, an accepted draft, and a final artifact. That middle state matters. It means the method contract passed, but the Critic has not yet granted promotion.
| Rule | What it protects | Typical failure |
|---|---|---|
min-nodes |
Prevents tiny artifacts from pretending to cover a system. | A journey with one stage, a research plan with one activity, a persona set with one persona. |
min-evidence-per-node |
Prevents unsupported claims inside otherwise well-formed artifacts. | A pain point with zero quotes, a persona defined by one anecdote, a gap row citing nothing. |
field-non-empty |
Prevents placeholder semantics from slipping into delivery. | touchpoint: "", theme: "tbd", lane: "n/a". |
Because the failure report stays attached, remediation gets precise. I do not ask an agent to "improve the journey." I tell it to rewrite artifact 2f537689386e439abd3ae43769ab710c, add evidence to node transfer, fill touchpoint, and bring the node count above the floor. Specificity is the reward for preserving the failure instead of hiding it.
The Critic on the Write Path: Pass, Veto, and review-veto-log
Acceptance is necessary. It is not sufficient. A journey can meet its node floor and still propose a fantasy. A blueprint can cite real evidence and still violate an operational constraint hidden in a document row. That is why ASD makes review a data structure, not an opinion. If a method declares reviewGate: critic, the artifact is only final after asd review returns a valid verdict.
A pass is stricter than people expect. It still needs evidence-cited rows. You do not get to pass with an empty array because "everything looked fine." The minimum honest pass is an evidence-cited proposal row. A veto is stricter still. It needs at least one defect row, and every defect row needs a fix. That is what turns review from hand-waving into an executable remediation loop.
asd review --projectId lighthouse-transit-f7e5f8a2 --artifactId 2f537689386e439abd3ae43769ab710c --verdict veto --rows '[
{
"rowKind": "defect",
"severity": "high",
"rule": "evidence-sufficiency",
"message": "The missed-connection node needs the roster-constraint document cited alongside the rider quotes; without it the 3-minute connection fix looks feasible and is not.",
"fix": "Cite rosters-07 on the transfer node.",
"evidenceId": "ebc691cacc31cf5fb2db2f3c8347e5e085690a0971b0d3ca4d104a6e150fdc6a"
}
]'
{
"id": "a3c09c90fdb24c49be6efd1c1a58ce43",
"kind": "review-veto-log",
"title": "Review: Current-state journey",
"status": "final",
"reviewOf": "2f537689386e439abd3ae43769ab710c",
"nodes": [
{
"id": "r1",
"label": "The missed-connection node needs the roster-constraint document cited first.",
"evidence": [
{
"evidenceId": "ebc691cacc31cf5fb2db2f3c8347e5e085690a0971b0d3ca4d104a6e150fdc6a"
}
],
"fields": {
"rowKind": "defect",
"severity": "high",
"rule": "evidence-sufficiency",
"message": "The missed-connection node needs the roster-constraint document cited alongside the rider quotes; without it the 3-minute connection fix looks feasible and is not.",
"fix": "Cite rosters-07 on the transfer node."
}
}
]
}
This artifact is administrative, and that is an important distinction. A review-veto-log is part of the runtime registry, but it is not one of the flagship fillable templates. It exists because governance itself needs evidence. The Critic's row is not a Slack comment. It is a final artifact linked by reviewOf to the artifact it judged. On a later pass, ASD reuses that same log artifact and appends the new rows so the story stays continuous.
Promotion therefore becomes exact. Failed acceptance yields draft. Accepted write still yields draft. Critic veto yields draft plus a final review-veto-log. Critic pass may promote the artifact to final. Nothing else does.
The Fact-Check Triad and Why CI Trusts Exit Codes
The platform's final mechanical witness is asd factcheck. It replays the project as it exists now, not as it was when a role first wrote an artifact. That distinction matters. A manifest may tighten later. A bad ref may have slipped into an older file. A human may have copied something around the edges. factcheck does not care about excuses. It re-runs three tests for every artifact: integrity, acceptance, and review.
Integrity asks whether every cited evidence id resolves. Acceptance re-runs the method's rules against the live registry. Review checks that any artifact claiming final under a gated method actually carries a pass verdict. Drafts can remain drafts honestly. Failed finals cannot sneak through.
asd factcheck --projectId lighthouse-transit-f7e5f8a2
{
"pass": false,
"rows": [
{
"artifactId": "2f537689386e439abd3ae43769ab710c",
"kind": "journey-map",
"status": "draft",
"integrity": {
"pass": true,
"dangling": []
},
"acceptance": {
"pass": false,
"failures": [
"node \"transfer\" cites 0 evidence refs, needs 1"
]
},
"review": {
"pass": true,
"gate": "critic",
"verdict": null
},
"methodId": "journey-from-transcripts",
"methodResolution": "recorded"
}
]
}
The row tells me exactly why the build is red, but CI does not even need to read the JSON. It reads the exit code. When pass is false, asd factcheck exits 1. That single design choice turns service-design rigor into an enforceable delivery gate. A project cannot talk its way into green. It must satisfy the replay.
This is also where the platform's honesty shows. A draft is allowed to exist. A veto log is allowed to exist. Open work is allowed to exist. What is not allowed is pretending that open work is ready for export, phase movement, or executive reporting. The six report kinds render deterministically, but only from what the store can defend.
Human Phase Gates, Approval Receipts, and the Boundary of Authority
After all that machinery, the most important rule is still human. ASD does not infer approval from a passing artifact. It does not promote a project because the Critic was satisfied. It does not let ACP pretend to authorize work. Only a human phase gate moves the project from discover to define, define to develop, or develop to deliver, and that move must carry an approval receipt.
The receipt is the antidote to fuzzy governance. Somebody approved. Somebody stated a rationale. Somebody put a timestamp on it. The command is idempotent because gates are too serious to duplicate casually.
{
"receiptId": "gate-discover-1",
"decision": "approve",
"rationale": "Discover evidence and synthesis are complete; the open risks are documented for Define.",
"approvedBy": "service-lead",
"approvedAt": "2026-08-22T12:00:00Z"
}
asd phase-advance --projectId lighthouse-transit-f7e5f8a2 --toPhase define --idempotencyKey gate-discover-1 --approvalReceipt '{
"receiptId": "gate-discover-1",
"decision": "approve",
"rationale": "Discover evidence and synthesis are complete; the open risks are documented for Define.",
"approvedBy": "service-lead",
"approvedAt": "2026-08-22T12:00:00Z"
}'
In practice the tool also protects the shape of the gate. The transition must be legal. The receipt must be non-empty and well formed. The project must have at least one design artifact, passing factcheck, and no unresolved Critic veto standing in the way. That is why phase change belongs to the Orchestrator plus a human authority, not to whichever role happens to be loudest. The system can prepare the case; it cannot sign its own release.
This is also the point where ACP's boundary matters. asd-acp/1 is record-only. It can log a human gate, a handoff, an unsupported dispatch, or a Critic veto. It cannot promote a phase by narrative implication. BUZZ messages are not ACP transport. DSH UI events are not ACP transport. A host may present the gate beautifully, but the durable project truth is still the gate record.
Put all of this together and the chapter's thesis becomes simple. Agents can discover, cluster, map, critique, and render. They cannot improvise the evidence, waive the acceptance floor, erase a veto, fake a fact-check, or authorize the next phase. That is why ASD stays useful under pressure. The platform is opinionated about what must be true before design becomes durable, and it keeps those truths inspectable all the way down to the row.