Run Conduct Desk from your own code
Both metered lanes are available over HTTP and each returns one JSON object. The division of labour: the page reads the policy against the standard anatomy, checks the response team, re-ranks the three menus, sets a clock that fits inside the event and lays out the sanctions ladder with its appeal rungs - all free, in conductkit.js. The run writes the audit or the runbook; the page then holds the reply to its own findings (conductreply.js). Not legal advice: anything involving a crime, a minor or an imminent threat goes to emergency services and counsel first.
Base URL and the response shape
Every endpoint lives under https://api.skillsafe.ai/v1/app-api, and every response has one shape:
{ "ok": true, "data": { ... } }
{ "ok": false, "error": { "code": "...", "message": "..." } }
The token is minted for this app (the guest call takes {"slug":"conduct-desk"}), so no slug header is needed afterwards. Send it as Authorization: Bearer YOUR_TOKEN. The run body is the input object, sent bare.
| Status | Code | Meaning |
|---|---|---|
| 400 | validation_error | The body is not a JSON object, or a required key (task, event, roster, policy, facts) is missing. |
| 401 | unauthorized | No token, or a stale one. Mint a guest token or sign in again. |
| 402 | insufficient_credits | The balance is under min_credits. Price with /estimate first. |
| 403 | forbidden | A guest token tried to run: both lanes are metered and need a personal sign-in. |
| 404 | not_found | Unknown job id. |
| 429 | rate_limited | Back off and retry. |
| 5xx | server_error | Transient. Retry with the same Idempotency-Key so a retry never double-bills. |
The task field comes first
Two lanes, chosen by task:
audit- before the policy is published: the verdict, a fix and suggested wording for every policy section, the three picks with their reasons, the clock, the ladder with its appeal rungs, 2 or 3 rehearsal cases, a transparency commitment and the caveats.runbook- for the response team at 2am: safety first, the intake script, the capture fields, recusal, escalation, the decision method with tie and absence rules, the four-part notification, closure, the clock, staff guidance and the contacts - only people on the roster. The page offers it once at least two responders are named.
A missing or unknown task is answered as audit. Both lanes send the same five fields.
The input
| Field | Required | What |
|---|---|---|
task | yes | audit or runbook. If it is missing or neither, do audit and set "task": "audit". |
event | yes | the event's facts from the interview: format, size, dates, who is bound, the organizing model, the power gradient, the publication date, the edition, the effort ceiling, the existing assets, and the card details. |
roster | yes | the response team as entered: name, role, contact, place in the organizing chain, on-site hours and conflict declaration, with the page's tags. |
policy | yes | the code of conduct text; a long one has its middle cut, and the cut is marked. |
facts | yes | the page's verdict, every policy section with its status and excerpt, the team checks, the three menus with their picks, moves and deletions, the clock, the ladder with its appeal flags, the appeal route, and every finding tagged [fix], [check] or [info]. |
retry_note | no | optional; if present, your previous reply was unusable - follow it. |
The rules the model applies
- This is not legal advice. Contract wording - the clause binding a sponsor's staff, the ticket terms carrying the ejection-without-refund right - goes to counsel. Retention, access and deletion of incident records go to whoever holds the privacy obligations. Anything involving a crime, a minor or an imminent physical threat goes to emergency services and counsel first, and to this process second.
- The deliverable is two things, never one: a published policy and a pipeline of named people who can act on a report before the event ends. A code of conduct with no pipeline behind it is worse than none; do not publish until a named team, a working channel and a ladder exist.
- A working policy has a pledge, an enumerated list of prohibited behaviour (offensive comments tied to protected characteristics; sexual or violent imagery and language; intimidation, stalking, following, doxxing; harassing photography or recording; sustained disruption of talks; inappropriate physical contact and unwelcome sexual attention), a subjective backstop, a scope clause naming every role including sponsors and booth staff, every space including online channels, social and unofficial events, the dates, and a stance on conduct outside the event, then where to report, who receives it, and how a reporter physically finds a responder.
- Reporting: a published alias, individual contacts for at least two people with one outside the organizing chain, responders in visually distinctive clothing on any physical day, and an anonymous path promoted whenever there is a power gradient. The confidentiality promise has two parts: reports are confidential, and the reporter's identity stays confidential unless they instruct otherwise.
- The response team is 3-6 named, published people, sized to work with a third unavailable, with conflicts declared (hard: excluded from discussion, vote and confidential material; soft: may discuss, may not vote) and recusal from the moment it applies. A single organizer as sole responder is deleted wherever that organizer is the most senior person. When the most powerful person sits on the organizing team and no independent body exists above them, an external trust-and-safety contractor is the answer. Under a franchise or umbrella agreement, skip drafting: verify the binding document and the central body's public-statement authority. In a peer network each chapter owns its policy.
- Ruled-out options are deleted, never demoted, and every re-ranking names the interview answer that moved it.
- The response clock is published in hours and days and has to fit inside the event. Two published bands: PyCon US (leads meet within 24 hours for non-urgent reports, follow up within one week) and Aurora and Gardiner (24 hours to acknowledgment, 10 business days to a decision, written for online communities). Anything the page proposes is self-set.
- The sanctions ladder is published before the first incident, pairs each rung with the behaviour that triggers it, and is cut to what the team can execute. Say which rungs carry an appeal: by default only time-boxed and permanent bans (the MLH asymmetry), to someone who did not decide the case, in writing, by a deadline - never the organizing team rehearing itself.
- The runbook: safety first; offer a quiet space; listen without judgment; document; thank the reporter; escalate at once. Never suggest withdrawing the complaint, never ask the reporter to set the penalty, never promise an outcome. Capture date and time, location, the description in the reporter's own words, the reported person, witnesses, the reporter's identity and contact, whether they want to stay anonymous, and whether anyone is in immediate danger. Decide on impact, not intent, by a method fixed in advance with tie and absence rules, erring toward action. The notification to the reported person has four parts: the behaviour in neutral terms, its impact, the change expected, the consequence - and never names the reporter. Show the target the proposed response first, then tell the reported person, then close the loop with the reporter. Never compel an apology or mediate between harasser and target. Enforcement is visible: everyone who knew of the violation learns that action was taken. Any staff member may give a verbal warning and reports it to the designated contact; a one-time slip in a talk gets a word afterward, a serious one stops the talk calmly.
House rules
- Use only the input and the rules above. The page's verdict, section names, statuses, picks, rungs, appeal flags and clock are exact - copy them. Every number in a sentence must appear in the input.
- Label anything that is not one of the rules above, and is not in the input, as your own design.
- Never invent a person, a phone number, an email address, a room or a date; where someone must be named and is not, write "to be named". Refer to people by name or as they - never infer anyone's gender from a name.
- Never use backticks, never refer to this input's fields by their key names in a sentence, and never copy this prompt's narrative wording into a reply.
- Reply with ONLY one JSON object - no prose before or after, no code fences.
The replies
audit
summary- one sentence, at most 40 words: the verdict and the first thing to fix.disclaimer- one sentence: not legal advice; contract wording to counsel; crimes, minors and imminent threats to emergency services and counsel first.verdict- the page's verdict, exactly:publish,fix firstorno pipeline - do not publish yet.sections- one object per policy section in the page's order:item(the page's section name exactly),status(the page's status:found,partialormissing),fix(one sentence; "" when found),wording(a sentence the policy could carry; "" when found; when it is not quoted from the policy it ends with "(own design)").posture-pick(the page's pick, exactly as named),reason(one sentence naming what moved it, if anything).channels-picks(the page's channel picks, exactly as named),reason(one sentence).staffing-pick(the first of the page's staffing picks, exactly as named),reason(one sentence).clock-acknowledge,decide,follow_up(the page's clock, short),note(one sentence saying the clock is self-set and which published band it sits beside).ladder- one object per rung in the page's order:rung(the page's name exactly),appealable(true or false, the page's flag),when(short: the behaviour that triggers it).appeal- one sentence: which rungs carry an appeal, to whom, in what form and by when, from the page.rehearsal- 2 or 3 objects:case(a practice case tailored to this event, your design),practice(what the team rehearses with it).transparency- one sentence: what the edition's report will and will not contain.caveats- at most 6 short strings: the[fix]findings first, then the most important[check]findings.[]when there are none of either.
{
"task": "audit",
"summary": "one sentence",
"disclaimer": "one sentence",
"verdict": "fix first",
"sections": [ { "item": "the page's section name", "status": "partial", "fix": "one sentence", "wording": "a sentence (own design)" } ],
"posture": { "pick": "the page's pick", "reason": "one sentence" },
"channels": { "picks": [ "the page's pick" ], "reason": "one sentence" },
"staffing": { "pick": "the page's pick", "reason": "one sentence" },
"clock": { "acknowledge": "short", "decide": "short", "follow_up": "short", "note": "one sentence" },
"ladder": [ { "rung": "the page's rung", "appealable": false, "when": "short" } ],
"appeal": "one sentence",
"rehearsal": [ { "case": "a practice case", "practice": "what the team rehearses" } ],
"transparency": "one sentence",
"caveats": [ "a caveat" ]
}
The page holds it to its own findings: the verdict, every section in order with its status and a fix wherever it is not found, wording not taken from the policy labelled as the reply's own design, the three picks (never a deleted option), every rung with its appeal flag, the acknowledgment window, 2 or 3 rehearsal cases, and no number, address or phone number the input does not hold.
runbook
title- a short title naming the event.disclaimer- one sentence: not legal advice; crimes, minors and imminent threats go to emergency services and counsel first.safety- 2 to 4 short imperative steps: assess danger first and route it to emergency services or venue security, using the local emergency number when the input gives one.intake- 4 to 8 short steps in order, from the quiet space (name the room when the input gives one) to escalating to the leads.never- 2 to 4 short strings: what a responder never does at intake.capture- the fields to write down, one short string each: date and time, location, the description in the reporter's own words, the reported person, witnesses, the reporter's identity and contact, whether they want to stay anonymous, whether anyone is in immediate danger.recusal- one or two sentences: hard and soft conflicts, who executes the recusal, and any pre-declared recusal the roster shows.escalation- 2 to 4 short steps: who is called, in what order, and where a report about a team member goes.decision-method(who decides and how, erring toward action),tie(the tie rule),absence(the absence rule) - your design where the input is silent, labelled as such.notification- exactly 4 short strings in order: the behaviour, its impact, the change expected, the consequence.closure- 2 to 4 short steps: show the target first, notify, close the loop with the reporter, record the case.clock- 3 or 4 objects:step,deadline- the page's clock.staff- 2 to 4 short strings for every staff member: verbal warnings, talks, reporting each warning.contacts- one object per roster member, in roster order:name(exactly as entered),role,contact(from the roster, or ""),when(their on-site hours).note- one sentence, at most 30 words, for the organizers: what to fill in or rehearse before printing.
{
"task": "runbook",
"title": "Incident runbook - an event",
"disclaimer": "one sentence",
"safety": [ "a step" ],
"intake": [ "a step" ],
"never": [ "a prohibition" ],
"capture": [ "a field" ],
"recusal": "one or two sentences",
"escalation": [ "a step" ],
"decision": { "method": "one sentence", "tie": "one sentence", "absence": "one sentence" },
"notification": [ "the behaviour", "the impact", "the change", "the consequence" ],
"closure": [ "a step" ],
"clock": [ { "step": "acknowledge", "deadline": "the page's window" } ],
"staff": [ "a guideline" ],
"contacts": [ { "name": "a roster name", "role": "their role", "contact": "their contact", "when": "their hours" } ],
"note": "one sentence"
}
The page requires safety routed to emergency services or security, the eight capture fields, a recusal rule, a decision method with tie and absence rules, exactly four notification parts, the page's acknowledgment window, the quiet room when one is given, and a contact entry for every roster member and nobody else - with no contact the roster does not hold.
Worked examples - every lane, every sample
These are the page's three free samples (fictional events and people). Each input is exactly what the page sends; each reply is the saved reply the sample replays, shipped unedited; the last line is the page's own check.
Harbourline DevConf (300, a template with a placeholder) - audit
Verdict: no pipeline - do not publish yet; 6 of 18 policy sections found; a team of 2; 10 fix-level findings.
Input:
{
"task": "audit",
"event": "Event: Harbourline DevConf; a multi-day conference; headcount 300; 2027-04-15 to 2027-04-16 (2 days); 1 venue\nBound beyond ticket-holders (Q2): speakers, volunteers, sponsor and booth staff, an online chat before and after\nOrganizing model (Q3): a single organizing entity\nPower gradient (Q4): no\nPublication (Q5): 2027-01-15, fixed by ticket sales opening; edition (Q6): annual, the team keeps running it\nEffort ceiling (Q7): someone staffs a channel live during the event yes; budget for external help no\nExisting assets (Q8): none\nCard details: alias not given; phone not given; responder identifier not given; anonymous path not given; quiet room not given; local emergency number not given",
"roster": "Response team (2), as entered - name | role | contact | chain | on-site hours | conflict declaration:\nPriya Raman | conference chair | priya@harbourline.dev | inside the organizing chain | 08:00-19:00 both days | conflict: none (none) [most senior]\nTom Okafor | volunteer lead | no contact | inside the organizing chain | 09:00-17:00 both days | conflict: not declared (undeclared)",
"policy": "Harbourline DevConf Code of Conduct\n\nAll attendees, speakers and volunteers at our conference are required to agree with the following code of conduct. Organisers will enforce this code throughout the event. We expect cooperation from all participants to help ensure a safe environment for everybody.\n\nNeed help? Contact us at [email address].\n\nThe Quick Version\nOur conference is dedicated to providing a harassment-free conference experience for everyone, regardless of gender, gender identity and expression, age, sexual orientation, disability, physical appearance, body size, race, ethnicity, religion (or lack thereof), or technology choices. We do not tolerate harassment of conference participants in any form. Sexual language and imagery is not appropriate for any conference venue, including talks, workshops, parties, Twitter and other online media. Conference participants violating these rules may be sanctioned or expelled from the conference without a refund at the discretion of the conference organisers.\n\nThe Less Quick Version\nHarassment includes offensive verbal comments related to gender, gender identity and expression, age, sexual orientation, disability, physical appearance, body size, race, ethnicity, religion, technology choices, sexual images in public spaces, deliberate intimidation, stalking, following, harassing photography or recording, sustained disruption of talks or other events, inappropriate physical contact, and unwelcome sexual attention.\nParticipants asked to stop any harassing behavior are expected to comply immediately.\nIf a participant engages in harassing behavior, the conference organisers may take any action they deem appropriate, including warning the offender or expulsion from the conference with no refund.\nIf you are being harassed, notice that someone else is being harassed, or have any other concerns, please contact a member of conference staff immediately.\nConference staff will be happy to help participants contact hotel/venue security or local law enforcement, provide escorts, or otherwise assist those experiencing harassment to feel safe for the duration of the conference. We value your attendance.\nWe expect participants to follow these rules at conference and workshop venues and conference-related social events.\n\nThis policy is adapted from confcodeofconduct.com and licensed under a Creative Commons Attribution 3.0 Unported License.",
"facts": "Verdict: no pipeline - do not publish yet (pipeline - named team yes, working channel no, published ladder yes)\nPolicy text: 2,411 characters; template signature phrases 5 of 6 (adopted nearly verbatim)\nAnatomy (6 of 18 found, in order):\n1. Pledge - a harassment-free event, and for whom: FOUND - \"Our conference is dedicated to providing a harassment-free conference experience for everyone, regardless of gender, gender identity and expression, age, sexual orientation, disability, physical...\"\n2. Prohibited behaviour, enumerated: FOUND - \"We do not tolerate harassment of conference participants in any form.\"\n3. Scope - which people (sponsors and booth staff by name): PARTIAL - \"All attendees, speakers and volunteers at our conference are required to agree with the following code of conduct.\" - Sponsors and booth staff are not named - every sourced event policy names them.\n4. Scope - which spaces (venue, online, social, unofficial): FOUND - \"Sexual language and imagery is not appropriate for any conference venue, including talks, workshops, parties, Twitter and other online media.\"\n5. Scope - which dates: PARTIAL - \"Organisers will enforce this code throughout the event.\" - The chat runs before and after doors - say whether that whole window is in scope.\n6. Scope - conduct outside the event: MISSING - Take a position on conduct outside the event - the practitioner stance acts inside your spaces on evidence from outside them.\n7. Reporting channel - a working alias or line: MISSING - \"Contact us at [email address].\" - The reporting sentence carries a placeholder, not a working address.\n8. Named individual contacts (a path for a report about the team): MISSING - Publish individual contacts for at least two people, one of them outside the organizing chain.\n9. An anonymous intake path: MISSING - No anonymous path - the reports the other channels never receive.\n10. How to find a responder on site: MISSING - Say how a reporter physically finds a responder - distinctive clothing, named in the opening announcement.\n11. Two-part confidentiality - the report, and the reporter's identity: MISSING - Promise both: reports are confidential, and the reporter's identity stays confidential unless they say otherwise.\n12. A published response clock, in hours and days: MISSING - No response clock - set one in hours and days and publish it.\n13. The sanctions, listed: FOUND - \"Conference participants violating these rules may be sanctioned or expelled from the conference without a refund at the discretion of the conference organisers.\"\n14. Which rungs carry an appeal: MISSING - No appeal route - decide which rungs carry one and say so.\n15. A transparency report for the edition: MISSING - Commit to a report per edition: counts per rung, time to acknowledgment and outcome, no identities.\n16. Template leftovers removed: MISSING - \"leftover: [email address]\" - Replace every placeholder and template note with this event's own names and contacts.\n17. Attribution and licence line: FOUND - \"This policy is adapted from confcodeofconduct.com and licensed under a Creative Commons Attribution 3.0 Unported License.\"\n18. Help on offer - security, law enforcement, escorts: FOUND - \"Conference staff will be happy to help participants contact hotel/venue security or local law enforcement, provide escorts, or otherwise assist those experiencing harassment to feel safe for the...\"\nTeam checks: A team of 3-6 that survives a third away MISSING; No single organizer as sole responder ok; Individual contacts for at least two members MISSING; At least one member outside the organizing chain MISSING; Every member's place in the chain stated ok; Every member's conflict declaration recorded MISSING; On-site hours for every member ok; Responders a reporter can see MISSING; Someone staffs a channel live during the event ok\nMenu 1 - Base-text posture (pick: Adapt an established text): 1. Adapt an established text; 2. Adopt one verbatim; 3. Adapt plus a culture preamble. Deleted, not demoted: Write your own from scratch (no in-house counsel (Q8) - a from-scratch draft spends a week arriving at the shared list minus whatever it forgets)\nMenu 2 - Reporting channels (pick: Published email alias + Anonymous intake path + Physically identifiable on-site responders + Named conflict-of-interest alternates): 1. Published email alias; 2. Anonymous intake path [moved by: a power gradient: sponsor booth staff answer to a sponsor (Q2); the response team includes the most senior organizer, Priya Raman]; 3. Physically identifiable on-site responders; 4. Named conflict-of-interest alternates. Deleted, not demoted: Staffed phone or SMS hotline (no budget for outside help and no phone line given (Q7) - nobody can staff it)\nMenu 3 - Response-team staffing (pick: A named, published team of 3-6): 1. A named, published team of 3-6. Deleted, not demoted: Route into an umbrella body's incidents team (no umbrella body with its own incidents team (Q3, Q8)); An external trust-and-safety contractor (no budget for external help (Q7)); A single named organizer as sole responder (the sole organizer is the most senior person on the team, so the channel cannot receive the one report most likely to need it)\nClock (self-set): immediately, for anything urgent or ongoing - safety first; acknowledge within 1 hour while the event is running, within 24 hours before and after it; the leads meet within 24 hours, and before the event closes for anything reported on its last day; the reporter hears the outcome within 7 days (one week); the event runs 2 days. Bands: PyCon US (the leads meet within 24 hours for non-urgent reports and follow up with the reporter within one week) fits - a 24-hour meeting lands inside a 2-day event; Aurora and Gardiner (24 hours to acknowledgment and 10 business days to a decision, written for online communities) does not fit - 10 business days runs past a 2-day event. Stated in the policy: none\nLadder (7 rungs, in order): 1. Warning - appeal no - inappropriate or unwelcome behaviour, a first instance - any staff member may give one; 2. Separation requirement - no contact with the reporter for the rest of the event - appeal no - behaviour aimed at one person; an interim measure alongside another response, never the whole response; 3. Removal of volunteer or staff privileges - appeal no - a volunteer or staff member breaks the policy; 4. Revocation of speaker privileges - appeal no - a talk or a speaker breaks the policy - the rung a conference specifically needs; 5. Ejection from the event, without refund - appeal no - a serious single offence, continuing after being told to stop, or repeated warnings; 6. Ban from future editions, time-boxed - appeal yes - a serious violation or a pattern; the notice states the duration; 7. Permanent ban - appeal yes - a pattern of violation, sustained harassment, or aggression. Outside the ladder: no violation found.\nAppeal route: Ban from future editions, time-boxed and Permanent ban; to a named person outside the response team who did not decide the original case (to be named) - never the organizing team rehearing itself; in writing, by email with [Appeal] in the subject line and the evidence attached; within 14 days of the written notice (self-set)\nPass threshold (self-set): every report acknowledged inside the published window, and every reporter told the outcome before the published follow-up deadline. Rehearse 2 or 3 practice cases before doors open.\nFindings (27):\n[fix] size (team): A team of 2 cannot lose a third (1) and still have the two people a decision needs - name 3 to 6.\n[fix] contacts (team): 1 member with a published contact - publish individual contacts for at least two, so a report about one member has somewhere else to go.\n[fix] outside (team): Nobody sits outside the organizing chain - a report about the team itself has nowhere to go.\n[fix] p_people (policy): Scope - which people (sponsors and booth staff by name): Sponsors and booth staff are not named - every sourced event policy names them.\n[fix] p_channel (policy): Reporting channel - a working alias or line: The reporting sentence carries a placeholder, not a working address.\n[fix] p_contacts (policy): Named individual contacts (a path for a report about the team): Publish individual contacts for at least two people, one of them outside the organizing chain.\n[fix] p_anonymous (policy): An anonymous intake path: a power gradient promotes it - sponsor booth staff answer to a sponsor (Q2).\n[fix] p_confidential (policy): Two-part confidentiality - the report, and the reporter's identity: Promise both: reports are confidential, and the reporter's identity stays confidential unless they say otherwise.\n[fix] p_clock (policy): A published response clock, in hours and days: No response clock - set one in hours and days and publish it.\n[fix] p_template (policy): Template leftovers removed: Replace every placeholder and template note with this event's own names and contacts.\n[check] sponsor_clause (event): Sponsor and booth staff are bound by a contract their employer signed, not a ticket: confirm the sponsor agreement carries the compliance clause and the ejection-without-refund right - wording to counsel.\n[check] declared (team): Tom Okafor has no conflict declaration - every member declares one, none counts, before the event.\n[check] visible (team): A physical day needs responders in visually distinctive clothing - name the identifier and say it in the opening announcement.\n[check] p_dates (policy): Scope - which dates: The chat runs before and after doors - say whether that whole window is in scope.\n[check] p_offsite (policy): Scope - conduct outside the event: Take a position on conduct outside the event - the practitioner stance acts inside your spaces on evidence from outside them.\n[check] p_responders (policy): How to find a responder on site: Say how a reporter physically finds a responder - distinctive clothing, named in the opening announcement.\n[check] p_appeals (policy): Which rungs carry an appeal: No appeal route - decide which rungs carry one and say so.\n[check] p_transparency (policy): A transparency report for the edition: Commit to a report per edition: counts per rung, time to acknowledgment and outcome, no identities.\n[info] hard_date (event): A hard publication date (fixed by ticket sales opening) promotes the rungs that stand up in an afternoon and compresses the drafting.\n[info] not_legal (event): Not legal advice: contract wording goes to counsel; retention, access and deletion of incident records to whoever holds the privacy obligations; anything involving a crime, a minor or an imminent physical threat goes to emergency services and counsel first, this process second.\n[info] backstop (policy): No subjective backstop - a catch-all means a report does not have to match a named category to count.\n[info] booth (policy): No booth-staff clause - booth staff, volunteers included, do not use sexualised clothing, uniforms, costumes or environments.\n[info] transport (policy): Transport is not named - a shuttle is neither the venue nor a social event.\n[info] verbatim (policy): This reads as a template adopted nearly verbatim - it names roles and contacts that do not exist at your event.\n[info] clock (clock): Proposed clock (self-set, between the two published bands): immediately, for anything urgent or ongoing - safety first; acknowledge within 1 hour while the event is running, within 24 hours before and after it; the leads meet within 24 hours, and before the event closes for anything reported on its last day; the reporter hears the outcome within 7 days (one week).\n[info] appeal_asym (ladder): Appeals follow the MLH asymmetry: only ban from future editions, time-boxed and permanent ban carry one; the lighter rungs are over before an appeal could be heard.\n[info] records (ladder): Keep every sanction with its rung and reason across editions - a repeat offence moves up the ladder only when someone can see it is a repeat."
}
Reply:
{
"task": "audit",
"summary": "No pipeline yet: the reporting sentence still says [email address], so publish nothing until a working alias, a team of at least 3 with someone outside the organizing chain, and a stated clock exist.",
"disclaimer": "This is not legal advice: sponsor-contract and ticket-term wording goes to counsel, and anything involving a crime, a minor or an imminent threat goes to emergency services and counsel first.",
"verdict": "no pipeline - do not publish yet",
"sections": [
{
"item": "Pledge - a harassment-free event, and for whom",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Prohibited behaviour, enumerated",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Scope - which people (sponsors and booth staff by name)",
"status": "partial",
"fix": "Name sponsors, exhibitors and booth staff alongside attendees, speakers and volunteers - they are bound through the sponsor contract, not a ticket.",
"wording": "This code of conduct applies to all attendees, speakers, volunteers, sponsors, exhibitors and booth staff, organizers and contractors at Harbourline DevConf. (own design)"
},
{
"item": "Scope - which spaces (venue, online, social, unofficial)",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Scope - which dates",
"status": "partial",
"fix": "The online chat runs before and after doors, so say whether that whole window is in scope, not only the two event days.",
"wording": "It covers the event chat from the day it opens until it closes after the conference, as well as 2027-04-15 and 2027-04-16 at the venue. (own design)"
},
{
"item": "Scope - conduct outside the event",
"status": "missing",
"fix": "Take a position: the team acts inside its own spaces on evidence of conduct elsewhere, without claiming jurisdiction over it.",
"wording": "We do not police conduct outside the conference, but we may act inside our spaces - including declining a speaking slot - on evidence of it. (own design)"
},
{
"item": "Reporting channel - a working alias or line",
"status": "missing",
"fix": "Replace the placeholder with a real alias that the response team reads during and between the event days.",
"wording": "To report, email the conduct alias (to be named) or find a responder on site. (own design)"
},
{
"item": "Named individual contacts (a path for a report about the team)",
"status": "missing",
"fix": "Publish individual contacts for at least two people, one of them outside the organizing chain, so a report about the team still has somewhere to go.",
"wording": "You can also contact Priya Raman (priya@harbourline.dev) or our independent alternate (to be named) directly. (own design)"
},
{
"item": "An anonymous intake path",
"status": "missing",
"fix": "Sponsor booth staff answer to a sponsor and the chair sits on the response team, so add an anonymous path and write its decision rules before the first report.",
"wording": "You can report anonymously through the form linked here (to be named); anonymous reports are read by the full team. (own design)"
},
{
"item": "How to find a responder on site",
"status": "missing",
"fix": "Put responders in distinctive clothing and say so in the policy and the opening announcement.",
"wording": "Responders wear (identifier to be named) and are introduced at the opening session. (own design)"
},
{
"item": "Two-part confidentiality - the report, and the reporter's identity",
"status": "missing",
"fix": "Promise both parts: the report is confidential, and so is the reporter's identity unless they say otherwise.",
"wording": "Reports are handled confidentially, and we never share who made a report without that person's permission. (own design)"
},
{
"item": "A published response clock, in hours and days",
"status": "missing",
"fix": "Publish the page's clock so reporters know when to expect an answer, and meet it.",
"wording": "We acknowledge every report within 1 hour during the conference and within 24 hours otherwise, and tell the reporter the outcome within one week. (own design)"
},
{
"item": "The sanctions, listed",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Which rungs carry an appeal",
"status": "missing",
"fix": "Say that only the time-boxed and permanent bans carry an appeal, to whom, in what form and by when.",
"wording": "Only a ban from future editions can be appealed, in writing with [Appeal] in the subject line and evidence attached, within 14 days of the notice, to a reviewer who did not decide the case. (own design)"
},
{
"item": "A transparency report for the edition",
"status": "missing",
"fix": "Commit now to a report after the event, decided before any incident.",
"wording": "After each edition we publish the number of reports, the outcomes by rung and our response times - never names or incident details. (own design)"
},
{
"item": "Template leftovers removed",
"status": "missing",
"fix": "Remove the [email address] placeholder and rename every role to a title someone actually holds at this event.",
"wording": ""
},
{
"item": "Attribution and licence line",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Help on offer - security, law enforcement, escorts",
"status": "found",
"fix": "",
"wording": ""
}
],
"posture": {
"pick": "Adapt an established text",
"reason": "The current text is the template adopted nearly verbatim; adapting it costs an hour or two and replaces the roles and contacts that do not exist here, and the hard date set by ticket sales opening rules out a slower posture."
},
"channels": {
"picks": [
"Published email alias",
"Anonymous intake path",
"Physically identifiable on-site responders",
"Named conflict-of-interest alternates"
],
"reason": "The anonymous path moved up because sponsor booth staff answer to a sponsor and the chair is on the response team; the hotline is deleted because there is no budget and no line to staff."
},
"staffing": {
"pick": "A named, published team of 3-6",
"reason": "With no umbrella body and no budget for a contractor, a named team is the only rung left - and a team of 2 has to grow to at least 3, one of them outside the organizing chain."
},
"clock": {
"acknowledge": "within 1 hour while the event is running, within 24 hours before and after it",
"decide": "the leads meet within 24 hours, and before the event closes for anything reported on its last day",
"follow_up": "the reporter hears the outcome within 7 days (one week)",
"note": "This clock is self-set and sits beside the PyCon US band, which fits inside a 2-day event; the 10-business-day band does not."
},
"ladder": [
{
"rung": "Warning",
"appealable": false,
"when": "inappropriate or unwelcome behaviour, a first instance"
},
{
"rung": "Separation requirement - no contact with the reporter for the rest of the event",
"appealable": false,
"when": "behaviour aimed at one person, alongside another response"
},
{
"rung": "Removal of volunteer or staff privileges",
"appealable": false,
"when": "a volunteer or staff member breaks the policy"
},
{
"rung": "Revocation of speaker privileges",
"appealable": false,
"when": "a talk or a speaker breaks the policy"
},
{
"rung": "Ejection from the event, without refund",
"appealable": false,
"when": "a serious single offence or continuing after being told to stop"
},
{
"rung": "Ban from future editions, time-boxed",
"appealable": true,
"when": "a serious violation or a pattern, with the duration stated"
},
{
"rung": "Permanent ban",
"appealable": true,
"when": "a pattern of violation, sustained harassment, or aggression"
}
],
"appeal": "Only the time-boxed and permanent bans carry an appeal: in writing, by email with [Appeal] in the subject line and the evidence attached, within 14 days of the written notice, to a named person outside the response team who did not decide the case (to be named).",
"rehearsal": [
{
"case": "During the evening social, an attendee tells Tom Okafor that a sponsor's booth staffer has been photographing them after being asked to stop.",
"practice": "Intake in a quiet space, the capture fields, escalating to the leads, and checking the sponsor contract before deciding on ejection."
},
{
"case": "A message in the event chat two weeks before doors reports a speaker for repeated unwelcome comments in that chat.",
"practice": "Deciding whether the pre-event chat is in scope, acknowledging inside the published window, and whether speaker privileges are at stake."
},
{
"case": "An attendee reports Priya Raman, the conference chair, to a volunteer on day 2.",
"practice": "Recusal of the chair from the case, routing to the outside alternate, and keeping the reporter's identity confidential."
}
],
"transparency": "After the edition, publish the number of reports, how many reached each rung, and the median time to acknowledgment and to outcome against the published clock - no names and no incident narratives.",
"caveats": [
"Replace the [email address] placeholder with a working alias before anything is published.",
"Grow the team from 2 to at least 3, with individual contacts and one person outside the organizing chain.",
"Name sponsors and booth staff in the scope clause, and confirm the sponsor contract carries the ejection-without-refund right (counsel).",
"Add the two-part confidentiality promise and the published response clock.",
"Add an anonymous intake path and write its decision rules before the first report.",
"Tom Okafor has no conflict declaration and no contact on the roster - record both before the event."
]
}
The page's check: kept - nothing to flag
Harbourline DevConf (300, a template with a placeholder) - runbook
Verdict: no pipeline - do not publish yet; 6 of 18 policy sections found; a team of 2; 10 fix-level findings.
Input:
{
"task": "runbook",
"event": "Event: Harbourline DevConf; a multi-day conference; headcount 300; 2027-04-15 to 2027-04-16 (2 days); 1 venue\nBound beyond ticket-holders (Q2): speakers, volunteers, sponsor and booth staff, an online chat before and after\nOrganizing model (Q3): a single organizing entity\nPower gradient (Q4): no\nPublication (Q5): 2027-01-15, fixed by ticket sales opening; edition (Q6): annual, the team keeps running it\nEffort ceiling (Q7): someone staffs a channel live during the event yes; budget for external help no\nExisting assets (Q8): none\nCard details: alias not given; phone not given; responder identifier not given; anonymous path not given; quiet room not given; local emergency number not given",
"roster": "Response team (2), as entered - name | role | contact | chain | on-site hours | conflict declaration:\nPriya Raman | conference chair | priya@harbourline.dev | inside the organizing chain | 08:00-19:00 both days | conflict: none (none) [most senior]\nTom Okafor | volunteer lead | no contact | inside the organizing chain | 09:00-17:00 both days | conflict: not declared (undeclared)",
"policy": "Harbourline DevConf Code of Conduct\n\nAll attendees, speakers and volunteers at our conference are required to agree with the following code of conduct. Organisers will enforce this code throughout the event. We expect cooperation from all participants to help ensure a safe environment for everybody.\n\nNeed help? Contact us at [email address].\n\nThe Quick Version\nOur conference is dedicated to providing a harassment-free conference experience for everyone, regardless of gender, gender identity and expression, age, sexual orientation, disability, physical appearance, body size, race, ethnicity, religion (or lack thereof), or technology choices. We do not tolerate harassment of conference participants in any form. Sexual language and imagery is not appropriate for any conference venue, including talks, workshops, parties, Twitter and other online media. Conference participants violating these rules may be sanctioned or expelled from the conference without a refund at the discretion of the conference organisers.\n\nThe Less Quick Version\nHarassment includes offensive verbal comments related to gender, gender identity and expression, age, sexual orientation, disability, physical appearance, body size, race, ethnicity, religion, technology choices, sexual images in public spaces, deliberate intimidation, stalking, following, harassing photography or recording, sustained disruption of talks or other events, inappropriate physical contact, and unwelcome sexual attention.\nParticipants asked to stop any harassing behavior are expected to comply immediately.\nIf a participant engages in harassing behavior, the conference organisers may take any action they deem appropriate, including warning the offender or expulsion from the conference with no refund.\nIf you are being harassed, notice that someone else is being harassed, or have any other concerns, please contact a member of conference staff immediately.\nConference staff will be happy to help participants contact hotel/venue security or local law enforcement, provide escorts, or otherwise assist those experiencing harassment to feel safe for the duration of the conference. We value your attendance.\nWe expect participants to follow these rules at conference and workshop venues and conference-related social events.\n\nThis policy is adapted from confcodeofconduct.com and licensed under a Creative Commons Attribution 3.0 Unported License.",
"facts": "Verdict: no pipeline - do not publish yet (pipeline - named team yes, working channel no, published ladder yes)\nPolicy text: 2,411 characters; template signature phrases 5 of 6 (adopted nearly verbatim)\nAnatomy (6 of 18 found, in order):\n1. Pledge - a harassment-free event, and for whom: FOUND - \"Our conference is dedicated to providing a harassment-free conference experience for everyone, regardless of gender, gender identity and expression, age, sexual orientation, disability, physical...\"\n2. Prohibited behaviour, enumerated: FOUND - \"We do not tolerate harassment of conference participants in any form.\"\n3. Scope - which people (sponsors and booth staff by name): PARTIAL - \"All attendees, speakers and volunteers at our conference are required to agree with the following code of conduct.\" - Sponsors and booth staff are not named - every sourced event policy names them.\n4. Scope - which spaces (venue, online, social, unofficial): FOUND - \"Sexual language and imagery is not appropriate for any conference venue, including talks, workshops, parties, Twitter and other online media.\"\n5. Scope - which dates: PARTIAL - \"Organisers will enforce this code throughout the event.\" - The chat runs before and after doors - say whether that whole window is in scope.\n6. Scope - conduct outside the event: MISSING - Take a position on conduct outside the event - the practitioner stance acts inside your spaces on evidence from outside them.\n7. Reporting channel - a working alias or line: MISSING - \"Contact us at [email address].\" - The reporting sentence carries a placeholder, not a working address.\n8. Named individual contacts (a path for a report about the team): MISSING - Publish individual contacts for at least two people, one of them outside the organizing chain.\n9. An anonymous intake path: MISSING - No anonymous path - the reports the other channels never receive.\n10. How to find a responder on site: MISSING - Say how a reporter physically finds a responder - distinctive clothing, named in the opening announcement.\n11. Two-part confidentiality - the report, and the reporter's identity: MISSING - Promise both: reports are confidential, and the reporter's identity stays confidential unless they say otherwise.\n12. A published response clock, in hours and days: MISSING - No response clock - set one in hours and days and publish it.\n13. The sanctions, listed: FOUND - \"Conference participants violating these rules may be sanctioned or expelled from the conference without a refund at the discretion of the conference organisers.\"\n14. Which rungs carry an appeal: MISSING - No appeal route - decide which rungs carry one and say so.\n15. A transparency report for the edition: MISSING - Commit to a report per edition: counts per rung, time to acknowledgment and outcome, no identities.\n16. Template leftovers removed: MISSING - \"leftover: [email address]\" - Replace every placeholder and template note with this event's own names and contacts.\n17. Attribution and licence line: FOUND - \"This policy is adapted from confcodeofconduct.com and licensed under a Creative Commons Attribution 3.0 Unported License.\"\n18. Help on offer - security, law enforcement, escorts: FOUND - \"Conference staff will be happy to help participants contact hotel/venue security or local law enforcement, provide escorts, or otherwise assist those experiencing harassment to feel safe for the...\"\nTeam checks: A team of 3-6 that survives a third away MISSING; No single organizer as sole responder ok; Individual contacts for at least two members MISSING; At least one member outside the organizing chain MISSING; Every member's place in the chain stated ok; Every member's conflict declaration recorded MISSING; On-site hours for every member ok; Responders a reporter can see MISSING; Someone staffs a channel live during the event ok\nMenu 1 - Base-text posture (pick: Adapt an established text): 1. Adapt an established text; 2. Adopt one verbatim; 3. Adapt plus a culture preamble. Deleted, not demoted: Write your own from scratch (no in-house counsel (Q8) - a from-scratch draft spends a week arriving at the shared list minus whatever it forgets)\nMenu 2 - Reporting channels (pick: Published email alias + Anonymous intake path + Physically identifiable on-site responders + Named conflict-of-interest alternates): 1. Published email alias; 2. Anonymous intake path [moved by: a power gradient: sponsor booth staff answer to a sponsor (Q2); the response team includes the most senior organizer, Priya Raman]; 3. Physically identifiable on-site responders; 4. Named conflict-of-interest alternates. Deleted, not demoted: Staffed phone or SMS hotline (no budget for outside help and no phone line given (Q7) - nobody can staff it)\nMenu 3 - Response-team staffing (pick: A named, published team of 3-6): 1. A named, published team of 3-6. Deleted, not demoted: Route into an umbrella body's incidents team (no umbrella body with its own incidents team (Q3, Q8)); An external trust-and-safety contractor (no budget for external help (Q7)); A single named organizer as sole responder (the sole organizer is the most senior person on the team, so the channel cannot receive the one report most likely to need it)\nClock (self-set): immediately, for anything urgent or ongoing - safety first; acknowledge within 1 hour while the event is running, within 24 hours before and after it; the leads meet within 24 hours, and before the event closes for anything reported on its last day; the reporter hears the outcome within 7 days (one week); the event runs 2 days. Bands: PyCon US (the leads meet within 24 hours for non-urgent reports and follow up with the reporter within one week) fits - a 24-hour meeting lands inside a 2-day event; Aurora and Gardiner (24 hours to acknowledgment and 10 business days to a decision, written for online communities) does not fit - 10 business days runs past a 2-day event. Stated in the policy: none\nLadder (7 rungs, in order): 1. Warning - appeal no - inappropriate or unwelcome behaviour, a first instance - any staff member may give one; 2. Separation requirement - no contact with the reporter for the rest of the event - appeal no - behaviour aimed at one person; an interim measure alongside another response, never the whole response; 3. Removal of volunteer or staff privileges - appeal no - a volunteer or staff member breaks the policy; 4. Revocation of speaker privileges - appeal no - a talk or a speaker breaks the policy - the rung a conference specifically needs; 5. Ejection from the event, without refund - appeal no - a serious single offence, continuing after being told to stop, or repeated warnings; 6. Ban from future editions, time-boxed - appeal yes - a serious violation or a pattern; the notice states the duration; 7. Permanent ban - appeal yes - a pattern of violation, sustained harassment, or aggression. Outside the ladder: no violation found.\nAppeal route: Ban from future editions, time-boxed and Permanent ban; to a named person outside the response team who did not decide the original case (to be named) - never the organizing team rehearing itself; in writing, by email with [Appeal] in the subject line and the evidence attached; within 14 days of the written notice (self-set)\nPass threshold (self-set): every report acknowledged inside the published window, and every reporter told the outcome before the published follow-up deadline. Rehearse 2 or 3 practice cases before doors open.\nFindings (27):\n[fix] size (team): A team of 2 cannot lose a third (1) and still have the two people a decision needs - name 3 to 6.\n[fix] contacts (team): 1 member with a published contact - publish individual contacts for at least two, so a report about one member has somewhere else to go.\n[fix] outside (team): Nobody sits outside the organizing chain - a report about the team itself has nowhere to go.\n[fix] p_people (policy): Scope - which people (sponsors and booth staff by name): Sponsors and booth staff are not named - every sourced event policy names them.\n[fix] p_channel (policy): Reporting channel - a working alias or line: The reporting sentence carries a placeholder, not a working address.\n[fix] p_contacts (policy): Named individual contacts (a path for a report about the team): Publish individual contacts for at least two people, one of them outside the organizing chain.\n[fix] p_anonymous (policy): An anonymous intake path: a power gradient promotes it - sponsor booth staff answer to a sponsor (Q2).\n[fix] p_confidential (policy): Two-part confidentiality - the report, and the reporter's identity: Promise both: reports are confidential, and the reporter's identity stays confidential unless they say otherwise.\n[fix] p_clock (policy): A published response clock, in hours and days: No response clock - set one in hours and days and publish it.\n[fix] p_template (policy): Template leftovers removed: Replace every placeholder and template note with this event's own names and contacts.\n[check] sponsor_clause (event): Sponsor and booth staff are bound by a contract their employer signed, not a ticket: confirm the sponsor agreement carries the compliance clause and the ejection-without-refund right - wording to counsel.\n[check] declared (team): Tom Okafor has no conflict declaration - every member declares one, none counts, before the event.\n[check] visible (team): A physical day needs responders in visually distinctive clothing - name the identifier and say it in the opening announcement.\n[check] p_dates (policy): Scope - which dates: The chat runs before and after doors - say whether that whole window is in scope.\n[check] p_offsite (policy): Scope - conduct outside the event: Take a position on conduct outside the event - the practitioner stance acts inside your spaces on evidence from outside them.\n[check] p_responders (policy): How to find a responder on site: Say how a reporter physically finds a responder - distinctive clothing, named in the opening announcement.\n[check] p_appeals (policy): Which rungs carry an appeal: No appeal route - decide which rungs carry one and say so.\n[check] p_transparency (policy): A transparency report for the edition: Commit to a report per edition: counts per rung, time to acknowledgment and outcome, no identities.\n[info] hard_date (event): A hard publication date (fixed by ticket sales opening) promotes the rungs that stand up in an afternoon and compresses the drafting.\n[info] not_legal (event): Not legal advice: contract wording goes to counsel; retention, access and deletion of incident records to whoever holds the privacy obligations; anything involving a crime, a minor or an imminent physical threat goes to emergency services and counsel first, this process second.\n[info] backstop (policy): No subjective backstop - a catch-all means a report does not have to match a named category to count.\n[info] booth (policy): No booth-staff clause - booth staff, volunteers included, do not use sexualised clothing, uniforms, costumes or environments.\n[info] transport (policy): Transport is not named - a shuttle is neither the venue nor a social event.\n[info] verbatim (policy): This reads as a template adopted nearly verbatim - it names roles and contacts that do not exist at your event.\n[info] clock (clock): Proposed clock (self-set, between the two published bands): immediately, for anything urgent or ongoing - safety first; acknowledge within 1 hour while the event is running, within 24 hours before and after it; the leads meet within 24 hours, and before the event closes for anything reported on its last day; the reporter hears the outcome within 7 days (one week).\n[info] appeal_asym (ladder): Appeals follow the MLH asymmetry: only ban from future editions, time-boxed and permanent ban carry one; the lighter rungs are over before an appeal could be heard.\n[info] records (ladder): Keep every sanction with its rung and reason across editions - a repeat offence moves up the ladder only when someone can see it is a repeat."
}
Reply:
{
"task": "runbook",
"title": "Incident runbook - Harbourline DevConf, 2027-04-15 to 2027-04-16",
"disclaimer": "This is not legal advice: anything involving a crime, a minor or an imminent threat goes to emergency services and counsel first, and to this runbook second.",
"safety": [
"Ask first whether anyone is in immediate danger.",
"If anyone is, call local emergency services and venue security at once, then note what you did in the report.",
"If everyone is physically safe, involve venue security or law enforcement only at the reporter's request."
],
"intake": [
"Offer the reporter a quiet space where nobody can overhear - the quiet room is to be named and reserved before doors open.",
"Listen actively, without judgment language.",
"Write the account down as you go, asking only clarifying questions.",
"Ask whether they want to stay anonymous, and offer an escort if they want one.",
"Thank the reporter.",
"Escalate at once to Priya Raman by call or message, and to the second lead once named."
],
"never": [
"Never suggest that withdrawing the complaint is an option.",
"Never ask the reporter what the penalty should be.",
"Never promise an outcome - only confidentiality and safety as far as the team can deliver them."
],
"capture": [
"Date and time of the incident",
"Location",
"What happened, in the reporter's own words",
"The reported person, or anything that identifies them",
"Witnesses",
"The reporter's name, contact and relation to the event",
"Whether the reporter wants to stay anonymous",
"Whether anyone is in immediate danger"
],
"recusal": "Any member who realizes they have a conflict says so at once and steps out: a hard conflict (accused, close relationship, personal interest) means no discussion, vote or access to the case file; a soft conflict (same employer) means discussion but no vote. Tom Okafor has no declaration on the roster yet - record one before the event.",
"escalation": [
"The responder who takes the report calls Priya Raman, the conference chair.",
"If the report is about Priya Raman, it goes to the person outside the organizing chain (to be named) instead, and the chair is excluded from the case.",
"Urgent or ongoing incidents are acted on immediately, before any meeting."
],
"decision": {
"method": "The non-conflicted leads decide together on impact, not intent, with consensus as the target and at least two agreeing; when in doubt, err toward taking action (own design where the roster is silent).",
"tie": "A tie goes to the more protective option for the people affected, and is recorded as a tie (own design).",
"absence": "If fewer than two non-conflicted leads can be reached inside the clock, the person outside the organizing chain (to be named) joins the decision (own design)."
},
"notification": [
"The behaviour, in neutral factual terms, with no mention of who reported it.",
"Its impact on the people affected and on the event.",
"The specific change expected from now on.",
"The consequence applied, its rung and, for a ban, its duration - effective immediately."
],
"closure": [
"Show the target the proposed response privately first, to catch missed facts and retaliation risk.",
"Tell the reported person in writing; their only required answer is whether they will comply.",
"Tell the reporter the outcome and that the case is closed unless new information appears.",
"Record the case under a code name with the rung and the reason, and make sure everyone who knew of the incident learns that action was taken."
],
"clock": [
{
"step": "Urgent or ongoing",
"deadline": "immediately - safety first"
},
{
"step": "Acknowledge",
"deadline": "within 1 hour while the event is running, within 24 hours before and after it"
},
{
"step": "Decide",
"deadline": "the leads meet within 24 hours, and before the event closes for anything reported on its last day"
},
{
"step": "Follow up with the reporter",
"deadline": "within 7 days (one week)"
}
],
"staff": [
"Any staff member or volunteer may give a verbal warning without waiting for the response team.",
"Report every warning to Priya Raman as soon as practical: who, when, what behaviour, witnesses, and who reported it.",
"A one-time slip in a talk gets a word with the speaker afterward; a repeated or serious one is stopped calmly, without a long explanation in front of the room."
],
"contacts": [
{
"name": "Priya Raman",
"role": "conference chair",
"contact": "priya@harbourline.dev",
"when": "08:00-19:00 both days"
},
{
"name": "Tom Okafor",
"role": "volunteer lead",
"contact": "",
"when": "09:00-17:00 both days"
}
],
"note": "Before printing, name the quiet room, a third responder outside the organizing chain, Tom Okafor's contact and the local emergency number, then rehearse once."
}
The page's check: kept - nothing to flag
Northwind Data Summit (900, the founder on the team) - audit
Verdict: fix first; 16 of 18 policy sections found; a team of 4; 2 fix-level findings.
Input:
{
"task": "audit",
"event": "Event: Northwind Data Summit; a multi-day conference; headcount 900; 2027-06-08 to 2027-06-10 (3 days); 2 venues\nBound beyond ticket-holders (Q2): speakers, volunteers, sponsor and booth staff, contractors, satellite or fringe events, an online chat before and after\nOrganizing model (Q3): a single organizing entity\nPower gradient (Q4): yes - Dana Whitfield founded the summit, chairs the organizing team and gives the opening keynote.\nPublication (Q5): 2027-02-01, fixed by a sponsor contract; edition (Q6): annual, the team keeps running it\nEffort ceiling (Q7): someone staffs a channel live during the event yes; budget for external help yes\nExisting assets (Q8): a prior edition's policy and records, a trained volunteer pool\nCard details: alias conduct@northwind-summit.org; phone not given; responder identifier bright orange SAFETY shirts; anonymous path the anonymous form in the event app; quiet room Room 2.14, level 2 of the main venue; local emergency number 911",
"roster": "Response team (4), as entered - name | role | contact | chain | on-site hours | conflict declaration:\nDana Whitfield | founder and conference chair | dana@northwind-summit.org | inside the organizing chain | 08:00-18:00 all three days | conflict: none (none) [most senior; could be a report's subject (Q4)]\nLuis Moreno | incident response lead | luis@northwind-summit.org | inside the organizing chain | 08:00-20:00 all three days | conflict: none (none)\nAiko Tanaka | operations director | aiko@northwind-summit.org | inside the organizing chain | 07:30-18:00 all three days | conflict: same employer as a gold sponsor's booth team (soft)\nGrace Mensah | independent alternate, Community Safety Collective | grace@safetycollective.org | outside the organizing chain | on call all three days | conflict: none (none)",
"policy": "Northwind Data Summit - Code of Conduct\n\nThe Northwind Data Summit is dedicated to providing a harassment-free experience for everyone who takes part, regardless of gender, gender identity and expression, sexual orientation, disability, physical appearance, body size, race, ethnicity, age, religion or nationality.\n\nWho and where\nThis code of conduct applies to all attendees, speakers, sponsors, exhibitors and booth staff, volunteers, contractors, organizers and staff - in every summit venue, at summit social events and receptions, at sponsored and unofficial events around the summit, on the summit shuttles, and in the summit's online chat from the day registration opens until two weeks after the closing day. Conduct outside the event is not ours to police, but we can act inside our own spaces on evidence of it - including declining a speaking slot.\n\nUnacceptable behavior\nHarassment includes, but is not limited to: offensive comments related to the characteristics above; sexual or violent imagery and language in talks, slides, booths or public spaces; deliberate intimidation, stalking, following, brigading or doxxing; harassing photography or recording, including photographing someone who has asked not to be photographed; sustained disruption of talks and other events; inappropriate physical contact; and unwelcome sexual attention. If what you are doing is making someone uncomfortable, stop. Booth staff, including volunteers, should not use sexualized clothing, uniforms, costumes or environments.\n\nHow to report\nEmail conduct@northwind-summit.org, or find a responder - responders wear bright orange SAFETY shirts and are introduced at the opening session. You can also contact Luis Moreno (luis@northwind-summit.org), Dana Whitfield (dana@northwind-summit.org) or our independent alternate Grace Mensah (grace@safetycollective.org) directly. Reports can be made anonymously through the form in the event app.\nAll reports are handled confidentially, and the reporter's identity will not be shared without the reporter's permission. Responders will help you contact venue security or local law enforcement, arrange an escort, or find a quiet room.\n\nWhat happens next\nResponders act immediately on anything urgent or ongoing. For everything else we acknowledge the report within 24 hours, the response leads meet within 24 hours, and we follow up with the reporter within one week.\n\nConsequences\nDepending on the behavior, the response team may give a warning, require no contact with the people involved for the rest of the summit, remove volunteer privileges, revoke speaker privileges, eject the person from the summit without a refund, or ban them from future events.\nAnyone sanctioned under this policy may appeal the decision by writing to the organizing team.\n\nAdapted from the PyCon US Code of Conduct, licensed under CC BY 3.0.",
"facts": "Verdict: fix first (pipeline - named team yes, working channel yes, published ladder yes)\nPolicy text: 2,858 characters; template signature phrases 0 of 6\nAnatomy (16 of 18 found, in order):\n1. Pledge - a harassment-free event, and for whom: FOUND - \"The Northwind Data Summit is dedicated to providing a harassment-free experience for everyone who takes part, regardless of gender, gender identity and expression, sexual orientation, disability,...\"\n2. Prohibited behaviour, enumerated: FOUND - \"Unacceptable behavior\"\n3. Scope - which people (sponsors and booth staff by name): FOUND - \"This code of conduct applies to all attendees, speakers, sponsors, exhibitors and booth staff, volunteers, contractors, organizers and staff - in every summit venue, at summit social events and...\"\n4. Scope - which spaces (venue, online, social, unofficial): FOUND - \"This code of conduct applies to all attendees, speakers, sponsors, exhibitors and booth staff, volunteers, contractors, organizers and staff - in every summit venue, at summit social events and...\"\n5. Scope - which dates: FOUND - \"...and receptions, at sponsored and unofficial events around the summit, on the summit shuttles, and in the summit's online chat from the day registration opens until two weeks after the closing day.\"\n6. Scope - conduct outside the event: FOUND - \"Conduct outside the event is not ours to police, but we can act inside our own spaces on evidence of it - including declining a speaking slot.\"\n7. Reporting channel - a working alias or line: FOUND - \"Email conduct@northwind-summit.org, or find a responder - responders wear bright orange SAFETY shirts and are introduced at the opening session.\"\n8. Named individual contacts (a path for a report about the team): FOUND - \"names Dana Whitfield, Luis Moreno and Grace Mensah\"\n9. An anonymous intake path: FOUND - \"Reports can be made anonymously through the form in the event app.\"\n10. How to find a responder on site: FOUND - \"Email conduct@northwind-summit.org, or find a responder - responders wear bright orange SAFETY shirts and are introduced at the opening session.\"\n11. Two-part confidentiality - the report, and the reporter's identity: FOUND - \"All reports are handled confidentially, and the reporter's identity will not be shared without the reporter's permission.\"\n12. A published response clock, in hours and days: FOUND - \"For everything else we acknowledge the report within 24 hours, the response leads meet within 24 hours, and we follow up with the reporter within one week.\"\n13. The sanctions, listed: FOUND - \"Consequences\"\n14. Which rungs carry an appeal: PARTIAL - \"Anyone sanctioned under this policy may appeal the decision by writing to the organizing team.\" - An appeal right with no rungs named reads as uniform - say which rungs are appealable, to whom, in what form and by when.\n15. A transparency report for the edition: MISSING - Commit to a report per edition: counts per rung, time to acknowledgment and outcome, no identities.\n16. Template leftovers removed: FOUND\n17. Attribution and licence line: FOUND - \"Adapted from the PyCon US Code of Conduct, licensed under CC BY 3.0.\"\n18. Help on offer - security, law enforcement, escorts: FOUND - \"Responders will help you contact venue security or local law enforcement, arrange an escort, or find a quiet room.\"\nTeam checks: A team of 3-6 that survives a third away ok; No single organizer as sole responder ok; Individual contacts for at least two members ok; At least one member outside the organizing chain ok; Every member's place in the chain stated ok; Every member's conflict declaration recorded ok; A possible report subject on the team has pre-declared recusal MISSING; On-site hours for every member ok; Responders a reporter can see ok; Someone staffs a channel live during the event ok\nMenu 1 - Base-text posture (pick: Adapt an established text): 1. Adapt an established text; 2. Adopt one verbatim; 3. Adapt plus a culture preamble. Deleted, not demoted: Write your own from scratch (no in-house counsel (Q8) - a from-scratch draft spends a week arriving at the shared list minus whatever it forgets)\nMenu 2 - Reporting channels (pick: Published email alias + Anonymous intake path + Physically identifiable on-site responders + Named conflict-of-interest alternates): 1. Published email alias; 2. Anonymous intake path [moved by: a power gradient: someone who could be a report's subject holds power on the organizing side (Q4); sponsor booth staff answer to a sponsor (Q2); the response team includes the most senior organizer, Dana Whitfield]; 3. Physically identifiable on-site responders; 4. Named conflict-of-interest alternates; 5. Staffed phone or SMS hotline\nMenu 3 - Response-team staffing (pick: An external trust-and-safety contractor + A named, published team of 3-6): 1. An external trust-and-safety contractor [moved by: the most powerful person sits on the organizing team and no independent body exists above them (Q4)]; 2. A named, published team of 3-6. Deleted, not demoted: Route into an umbrella body's incidents team (no umbrella body with its own incidents team (Q3, Q8)); A single named organizer as sole responder (the sole organizer is the most senior person on the team, so the channel cannot receive the one report most likely to need it)\nClock (self-set): immediately, for anything urgent or ongoing - safety first; acknowledge within 1 hour while the event is running, within 24 hours before and after it; the leads meet within 24 hours, and before the event closes for anything reported on its last day; the reporter hears the outcome within 7 days (one week); the event runs 3 days. Bands: PyCon US (the leads meet within 24 hours for non-urgent reports and follow up with the reporter within one week) fits - a 24-hour meeting lands inside a 3-day event; Aurora and Gardiner (24 hours to acknowledgment and 10 business days to a decision, written for online communities) does not fit - 10 business days runs past a 3-day event. Stated in the policy: within 24 hours; within one week\nLadder (7 rungs, in order): 1. Warning - appeal no - inappropriate or unwelcome behaviour, a first instance - any staff member may give one; 2. Separation requirement - no contact with the reporter for the rest of the event - appeal no - behaviour aimed at one person; an interim measure alongside another response, never the whole response; 3. Removal of volunteer or staff privileges - appeal no - a volunteer or staff member breaks the policy; 4. Revocation of speaker privileges - appeal no - a talk or a speaker breaks the policy - the rung a conference specifically needs; 5. Ejection from the event, without refund - appeal no - a serious single offence, continuing after being told to stop, or repeated warnings; 6. Ban from future editions, time-boxed - appeal yes - a serious violation or a pattern; the notice states the duration; 7. Permanent ban - appeal yes - a pattern of violation, sustained harassment, or aggression. Outside the ladder: no violation found.\nAppeal route: Ban from future editions, time-boxed and Permanent ban; to an external reviewer retained for the purpose, or a named person outside the response team who did not decide the case; in writing, by email with [Appeal] in the subject line and the evidence attached; within 14 days of the written notice (self-set)\nPass threshold (self-set): every report acknowledged inside the published window, and every reporter told the outcome before the published follow-up deadline. Rehearse 2 or 3 practice cases before doors open.\nFindings (11):\n[fix] subject (team): Dana Whitfield could be the subject of a report and sits on the response team without a hard-conflict declaration - pre-declare recusal: out of the discussion, the vote and the confidential material for any report naming them.\n[fix] p_appeals (policy): Which rungs carry an appeal: An appeal right with no rungs named reads as uniform - say which rungs are appealable, to whom, in what form and by when.\n[check] sponsor_clause (event): Sponsor and booth staff are bound by a contract their employer signed, not a ticket: confirm the sponsor agreement carries the compliance clause and the ejection-without-refund right - wording to counsel.\n[check] contractor (team): The most powerful person sits on the organizing team and no independent body sits above them: retain an external trust-and-safety contractor for reports that name them.\n[check] p_transparency (policy): A transparency report for the edition: Commit to a report per edition: counts per rung, time to acknowledgment and outcome, no identities.\n[info] hard_date (event): A hard publication date (fixed by a sponsor contract) promotes the rungs that stand up in an afternoon and compresses the drafting.\n[info] not_legal (event): Not legal advice: contract wording goes to counsel; retention, access and deletion of incident records to whoever holds the privacy obligations; anything involving a crime, a minor or an imminent physical threat goes to emergency services and counsel first, this process second.\n[info] soft_3 (team): Aiko Tanaka declares a soft conflict (same employer as a gold sponsor's booth team): may discuss a case it touches, may not vote.\n[info] clock (clock): Proposed clock (self-set, between the two published bands): immediately, for anything urgent or ongoing - safety first; acknowledge within 1 hour while the event is running, within 24 hours before and after it; the leads meet within 24 hours, and before the event closes for anything reported on its last day; the reporter hears the outcome within 7 days (one week).\n[info] appeal_asym (ladder): Appeals follow the MLH asymmetry: only ban from future editions, time-boxed and permanent ban carry one; the lighter rungs are over before an appeal could be heard.\n[info] records (ladder): Keep every sanction with its rung and reason across editions - a repeat offence moves up the ladder only when someone can see it is a repeat."
}
Reply:
{
"task": "audit",
"summary": "Fix first: the policy and the team are nearly ready, but Dana Whitfield sits on the response team with no recusal declared and the appeal right is uniform - settle both before 2027-02-01.",
"disclaimer": "This is not legal advice: the sponsor clause and the ticket terms go to counsel, and anything involving a crime, a minor or an imminent threat goes to emergency services and counsel first.",
"verdict": "fix first",
"sections": [
{
"item": "Pledge - a harassment-free event, and for whom",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Prohibited behaviour, enumerated",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Scope - which people (sponsors and booth staff by name)",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Scope - which spaces (venue, online, social, unofficial)",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Scope - which dates",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Scope - conduct outside the event",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Reporting channel - a working alias or line",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Named individual contacts (a path for a report about the team)",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "An anonymous intake path",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "How to find a responder on site",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Two-part confidentiality - the report, and the reporter's identity",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "A published response clock, in hours and days",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "The sanctions, listed",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Which rungs carry an appeal",
"status": "partial",
"fix": "The policy offers an appeal of any decision to the organizing team - the same people rehearing themselves; name the appealable rungs, the reviewer, the form and the deadline.",
"wording": "Only a time-boxed or permanent ban from future editions can be appealed: email the independent reviewer (to be named) with [Appeal] in the subject line and your evidence, within 14 days of the written notice. Warnings, no-contact requirements, removal of privileges and ejection are not appealable. (own design)"
},
{
"item": "A transparency report for the edition",
"status": "missing",
"fix": "Commit to a report for the edition and decide its contents before the first incident.",
"wording": "After each summit we publish how many reports we received, how many led to each consequence, and how quickly we acknowledged and resolved them - never names or incident details. (own design)"
},
{
"item": "Template leftovers removed",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Attribution and licence line",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Help on offer - security, law enforcement, escorts",
"status": "found",
"fix": "",
"wording": ""
}
],
"posture": {
"pick": "Adapt an established text",
"reason": "The summit already adapts the PyCon US text and has last edition's policy, so this is an editing pass; the sponsor-contract deadline keeps the culture preamble from moving up."
},
"channels": {
"picks": [
"Published email alias",
"Anonymous intake path",
"Physically identifiable on-site responders",
"Named conflict-of-interest alternates"
],
"reason": "The anonymous path moved up because the founder holds power on the organizing side, booth staff answer to sponsors, and the most senior organizer is on the team - and the policy already offers one through the event app."
},
"staffing": {
"pick": "An external trust-and-safety contractor",
"reason": "The most powerful person sits on the organizing team with no independent body above them, and there is budget for outside help - retain a contractor for reports that name Dana Whitfield, alongside the named team of 4."
},
"clock": {
"acknowledge": "within 1 hour while the event is running, within 24 hours before and after it",
"decide": "the leads meet within 24 hours, and before the event closes for anything reported on its last day",
"follow_up": "the reporter hears the outcome within 7 days (one week)",
"note": "The page's clock is self-set and tightens the policy's published PyCon US band, which fits inside a 3-day event; the 10-business-day band does not."
},
"ladder": [
{
"rung": "Warning",
"appealable": false,
"when": "inappropriate or unwelcome behaviour, a first instance"
},
{
"rung": "Separation requirement - no contact with the reporter for the rest of the event",
"appealable": false,
"when": "behaviour aimed at one person, as an interim measure alongside another response"
},
{
"rung": "Removal of volunteer or staff privileges",
"appealable": false,
"when": "a volunteer or staff member breaks the policy"
},
{
"rung": "Revocation of speaker privileges",
"appealable": false,
"when": "a talk, its slides or a speaker breaks the policy"
},
{
"rung": "Ejection from the event, without refund",
"appealable": false,
"when": "a serious single offence, continuing after being told to stop, or repeated warnings"
},
{
"rung": "Ban from future editions, time-boxed",
"appealable": true,
"when": "a serious violation or a pattern, with the duration in the notice"
},
{
"rung": "Permanent ban",
"appealable": true,
"when": "a pattern of violation, sustained harassment, or aggression"
}
],
"appeal": "Only the time-boxed and permanent bans carry an appeal - in writing, by email with [Appeal] in the subject line and the evidence attached, within 14 days of the written notice, to an external reviewer retained for the purpose or a named person outside the response team who did not decide the case.",
"rehearsal": [
{
"case": "An attendee at a sponsored evening event reports that Dana Whitfield made repeated unwelcome comments to them.",
"practice": "Dana Whitfield's recusal from the first minute, routing to Grace Mensah and the contractor, and keeping the reporter's identity out of every message."
},
{
"case": "A gold sponsor's booth staffer is reported on day 2 for photographing attendees who asked not to be photographed.",
"practice": "Aiko Tanaka's soft conflict (may discuss, may not vote), checking the sponsor contract's ejection right, and the four-part notification."
},
{
"case": "A report arrives in the summit chat a week after the closing day about a speaker's slides.",
"practice": "Confirming the chat is in scope until two weeks after the closing day, acknowledging within 24 hours, and deciding on speaker privileges for the next edition."
}
],
"transparency": "Publish one report per edition with the number of reports, the count reaching each rung and the median time to acknowledgment and to outcome against the published clock - no reporter, witness or reported-person identities and no incident narratives.",
"caveats": [
"Dana Whitfield could be the subject of a report and has no hard-conflict declaration - pre-declare recusal from discussion, vote and confidential material.",
"Replace the uniform appeal to the organizing team with stated appeal rungs, an independent reviewer, a form and a deadline.",
"Confirm the sponsor agreement carries the compliance clause and the ejection-without-refund right - wording to counsel.",
"Retain the external trust-and-safety contractor for reports that name the founder.",
"Commit to a transparency report for the edition."
]
}
The page's check: kept - nothing to flag
Northwind Data Summit (900, the founder on the team) - runbook
Verdict: fix first; 16 of 18 policy sections found; a team of 4; 2 fix-level findings.
Input:
{
"task": "runbook",
"event": "Event: Northwind Data Summit; a multi-day conference; headcount 900; 2027-06-08 to 2027-06-10 (3 days); 2 venues\nBound beyond ticket-holders (Q2): speakers, volunteers, sponsor and booth staff, contractors, satellite or fringe events, an online chat before and after\nOrganizing model (Q3): a single organizing entity\nPower gradient (Q4): yes - Dana Whitfield founded the summit, chairs the organizing team and gives the opening keynote.\nPublication (Q5): 2027-02-01, fixed by a sponsor contract; edition (Q6): annual, the team keeps running it\nEffort ceiling (Q7): someone staffs a channel live during the event yes; budget for external help yes\nExisting assets (Q8): a prior edition's policy and records, a trained volunteer pool\nCard details: alias conduct@northwind-summit.org; phone not given; responder identifier bright orange SAFETY shirts; anonymous path the anonymous form in the event app; quiet room Room 2.14, level 2 of the main venue; local emergency number 911",
"roster": "Response team (4), as entered - name | role | contact | chain | on-site hours | conflict declaration:\nDana Whitfield | founder and conference chair | dana@northwind-summit.org | inside the organizing chain | 08:00-18:00 all three days | conflict: none (none) [most senior; could be a report's subject (Q4)]\nLuis Moreno | incident response lead | luis@northwind-summit.org | inside the organizing chain | 08:00-20:00 all three days | conflict: none (none)\nAiko Tanaka | operations director | aiko@northwind-summit.org | inside the organizing chain | 07:30-18:00 all three days | conflict: same employer as a gold sponsor's booth team (soft)\nGrace Mensah | independent alternate, Community Safety Collective | grace@safetycollective.org | outside the organizing chain | on call all three days | conflict: none (none)",
"policy": "Northwind Data Summit - Code of Conduct\n\nThe Northwind Data Summit is dedicated to providing a harassment-free experience for everyone who takes part, regardless of gender, gender identity and expression, sexual orientation, disability, physical appearance, body size, race, ethnicity, age, religion or nationality.\n\nWho and where\nThis code of conduct applies to all attendees, speakers, sponsors, exhibitors and booth staff, volunteers, contractors, organizers and staff - in every summit venue, at summit social events and receptions, at sponsored and unofficial events around the summit, on the summit shuttles, and in the summit's online chat from the day registration opens until two weeks after the closing day. Conduct outside the event is not ours to police, but we can act inside our own spaces on evidence of it - including declining a speaking slot.\n\nUnacceptable behavior\nHarassment includes, but is not limited to: offensive comments related to the characteristics above; sexual or violent imagery and language in talks, slides, booths or public spaces; deliberate intimidation, stalking, following, brigading or doxxing; harassing photography or recording, including photographing someone who has asked not to be photographed; sustained disruption of talks and other events; inappropriate physical contact; and unwelcome sexual attention. If what you are doing is making someone uncomfortable, stop. Booth staff, including volunteers, should not use sexualized clothing, uniforms, costumes or environments.\n\nHow to report\nEmail conduct@northwind-summit.org, or find a responder - responders wear bright orange SAFETY shirts and are introduced at the opening session. You can also contact Luis Moreno (luis@northwind-summit.org), Dana Whitfield (dana@northwind-summit.org) or our independent alternate Grace Mensah (grace@safetycollective.org) directly. Reports can be made anonymously through the form in the event app.\nAll reports are handled confidentially, and the reporter's identity will not be shared without the reporter's permission. Responders will help you contact venue security or local law enforcement, arrange an escort, or find a quiet room.\n\nWhat happens next\nResponders act immediately on anything urgent or ongoing. For everything else we acknowledge the report within 24 hours, the response leads meet within 24 hours, and we follow up with the reporter within one week.\n\nConsequences\nDepending on the behavior, the response team may give a warning, require no contact with the people involved for the rest of the summit, remove volunteer privileges, revoke speaker privileges, eject the person from the summit without a refund, or ban them from future events.\nAnyone sanctioned under this policy may appeal the decision by writing to the organizing team.\n\nAdapted from the PyCon US Code of Conduct, licensed under CC BY 3.0.",
"facts": "Verdict: fix first (pipeline - named team yes, working channel yes, published ladder yes)\nPolicy text: 2,858 characters; template signature phrases 0 of 6\nAnatomy (16 of 18 found, in order):\n1. Pledge - a harassment-free event, and for whom: FOUND - \"The Northwind Data Summit is dedicated to providing a harassment-free experience for everyone who takes part, regardless of gender, gender identity and expression, sexual orientation, disability,...\"\n2. Prohibited behaviour, enumerated: FOUND - \"Unacceptable behavior\"\n3. Scope - which people (sponsors and booth staff by name): FOUND - \"This code of conduct applies to all attendees, speakers, sponsors, exhibitors and booth staff, volunteers, contractors, organizers and staff - in every summit venue, at summit social events and...\"\n4. Scope - which spaces (venue, online, social, unofficial): FOUND - \"This code of conduct applies to all attendees, speakers, sponsors, exhibitors and booth staff, volunteers, contractors, organizers and staff - in every summit venue, at summit social events and...\"\n5. Scope - which dates: FOUND - \"...and receptions, at sponsored and unofficial events around the summit, on the summit shuttles, and in the summit's online chat from the day registration opens until two weeks after the closing day.\"\n6. Scope - conduct outside the event: FOUND - \"Conduct outside the event is not ours to police, but we can act inside our own spaces on evidence of it - including declining a speaking slot.\"\n7. Reporting channel - a working alias or line: FOUND - \"Email conduct@northwind-summit.org, or find a responder - responders wear bright orange SAFETY shirts and are introduced at the opening session.\"\n8. Named individual contacts (a path for a report about the team): FOUND - \"names Dana Whitfield, Luis Moreno and Grace Mensah\"\n9. An anonymous intake path: FOUND - \"Reports can be made anonymously through the form in the event app.\"\n10. How to find a responder on site: FOUND - \"Email conduct@northwind-summit.org, or find a responder - responders wear bright orange SAFETY shirts and are introduced at the opening session.\"\n11. Two-part confidentiality - the report, and the reporter's identity: FOUND - \"All reports are handled confidentially, and the reporter's identity will not be shared without the reporter's permission.\"\n12. A published response clock, in hours and days: FOUND - \"For everything else we acknowledge the report within 24 hours, the response leads meet within 24 hours, and we follow up with the reporter within one week.\"\n13. The sanctions, listed: FOUND - \"Consequences\"\n14. Which rungs carry an appeal: PARTIAL - \"Anyone sanctioned under this policy may appeal the decision by writing to the organizing team.\" - An appeal right with no rungs named reads as uniform - say which rungs are appealable, to whom, in what form and by when.\n15. A transparency report for the edition: MISSING - Commit to a report per edition: counts per rung, time to acknowledgment and outcome, no identities.\n16. Template leftovers removed: FOUND\n17. Attribution and licence line: FOUND - \"Adapted from the PyCon US Code of Conduct, licensed under CC BY 3.0.\"\n18. Help on offer - security, law enforcement, escorts: FOUND - \"Responders will help you contact venue security or local law enforcement, arrange an escort, or find a quiet room.\"\nTeam checks: A team of 3-6 that survives a third away ok; No single organizer as sole responder ok; Individual contacts for at least two members ok; At least one member outside the organizing chain ok; Every member's place in the chain stated ok; Every member's conflict declaration recorded ok; A possible report subject on the team has pre-declared recusal MISSING; On-site hours for every member ok; Responders a reporter can see ok; Someone staffs a channel live during the event ok\nMenu 1 - Base-text posture (pick: Adapt an established text): 1. Adapt an established text; 2. Adopt one verbatim; 3. Adapt plus a culture preamble. Deleted, not demoted: Write your own from scratch (no in-house counsel (Q8) - a from-scratch draft spends a week arriving at the shared list minus whatever it forgets)\nMenu 2 - Reporting channels (pick: Published email alias + Anonymous intake path + Physically identifiable on-site responders + Named conflict-of-interest alternates): 1. Published email alias; 2. Anonymous intake path [moved by: a power gradient: someone who could be a report's subject holds power on the organizing side (Q4); sponsor booth staff answer to a sponsor (Q2); the response team includes the most senior organizer, Dana Whitfield]; 3. Physically identifiable on-site responders; 4. Named conflict-of-interest alternates; 5. Staffed phone or SMS hotline\nMenu 3 - Response-team staffing (pick: An external trust-and-safety contractor + A named, published team of 3-6): 1. An external trust-and-safety contractor [moved by: the most powerful person sits on the organizing team and no independent body exists above them (Q4)]; 2. A named, published team of 3-6. Deleted, not demoted: Route into an umbrella body's incidents team (no umbrella body with its own incidents team (Q3, Q8)); A single named organizer as sole responder (the sole organizer is the most senior person on the team, so the channel cannot receive the one report most likely to need it)\nClock (self-set): immediately, for anything urgent or ongoing - safety first; acknowledge within 1 hour while the event is running, within 24 hours before and after it; the leads meet within 24 hours, and before the event closes for anything reported on its last day; the reporter hears the outcome within 7 days (one week); the event runs 3 days. Bands: PyCon US (the leads meet within 24 hours for non-urgent reports and follow up with the reporter within one week) fits - a 24-hour meeting lands inside a 3-day event; Aurora and Gardiner (24 hours to acknowledgment and 10 business days to a decision, written for online communities) does not fit - 10 business days runs past a 3-day event. Stated in the policy: within 24 hours; within one week\nLadder (7 rungs, in order): 1. Warning - appeal no - inappropriate or unwelcome behaviour, a first instance - any staff member may give one; 2. Separation requirement - no contact with the reporter for the rest of the event - appeal no - behaviour aimed at one person; an interim measure alongside another response, never the whole response; 3. Removal of volunteer or staff privileges - appeal no - a volunteer or staff member breaks the policy; 4. Revocation of speaker privileges - appeal no - a talk or a speaker breaks the policy - the rung a conference specifically needs; 5. Ejection from the event, without refund - appeal no - a serious single offence, continuing after being told to stop, or repeated warnings; 6. Ban from future editions, time-boxed - appeal yes - a serious violation or a pattern; the notice states the duration; 7. Permanent ban - appeal yes - a pattern of violation, sustained harassment, or aggression. Outside the ladder: no violation found.\nAppeal route: Ban from future editions, time-boxed and Permanent ban; to an external reviewer retained for the purpose, or a named person outside the response team who did not decide the case; in writing, by email with [Appeal] in the subject line and the evidence attached; within 14 days of the written notice (self-set)\nPass threshold (self-set): every report acknowledged inside the published window, and every reporter told the outcome before the published follow-up deadline. Rehearse 2 or 3 practice cases before doors open.\nFindings (11):\n[fix] subject (team): Dana Whitfield could be the subject of a report and sits on the response team without a hard-conflict declaration - pre-declare recusal: out of the discussion, the vote and the confidential material for any report naming them.\n[fix] p_appeals (policy): Which rungs carry an appeal: An appeal right with no rungs named reads as uniform - say which rungs are appealable, to whom, in what form and by when.\n[check] sponsor_clause (event): Sponsor and booth staff are bound by a contract their employer signed, not a ticket: confirm the sponsor agreement carries the compliance clause and the ejection-without-refund right - wording to counsel.\n[check] contractor (team): The most powerful person sits on the organizing team and no independent body sits above them: retain an external trust-and-safety contractor for reports that name them.\n[check] p_transparency (policy): A transparency report for the edition: Commit to a report per edition: counts per rung, time to acknowledgment and outcome, no identities.\n[info] hard_date (event): A hard publication date (fixed by a sponsor contract) promotes the rungs that stand up in an afternoon and compresses the drafting.\n[info] not_legal (event): Not legal advice: contract wording goes to counsel; retention, access and deletion of incident records to whoever holds the privacy obligations; anything involving a crime, a minor or an imminent physical threat goes to emergency services and counsel first, this process second.\n[info] soft_3 (team): Aiko Tanaka declares a soft conflict (same employer as a gold sponsor's booth team): may discuss a case it touches, may not vote.\n[info] clock (clock): Proposed clock (self-set, between the two published bands): immediately, for anything urgent or ongoing - safety first; acknowledge within 1 hour while the event is running, within 24 hours before and after it; the leads meet within 24 hours, and before the event closes for anything reported on its last day; the reporter hears the outcome within 7 days (one week).\n[info] appeal_asym (ladder): Appeals follow the MLH asymmetry: only ban from future editions, time-boxed and permanent ban carry one; the lighter rungs are over before an appeal could be heard.\n[info] records (ladder): Keep every sanction with its rung and reason across editions - a repeat offence moves up the ladder only when someone can see it is a repeat."
}
Reply:
{
"task": "runbook",
"title": "Incident runbook - Northwind Data Summit, 2027-06-08 to 2027-06-10",
"disclaimer": "This is not legal advice: anything involving a crime, a minor or an imminent threat goes to emergency services and counsel first, and to this runbook second.",
"safety": [
"Ask first whether anyone is in immediate danger.",
"If anyone is, call 911 and venue security at once, then note what you did in the report.",
"If everyone is physically safe, involve venue security or law enforcement only at the reporter's request."
],
"intake": [
"Wear the bright orange SAFETY shirt so a reporter can find you.",
"Offer the reporter the quiet room - Room 2.14, level 2 of the main venue.",
"Listen actively, without judgment language.",
"Write the account down as you go, asking only clarifying questions.",
"Ask whether they want to stay anonymous, and offer an escort if they want one.",
"Thank the reporter.",
"Escalate at once to Luis Moreno by call or message."
],
"never": [
"Never suggest that withdrawing the complaint is an option.",
"Never ask the reporter what the penalty should be.",
"Never promise an outcome - only confidentiality and safety as far as the team can deliver them."
],
"capture": [
"Date and time of the incident",
"Location",
"What happened, in the reporter's own words",
"The reported person, or anything that identifies them",
"Witnesses",
"The reporter's name, contact and relation to the event",
"Whether the reporter wants to stay anonymous",
"Whether anyone is in immediate danger"
],
"recusal": "Dana Whitfield is recused from any report that names them - record it now as a hard conflict, so they are out of the discussion, the vote and the case file; Aiko Tanaka declares a soft conflict for cases touching the gold sponsor's booth team and may discuss but not vote. Luis Moreno executes every recusal.",
"escalation": [
"The responder who takes the report calls Luis Moreno, the incident response lead.",
"Luis Moreno brings in the non-conflicted leads: Aiko Tanaka and Grace Mensah, with Dana Whitfield only when not conflicted.",
"A report about Dana Whitfield goes to Grace Mensah and the external trust-and-safety contractor (to be named), never through the organizing chain.",
"Urgent or ongoing incidents are acted on immediately, before any meeting."
],
"decision": {
"method": "The non-conflicted members decide together on impact, not intent: consensus is the target, at least two must agree, and the team errs toward taking action (own design where the roster is silent).",
"tie": "A tie goes to the more protective option for the people affected, and is recorded as a tie (own design).",
"absence": "If fewer than two non-conflicted members are reachable inside the clock, Grace Mensah decides with the external contractor (own design)."
},
"notification": [
"The behaviour, in neutral factual terms, with no mention of who reported it.",
"Its impact on the people affected and on the event.",
"The specific change expected from now on.",
"The consequence applied, its rung and, for a ban, its duration - effective immediately."
],
"closure": [
"Show the target the proposed response privately first, to catch missed facts and retaliation risk.",
"Tell the reported person in writing; their only required answer is whether they will comply.",
"Tell the reporter the outcome and that the case is closed unless new information appears.",
"Record the case under a code name with the rung and the reason, and make sure everyone who knew of the incident learns that action was taken."
],
"clock": [
{
"step": "Urgent or ongoing",
"deadline": "immediately - safety first"
},
{
"step": "Acknowledge",
"deadline": "within 1 hour while the event is running, within 24 hours before and after it"
},
{
"step": "Decide",
"deadline": "the leads meet within 24 hours, and before the event closes for anything reported on its last day"
},
{
"step": "Follow up with the reporter",
"deadline": "within 7 days (one week)"
}
],
"staff": [
"Any staff member or volunteer may give a verbal warning without waiting for the response team.",
"Report every warning to Luis Moreno as soon as practical: who, when, what behaviour, witnesses, and who reported it.",
"A one-time slip in a talk gets a word with the speaker afterward; a repeated or serious one is stopped calmly, without a long explanation in front of the room."
],
"contacts": [
{
"name": "Dana Whitfield",
"role": "founder and conference chair",
"contact": "dana@northwind-summit.org",
"when": "08:00-18:00 all three days"
},
{
"name": "Luis Moreno",
"role": "incident response lead",
"contact": "luis@northwind-summit.org",
"when": "08:00-20:00 all three days"
},
{
"name": "Aiko Tanaka",
"role": "operations director",
"contact": "aiko@northwind-summit.org",
"when": "07:30-18:00 all three days"
},
{
"name": "Grace Mensah",
"role": "independent alternate, Community Safety Collective",
"contact": "grace@safetycollective.org",
"when": "on call all three days"
}
],
"note": "Before printing, record Dana Whitfield's hard-conflict declaration, name the external contractor, and rehearse two practice cases with all four members."
}
The page's check: kept - nothing to flag
Brickfield Rust Meetup (45, one organizer) - audit
Verdict: no pipeline - do not publish yet; 3 of 18 policy sections found; a team of 1; 9 fix-level findings.
Input:
{
"task": "audit",
"event": "Event: Brickfield Rust Meetup; a meetup; headcount 45; 2027-03-04 to 2027-03-04 (1 day); 1 venue\nBound beyond ticket-holders (Q2): speakers, an online chat before and after\nOrganizing model (Q3): a voluntary peer network of independent chapters - the Northern Rust meetups network\nPower gradient (Q4): no\nPublication (Q5): 2027-02-15, fixed by the team's own target; edition (Q6): annual, the team keeps running it\nEffort ceiling (Q7): someone staffs a channel live during the event yes; budget for external help no\nExisting assets (Q8): a values or cultural-identity document\nCard details: alias not given; phone not given; responder identifier not given; anonymous path not given; quiet room not given; local emergency number not given",
"roster": "Response team (1), as entered - name | role | contact | chain | on-site hours | conflict declaration:\nSam Ortiz | organizer and host | sam@brickfieldrust.dev | inside the organizing chain | 18:00-21:30 | conflict: none (none) [most senior]",
"policy": "Brickfield Rust Meetup - Code of Conduct\n\nWe want the meetup to be a friendly, welcoming place for everyone. Be kind and respectful.\nHarassment of any kind is not tolerated, including offensive comments about gender, race, disability or religion.\nIf someone makes you uncomfortable, talk to Sam, our organizer, at the meetup or by email at sam@brickfieldrust.dev.\nPeople who break these rules may be asked to leave the meetup.\n\nInspired by the Rust Code of Conduct.",
"facts": "Verdict: no pipeline - do not publish yet (pipeline - named team no, working channel yes, published ladder yes)\nPolicy text: 465 characters; template signature phrases 0 of 6\nAnatomy (3 of 18 found, in order):\n1. Pledge - a harassment-free event, and for whom: MISSING - Open with the commitment to a harassment-free event and who it covers.\n2. Prohibited behaviour, enumerated: MISSING - \"Harassment of any kind is not tolerated, including offensive comments about gender, race, disability or religion.\" - Missing from the standard list: sexual or violent imagery and language, intimidation, stalking, following or doxxing, harassing photography or recording, sustained disruption of talks and events and inappropriate physical contact and unwelcome sexual attention.\n3. Scope - which people (sponsors and booth staff by name): PARTIAL - \"names attendees and organizers and staff\" - Sponsors and booth staff are not named - every sourced event policy names them. Bound but not named: speakers.\n4. Scope - which spaces (venue, online, social, unofficial): MISSING - Not named: the venue, social events and online channels. Transport is easy to forget too.\n5. Scope - which dates: MISSING - Say which dates the policy covers.\n6. Scope - conduct outside the event: MISSING - Take a position on conduct outside the event - the practitioner stance acts inside your spaces on evidence from outside them.\n7. Reporting channel - a working alias or line: FOUND - \"If someone makes you uncomfortable, talk to Sam, our organizer, at the meetup or by email at sam@brickfieldrust.dev.\"\n8. Named individual contacts (a path for a report about the team): PARTIAL - \"lists sam@brickfieldrust.dev\" - Publish individual contacts for at least two people, one of them outside the organizing chain.\n9. An anonymous intake path: MISSING - No anonymous path - the reports the other channels never receive.\n10. How to find a responder on site: MISSING - Say how a reporter physically finds a responder - distinctive clothing, named in the opening announcement.\n11. Two-part confidentiality - the report, and the reporter's identity: MISSING - Promise both: reports are confidential, and the reporter's identity stays confidential unless they say otherwise.\n12. A published response clock, in hours and days: MISSING - No response clock - set one in hours and days and publish it.\n13. The sanctions, listed: PARTIAL - \"People who break these rules may be asked to leave the meetup.\" - Publish the consequences before the first incident.\n14. Which rungs carry an appeal: MISSING - No appeal route - decide which rungs carry one and say so.\n15. A transparency report for the edition: MISSING - Commit to a report per edition: counts per rung, time to acknowledgment and outcome, no identities.\n16. Template leftovers removed: FOUND\n17. Attribution and licence line: FOUND - \"Inspired by the Rust Code of Conduct.\"\n18. Help on offer - security, law enforcement, escorts: MISSING - Say what staff will do: contact venue security or law enforcement, provide escorts.\nTeam checks: A team of 3-6 that survives a third away MISSING; No single organizer as sole responder MISSING; Individual contacts for at least two members MISSING; At least one member outside the organizing chain MISSING; Every member's place in the chain stated ok; Every member's conflict declaration recorded ok; On-site hours for every member ok; Responders a reporter can see MISSING; Someone staffs a channel live during the event ok\nMenu 1 - Base-text posture (pick: Adapt plus a culture preamble): 1. Adapt plus a culture preamble [moved by: a values or cultural-identity document already exists (Q8) - the preamble becomes a copy-edit]; 2. Adapt an established text; 3. Adopt one verbatim. Deleted, not demoted: Write your own from scratch (no in-house counsel (Q8) - a from-scratch draft spends a week arriving at the shared list minus whatever it forgets)\nMenu 2 - Reporting channels (pick: Published email alias + Physically identifiable on-site responders + Named conflict-of-interest alternates): 1. Published email alias; 2. Physically identifiable on-site responders; 3. Named conflict-of-interest alternates; 4. Anonymous intake path. Deleted, not demoted: Staffed phone or SMS hotline (no budget for outside help and no phone line given (Q7) - nobody can staff it)\nMenu 3 - Response-team staffing (pick: A named, published team of 3-6): 1. A named, published team of 3-6. Deleted, not demoted: Route into an umbrella body's incidents team (a voluntary peer network decides no chapter's case unless the members agreed to that in writing (Q3)); An external trust-and-safety contractor (no budget for external help (Q7)); A single named organizer as sole responder (your roster is exactly this - Sam Ortiz alone, and so the most senior person on it: the channel cannot receive the report most likely to need it)\nClock (self-set): immediately, for anything urgent or ongoing - safety first; acknowledge within 1 hour while the event is running, within 24 hours before and after it; the same day, before the event closes; the reporter hears the outcome within 7 days (one week); the event runs 1 day. Bands: PyCon US (the leads meet within 24 hours for non-urgent reports and follow up with the reporter within one week) does not fit - a 24-hour meeting lands after a one-day event has closed; Aurora and Gardiner (24 hours to acknowledgment and 10 business days to a decision, written for online communities) does not fit - 10 business days runs past a 1-day event. Stated in the policy: none\nLadder (6 rungs, in order): 1. Warning - appeal no - inappropriate or unwelcome behaviour, a first instance - any staff member may give one; 2. Separation requirement - no contact with the reporter for the rest of the event - appeal no - behaviour aimed at one person; an interim measure alongside another response, never the whole response; 3. Revocation of speaker privileges - appeal no - a talk or a speaker breaks the policy - the rung a conference specifically needs; 4. Ejection from the event, without refund - appeal no - a serious single offence, continuing after being told to stop, or repeated warnings; 5. Ban from future editions, time-boxed - appeal yes - a serious violation or a pattern; the notice states the duration; 6. Permanent ban - appeal yes - a pattern of violation, sustained harassment, or aggression. Outside the ladder: no violation found. Trimmed: Removal of volunteer or staff privileges (no volunteers are bound (Q2))\nAppeal route: Ban from future editions, time-boxed and Permanent ban; to a named person outside the response team who did not decide the original case (to be named) - never the organizing team rehearing itself; in writing, by email with [Appeal] in the subject line and the evidence attached; within 14 days of the written notice (self-set)\nPass threshold (self-set): every report acknowledged inside the published window, and every reporter told the outcome before the published follow-up deadline. Rehearse 2 or 3 practice cases before doors open.\nFindings (25):\n[fix] size (team): A team of 1 cannot lose a third (1) and still have the two people a decision needs - name 3 to 6.\n[fix] sole (team): Sam Ortiz is the only responder and so the most senior person on it - the deleted rung: the channel cannot receive the one report most likely to need it, and one person deciding alone at 2am is not a process.\n[fix] contacts (team): 1 member with a published contact - publish individual contacts for at least two, so a report about one member has somewhere else to go.\n[fix] outside (team): Nobody sits outside the organizing chain - a report about the team itself has nowhere to go.\n[fix] p_behaviours (policy): Prohibited behaviour, enumerated: Missing from the standard list: sexual or violent imagery and language, intimidation, stalking, following or doxxing, harassing photography or recording, sustained disruption of talks and events and inappropriate physical contact and unwelcome sexual attention.\n[fix] p_spaces (policy): Scope - which spaces (venue, online, social, unofficial): Not named: the venue, social events and online channels. Transport is easy to forget too.\n[fix] p_contacts (policy): Named individual contacts (a path for a report about the team): Publish individual contacts for at least two people, one of them outside the organizing chain.\n[fix] p_confidential (policy): Two-part confidentiality - the report, and the reporter's identity: Promise both: reports are confidential, and the reporter's identity stays confidential unless they say otherwise.\n[fix] p_clock (policy): A published response clock, in hours and days: No response clock - set one in hours and days and publish it.\n[check] visible (team): A physical day needs responders in visually distinctive clothing - name the identifier and say it in the opening announcement.\n[check] p_pledge (policy): Pledge - a harassment-free event, and for whom: Open with the commitment to a harassment-free event and who it covers.\n[check] p_people (policy): Scope - which people (sponsors and booth staff by name): Sponsors and booth staff are not named - every sourced event policy names them. Bound but not named: speakers.\n[check] p_dates (policy): Scope - which dates: Say which dates the policy covers.\n[check] p_offsite (policy): Scope - conduct outside the event: Take a position on conduct outside the event - the practitioner stance acts inside your spaces on evidence from outside them.\n[check] p_responders (policy): How to find a responder on site: Say how a reporter physically finds a responder - distinctive clothing, named in the opening announcement.\n[check] p_sanctions (policy): The sanctions, listed: Publish the consequences before the first incident.\n[check] p_appeals (policy): Which rungs carry an appeal: No appeal route - decide which rungs carry one and say so.\n[check] p_transparency (policy): A transparency report for the edition: Commit to a report per edition: counts per rung, time to acknowledgment and outcome, no identities.\n[check] p_safety (policy): Help on offer - security, law enforcement, escorts: Say what staff will do: contact venue security or law enforcement, provide escorts.\n[info] peer (event): Peer network: treat this chapter as a single-organizer event - it owns its policy, its response team and its sanctions. A manifesto of values is not a policy, and the network decides no case unless the members agreed to that in writing.\n[info] not_legal (event): Not legal advice: contract wording goes to counsel; retention, access and deletion of incident records to whoever holds the privacy obligations; anything involving a crime, a minor or an imminent physical threat goes to emergency services and counsel first, this process second.\n[info] p_anonymous (policy): An anonymous intake path: No anonymous path - the reports the other channels never receive.\n[info] clock (clock): Proposed clock (self-set, between the two published bands): immediately, for anything urgent or ongoing - safety first; acknowledge within 1 hour while the event is running, within 24 hours before and after it; the same day, before the event closes; the reporter hears the outcome within 7 days (one week).\n[info] appeal_asym (ladder): Appeals follow the MLH asymmetry: only ban from future editions, time-boxed and permanent ban carry one; the lighter rungs are over before an appeal could be heard.\n[info] records (ladder): Keep every sanction with its rung and reason across editions - a repeat offence moves up the ladder only when someone can see it is a repeat."
}
Reply:
{
"task": "audit",
"summary": "No pipeline yet: Sam Ortiz is the only responder, which is the deleted rung - name at least 2 more people, one outside the organizing chain, before publishing anything.",
"disclaimer": "This is not legal advice; anything involving a crime, a minor or an imminent threat goes to emergency services and counsel first, and this process second.",
"verdict": "no pipeline - do not publish yet",
"sections": [
{
"item": "Pledge - a harassment-free event, and for whom",
"status": "missing",
"fix": "Open with the commitment to a harassment-free meetup and who it covers.",
"wording": "The Brickfield Rust Meetup is dedicated to a harassment-free experience for everyone who attends, speaks or helps run it. (own design)"
},
{
"item": "Prohibited behaviour, enumerated",
"status": "missing",
"fix": "Carry the standard list, not only offensive comments, so a reporter can see their case named.",
"wording": "Harassment includes offensive comments about the characteristics above, sexual or violent imagery and language, intimidation, stalking or following, harassing photography or recording, sustained disruption of talks, inappropriate physical contact and unwelcome sexual attention. (own design)"
},
{
"item": "Scope - which people (sponsors and booth staff by name)",
"status": "partial",
"fix": "Name speakers and organizers, and sponsors if the meetup ever takes sponsorship, not only everyone in general.",
"wording": "This applies to everyone at the meetup: attendees, speakers, organizers and hosts, and any sponsor's staff. (own design)"
},
{
"item": "Scope - which spaces (venue, online, social, unofficial)",
"status": "missing",
"fix": "Name the venue, the drinks or social time after talks, and the online chat the meetup runs.",
"wording": "It covers the meetup venue, any social time after the talks, and the meetup's online chat. (own design)"
},
{
"item": "Scope - which dates",
"status": "missing",
"fix": "Say which dates the policy covers, including the online chat before and after each meetup.",
"wording": "It applies on meetup evenings and in the meetup chat at all times. (own design)"
},
{
"item": "Scope - conduct outside the event",
"status": "missing",
"fix": "Take a position on conduct outside the meetup: act inside your own spaces on evidence of it.",
"wording": "We may act inside our meetup and chat on evidence of conduct elsewhere, without claiming jurisdiction over it. (own design)"
},
{
"item": "Reporting channel - a working alias or line",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Named individual contacts (a path for a report about the team)",
"status": "partial",
"fix": "Only one personal address is listed; publish contacts for at least two people, one outside the organizing chain, so a report about the organizer has somewhere to go.",
"wording": "You can also contact our independent alternate (to be named) directly. (own design)"
},
{
"item": "An anonymous intake path",
"status": "missing",
"fix": "Optional for now - no power gradient was named - but it is the path for reports the other channels never receive.",
"wording": ""
},
{
"item": "How to find a responder on site",
"status": "missing",
"fix": "Say how someone in the room finds a responder, and give responders something visible to wear.",
"wording": "Responders wear (identifier to be named) and are introduced at the start of each meetup. (own design)"
},
{
"item": "Two-part confidentiality - the report, and the reporter's identity",
"status": "missing",
"fix": "Promise both parts: the report is confidential, and so is the reporter's identity unless they say otherwise.",
"wording": "Reports are kept confidential, and we never share who made a report without that person's permission. (own design)"
},
{
"item": "A published response clock, in hours and days",
"status": "missing",
"fix": "Publish a clock that fits a one-evening meetup.",
"wording": "We act immediately on anything urgent, acknowledge every report within 1 hour during the meetup and within 24 hours otherwise, and tell the reporter the outcome within one week. (own design)"
},
{
"item": "The sanctions, listed",
"status": "partial",
"fix": "Asking someone to leave is the only consequence named; publish the ladder before the first incident.",
"wording": "Depending on the behaviour, organizers may give a warning, require no contact for the rest of the evening, remove a talk, ask the person to leave, or bar them from future meetups. (own design)"
},
{
"item": "Which rungs carry an appeal",
"status": "missing",
"fix": "Say that only a bar from future meetups can be appealed, to whom and by when.",
"wording": "Only a bar from future meetups can be appealed, in writing with [Appeal] in the subject line, within 14 days, to someone outside the response team (to be named). (own design)"
},
{
"item": "A transparency report for the edition",
"status": "missing",
"fix": "Commit to a short yearly note on reports and outcomes.",
"wording": "Once a year we publish how many reports we received and what came of them, without names. (own design)"
},
{
"item": "Template leftovers removed",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Attribution and licence line",
"status": "found",
"fix": "",
"wording": ""
},
{
"item": "Help on offer - security, law enforcement, escorts",
"status": "missing",
"fix": "Say what responders will do: contact venue security or law enforcement, or arrange a safe way home.",
"wording": "Responders will help you contact venue security or local law enforcement, or arrange an escort. (own design)"
}
],
"posture": {
"pick": "Adapt plus a culture preamble",
"reason": "The chapter already has a values document, which turns the preamble into a copy-edit and moved it to the top."
},
"channels": {
"picks": [
"Published email alias",
"Physically identifiable on-site responders",
"Named conflict-of-interest alternates"
],
"reason": "No power gradient was named, so the anonymous path stays unpromoted; the hotline is deleted because there is no budget and no line to staff."
},
"staffing": {
"pick": "A named, published team of 3-6",
"reason": "A single organizer as sole responder is deleted, the peer network decides no chapter's case, and there is no budget for a contractor - so the chapter names its own team of at least 3."
},
"clock": {
"acknowledge": "within 1 hour while the event is running, within 24 hours before and after it",
"decide": "the same day, before the event closes",
"follow_up": "the reporter hears the outcome within 7 days (one week)",
"note": "This clock is self-set: neither published band fits a 1-day meetup, so it runs tighter than the PyCon US band."
},
"ladder": [
{
"rung": "Warning",
"appealable": false,
"when": "inappropriate or unwelcome behaviour, a first instance"
},
{
"rung": "Separation requirement - no contact with the reporter for the rest of the event",
"appealable": false,
"when": "behaviour aimed at one person, alongside another response"
},
{
"rung": "Revocation of speaker privileges",
"appealable": false,
"when": "a talk or a speaker breaks the policy"
},
{
"rung": "Ejection from the event, without refund",
"appealable": false,
"when": "a serious single offence or continuing after being told to stop"
},
{
"rung": "Ban from future editions, time-boxed",
"appealable": true,
"when": "a serious violation or a pattern, with the duration stated"
},
{
"rung": "Permanent ban",
"appealable": true,
"when": "a pattern of violation, sustained harassment, or aggression"
}
],
"appeal": "Only the time-boxed and permanent bans carry an appeal - in writing, by email with [Appeal] in the subject line and the evidence attached, within 14 days of the written notice, to a named person outside the response team who did not decide the case (to be named).",
"rehearsal": [
{
"case": "A first-time attendee tells a regular, mid-talk, that someone keeps sitting next to them and touching their arm.",
"practice": "Stopping the behaviour calmly, intake away from the room, and who decides once there is a team of at least 3."
},
{
"case": "Someone emails a report about Sam Ortiz, the organizer.",
"practice": "Where a report about the organizer goes, and the outside alternate deciding without Sam Ortiz."
}
],
"transparency": "Once a year, publish the number of reports and how many reached each rung, with no names and no incident details.",
"caveats": [
"Sam Ortiz is the only responder - the deleted rung; name a team of at least 3 with someone outside the organizing chain.",
"Publish individual contacts for at least two people so a report about the organizer has somewhere to go.",
"Add the standard behaviour list and name the venue, social time and online chat in the scope.",
"Add the two-part confidentiality promise and a published response clock.",
"As a chapter of a peer network, this meetup owns its policy, its team and its sanctions - the network will not decide its cases."
]
}
The page's check: kept - The page has 9 fix-level findings; the caveats carry 5.
Brickfield Rust Meetup (45, one organizer) - runbook: not offered - name at least two responders - the sole-responder rung is deleted, and a runbook needs a team.
The free reporting card for the second sample
# Northwind Data Summit - how to report a code of conduct concern
**If anyone is in immediate danger, call 911 first - then find a responder.**
- Email: conduct@northwind-summit.org
- Find a responder: bright orange SAFETY shirts
- Anonymous: the anonymous form in the event app
- Quiet room: Room 2.14, level 2 of the main venue
## Responders
- Dana Whitfield - founder and conference chair - dana@northwind-summit.org - 08:00-18:00 all three days
- Luis Moreno - incident response lead - luis@northwind-summit.org - 08:00-20:00 all three days
- Aiko Tanaka - operations director - aiko@northwind-summit.org - 07:30-18:00 all three days
- Grace Mensah - independent alternate, Community Safety Collective - grace@safetycollective.org - on call all three days
## What happens next
As the policy states: within 24 hours; within one week.
Reports are confidential, and so is who made them unless you tell us otherwise.
_Not legal advice._
Build the input yourself
Load the engine in node (global.window = global; require("./conductkit.js"); require("./conductreply.js")), then:
const K = ConductKit, R = ConductReply;
const f = K.form({ name: "My Conf", format: "multi", startDate: "2027-05-20", endDate: "2027-05-21", bSponsors: "yes", liveStaff: "yes",
roster: fs.readFileSync("team.txt", "utf8"), policy: fs.readFileSync("coc.md", "utf8") });
// f.policy.items (label, status, excerpt, note), f.team, f.pipe, f.menus (posture, channels, staffing: options, deleted, picks)
// f.clock, f.ladder (label, appeal), f.appeal, f.verdict, f.findings, f.card
K.cardMd(f) // the printable reporting card as Markdown
const b = K.buildInput(f, "audit"); // or "runbook" (needs two named responders)
const wire = K.toWire(b.input); // POST this to /estimate and /run
// then: const reply = R.normalize(R.parseReply(job.output.output), "audit");
// R.check(reply, b) // {status: kept or flagged, notes}
Get a token for the steps below from /tokens.html.
Step 1 — a tiny client helper
One function that sends JSON and unwraps the response. Paste a personal token from /tokens.html, or leave it empty and mint a guest token in step 2.
BASE="https://api.skillsafe.ai/v1/app-api"
TOKEN="YOUR_TOKEN" # from https://conduct-desk.skillsafe.ai/tokens.html
api() { # api METHOD PATH [JSON-BODY]
curl -s -X "$1" "$BASE$2" -H "Content-Type: application/json" \
${TOKEN:+-H "Authorization: Bearer $TOKEN"} ${3:+--data "$3"}
}
import json, urllib.request
BASE = "https://api.skillsafe.ai/v1/app-api"
TOKEN = "YOUR_TOKEN" # from https://conduct-desk.skillsafe.ai/tokens.html
def api(method, path, body=None, headers=None):
req = urllib.request.Request(BASE + path, method=method,
data=None if body is None else json.dumps(body).encode(),
headers={"Content-Type": "application/json", **({"Authorization": "Bearer " + TOKEN} if TOKEN else {}), **(headers or {})})
with urllib.request.urlopen(req) as r:
env = json.load(r)
if env.get("error"):
raise RuntimeError(env["error"])
return env["data"]
// conduct-desk.mjs -- Node 18+ (global fetch)
const BASE = "https://api.skillsafe.ai/v1/app-api";
let TOKEN = "YOUR_TOKEN"; // from https://conduct-desk.skillsafe.ai/tokens.html
async function api(method, path, body, headers = {}) {
const r = await fetch(BASE + path, { method, headers: { "Content-Type": "application/json",
...(TOKEN ? { Authorization: "Bearer " + TOKEN } : {}), ...headers },
body: body === undefined ? undefined : JSON.stringify(body) });
const env = await r.json();
if (env.error) throw new Error(env.error.code + ": " + env.error.message);
return env.data;
}
package main
import ("bytes"; "encoding/json"; "fmt"; "net/http")
const base = "https://api.skillsafe.ai/v1/app-api"
var token = "YOUR_TOKEN" // from https://conduct-desk.skillsafe.ai/tokens.html
func api(method, path string, body any, headers map[string]string) (map[string]any, error) {
var buf bytes.Buffer
if body != nil { json.NewEncoder(&buf).Encode(body) }
req, _ := http.NewRequest(method, base+path, &buf)
req.Header.Set("Content-Type", "application/json")
if token != "" { req.Header.Set("Authorization", "Bearer "+token) }
for k, v := range headers { req.Header.Set(k, v) }
res, err := http.DefaultClient.Do(req)
if err != nil { return nil, err }
defer res.Body.Close()
var env struct { Data map[string]any; Error map[string]any }
json.NewDecoder(res.Body).Decode(&env)
if env.Error != nil { return nil, fmt.Errorf("%v", env.Error) }
return env.Data, nil
}
// ConductDesk.java -- Java 17+, with com.fasterxml.jackson.core:jackson-databind
import com.fasterxml.jackson.databind.*;
import java.net.URI; import java.net.http.*; import java.util.*;
public class ConductDesk {
static final String BASE = "https://api.skillsafe.ai/v1/app-api";
static String token = "YOUR_TOKEN"; // from https://conduct-desk.skillsafe.ai/tokens.html
static final ObjectMapper M = new ObjectMapper();
static final HttpClient C = HttpClient.newHttpClient();
static JsonNode api(String method, String path, Object body, Map<String, String> headers) throws Exception {
var b = HttpRequest.newBuilder(URI.create(BASE + path)).header("Content-Type", "application/json");
if (!token.isEmpty()) b.header("Authorization", "Bearer " + token);
if (headers != null) headers.forEach(b::header);
b.method(method, body == null ? HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofString(M.writeValueAsString(body)));
JsonNode env = M.readTree(C.send(b.build(), HttpResponse.BodyHandlers.ofString()).body());
if (env.hasNonNull("error")) throw new RuntimeException(env.get("error").toString());
return env.get("data");
}
}
require "json"
require "net/http"
BASE = "https://api.skillsafe.ai/v1/app-api"
TOKEN = "YOUR_TOKEN" # from https://conduct-desk.skillsafe.ai/tokens.html
def api(method, path, body = nil, headers = {})
uri = URI(BASE + path)
req = Net::HTTPGenericRequest.new(method, !body.nil?, true, uri.request_uri,
{ "Content-Type" => "application/json" }.merge(TOKEN.empty? ? {} : { "Authorization" => "Bearer #{TOKEN}" }).merge(headers))
req.body = JSON.generate(body) unless body.nil?
env = JSON.parse(Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }.body)
raise env["error"].to_s if env["error"]
env["data"]
end
<?php
const BASE = "https://api.skillsafe.ai/v1/app-api";
$TOKEN = "YOUR_TOKEN"; // from https://conduct-desk.skillsafe.ai/tokens.html
function api(string $method, string $path, $body = null, array $headers = []) {
global $TOKEN;
$h = ["Content-Type: application/json"];
if ($TOKEN) $h[] = "Authorization: Bearer $TOKEN";
foreach ($headers as $k => $v) $h[] = "$k: $v";
$ch = curl_init(BASE . $path);
curl_setopt_array($ch, [CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => $h, CURLOPT_RETURNTRANSFER => true]);
if ($body !== null) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
$env = json_decode(curl_exec($ch), true);
if (!empty($env["error"])) throw new Exception(json_encode($env["error"]));
return $env["data"];
}
// Program.cs -- .NET 6+ console app
using System.Net.Http.Json; using System.Text.Json; using System.Text.Json.Nodes;
static class Api {
public const string Base = "https://api.skillsafe.ai/v1/app-api";
public static string Token = "YOUR_TOKEN"; // from https://conduct-desk.skillsafe.ai/tokens.html
static readonly HttpClient C = new();
public static async Task<JsonNode?> Call(string method, string path, object? body = null, Dictionary<string, string>? headers = null) {
var req = new HttpRequestMessage(new HttpMethod(method), Base + path);
if (Token != "") req.Headers.Add("Authorization", "Bearer " + Token);
if (headers != null) foreach (var h in headers) req.Headers.Add(h.Key, h.Value);
if (body != null) req.Content = JsonContent.Create(body);
var env = JsonNode.Parse(await (await C.SendAsync(req)).Content.ReadAsStringAsync())!;
if (env["error"] is JsonNode e && e.GetValueKind() != JsonValueKind.Null) throw new Exception(e.ToJsonString());
return env["data"];
}
}
Step 2 — a token
A guest token is enough for /me and /estimate. A run is metered, so it needs a personal token: sign in on /tokens.html and copy it from there.
# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN=$(curl -s -X POST "$BASE/guest" -H "Content-Type: application/json" -d '{"slug":"conduct-desk"}' | jq -r '.data.token')
# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN = ""
TOKEN = api("POST", "/guest", {"slug": "conduct-desk"})["token"]
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN = "";
TOKEN = (await api("POST", "/guest", { slug: "conduct-desk" })).token;
// inside main: a guest token (enough for /me and /estimate); a run needs your personal token
token = ""
g, err := api("POST", "/guest", map[string]string{"slug": "conduct-desk"}, nil)
if err != nil { panic(err) }
token = g["token"].(string)
// inside main: a guest token (enough for /me and /estimate); a run needs your personal token
token = "";
token = api("POST", "/guest", Map.of("slug", "conduct-desk"), null).get("token").asText();
# a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
TOKEN.replace("")
TOKEN.replace(api("POST", "/guest", { slug: "conduct-desk" })["token"])
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
$TOKEN = "";
$TOKEN = api("POST", "/guest", ["slug" => "conduct-desk"])["token"];
// a guest token (enough for /me and /estimate); a run needs your personal token from /tokens.html
Api.Token = "";
Api.Token = (await Api.Call("POST", "/guest", new { slug = "conduct-desk" }))!["token"]!.GetValue<string>();
Step 3 — GET /me
Who the token is (subject_type: user or guest) and the credit balance.
api GET /me | jq '.data | {subject_type, credits}'
me = api("GET", "/me")
print(me["subject_type"], me.get("credits"))
const me = await api("GET", "/me");
console.log(me.subject_type, me.credits);
me, _ := api("GET", "/me", nil, nil)
fmt.Println(me["subject_type"], me["credits"])
JsonNode me = api("GET", "/me", null, null);
System.out.println(me.get("subject_type") + " " + me.get("credits"));
me = api("GET", "/me")
puts [me["subject_type"], me["credits"]].inspect
$me = api("GET", "/me");
echo $me["subject_type"], " ", $me["credits"] ?? "", "\n";
var me = await Api.Call("GET", "/me");
Console.WriteLine($"{me!["subject_type"]} {me["credits"]}");
Step 4 — POST /estimate
Free. The body is the run input itself, the bare object (never wrapped in {"input": ...}). hold_credits is a reservation, not the price; min_credits is what the balance must cover; model_alias reads gpt-terra.
# input.json: the run input object - {"task": "audit", "event": "Event: ...; a multi-day conference ...", "roster": "Response team (4), as entered ...", "policy": "the code of conduct text", "facts": "Verdict: ..."}
# - see the input table
api POST /estimate "$(cat input.json)" | jq '.data | {hold_credits, min_credits, model, model_alias, markup_bps, warnings}'
inp = json.load(open("input.json")) # {"task": "audit", "event": "Event: ...; a multi-day conference ...", "roster": "Response team (4), as entered ...", "policy": "the code of conduct text", "facts": "Verdict: ..."}
# - see the input table
est = api("POST", "/estimate", inp)
print(est["hold_credits"], est["min_credits"], est["model"], est.get("warnings"))
import { readFileSync } from "node:fs";
const input = JSON.parse(readFileSync("input.json", "utf8")); // {task: "audit" or "runbook", event, roster, policy, facts} (see the input table)
const est = await api("POST", "/estimate", input);
console.log(est.hold_credits, est.min_credits, est.model, est.warnings);
raw, _ := os.ReadFile("input.json") // add "os" to the imports
var input map[string]any
json.Unmarshal(raw, &input)
est, _ := api("POST", "/estimate", input, nil)
fmt.Println(est["hold_credits"], est["min_credits"], est["model"])
Map<String, Object> input = M.readValue(new java.io.File("input.json"), Map.class);
JsonNode est = api("POST", "/estimate", input, null);
System.out.println(est.get("hold_credits") + " " + est.get("min_credits") + " " + est.get("model"));
input = JSON.parse(File.read("input.json"))
est = api("POST", "/estimate", input)
puts [est["hold_credits"], est["min_credits"], est["model"]].inspect
$input = json_decode(file_get_contents("input.json"), true);
$est = api("POST", "/estimate", $input);
echo $est["hold_credits"], " ", $est["min_credits"], " ", $est["model"], "\n";
var input = JsonNode.Parse(File.ReadAllText("input.json"))!;
var est = await Api.Call("POST", "/estimate", input);
Console.WriteLine($"{est!["hold_credits"]} {est["min_credits"]} {est["model"]}");
Step 5 — POST /run, then poll the job
Send an Idempotency-Key built from the lane and the input: a retry with the same key never bills twice. The page uses conduct-desk:<task>:<inputHash>:a<attempt> - the lane is part of the key - and its one automatic reformat retry is a new attempt number, named in the page as one extra run. An audit carries summary, disclaimer, verdict, sections, posture, channels, staffing, clock, ladder, appeal, rehearsal, transparency and caveats; a runbook carries title, disclaimer, safety, intake, never, capture, recusal, escalation, decision, notification, closure, clock, staff, contacts and note. The code below prints the headline of either.
KEY="conduct-desk:audit:$(shasum -a 256 input.json | cut -c1-16):a1"
JOB=$(curl -s -X POST "$BASE/run" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $KEY" --data @input.json | jq -r '.data.job_id')
while :; do
J=$(api GET "/jobs/$JOB"); S=$(echo "$J" | jq -r '.data.status')
case "$S" in succeeded|failed|cancelled) break;; esac; sleep 2
done
echo "$J" | jq -r '.data.output.output' > reply.json # one JSON object, the reply contract
echo "$J" | jq '.data | {charged_credits, truncated}'
jq -r '.verdict // .title, .summary // .disclaimer' reply.json
jq -r '(.caveats // .intake)[]' reply.json # the audit's caveats, or the runbook's intake script
import hashlib, time
key = "conduct-desk:" + inp["task"] + ":" + hashlib.sha256(json.dumps(inp).encode()).hexdigest()[:16] + ":a1"
job = api("POST", "/run", inp, {"Idempotency-Key": key})
while True:
j = api("GET", "/jobs/" + job["job_id"])
if j["status"] in ("succeeded", "failed", "cancelled"):
break
time.sleep(2)
reply = json.loads(j["output"]["output"]) # the reply as one JSON object
print(j["charged_credits"], j.get("truncated"), reply.get("verdict") or reply.get("title"))
print(reply.get("summary") or reply.get("disclaimer", ""))
for line in reply.get("caveats") or reply.get("intake") or []:
print("-", line)
import { createHash } from "node:crypto";
const key = `conduct-desk:${input.task}:${createHash("sha256").update(JSON.stringify(input)).digest("hex").slice(0, 16)}:a1`;
const job = await api("POST", "/run", input, { "Idempotency-Key": key });
let j;
do { await new Promise((r) => setTimeout(r, 2000)); j = await api("GET", "/jobs/" + job.job_id); }
while (!["succeeded", "failed", "cancelled"].includes(j.status));
const reply = JSON.parse(j.output.output);
console.log(j.charged_credits, j.truncated, reply.verdict ?? reply.title);
console.log(reply.summary ?? reply.disclaimer);
for (const line of reply.caveats || reply.intake || []) console.log("-", line);
sum := sha256.Sum256(raw) // add "crypto/sha256", "encoding/hex", "time" to the imports
key := "conduct-desk:" + input["task"].(string) + ":" + hex.EncodeToString(sum[:8]) + ":a1"
job, _ := api("POST", "/run", input, map[string]string{"Idempotency-Key": key})
var j map[string]any
for {
time.Sleep(2 * time.Second)
j, _ = api("GET", "/jobs/"+job["job_id"].(string), nil, nil)
if s := j["status"]; s == "succeeded" || s == "failed" || s == "cancelled" { break }
}
var reply map[string]any
json.Unmarshal([]byte(j["output"].(map[string]any)["output"].(string)), &reply)
fmt.Println(j["charged_credits"], j["truncated"], reply["verdict"], reply["title"])
fmt.Println(reply["summary"], reply["disclaimer"])
items, _ := reply["caveats"].([]any) // the audit's caveats are plain strings
if items == nil { items, _ = reply["intake"].([]any) } // or the runbook's intake script
for _, x := range items {
fmt.Println("-", x)
}
var digest = java.security.MessageDigest.getInstance("SHA-256").digest(M.writeValueAsBytes(input));
String key = "conduct-desk:" + input.get("task") + ":" + HexFormat.of().formatHex(digest, 0, 8) + ":a1";
JsonNode job = api("POST", "/run", input, Map.of("Idempotency-Key", key)), j;
do { Thread.sleep(2000); j = api("GET", "/jobs/" + job.get("job_id").asText(), null, null); }
while (!Set.of("succeeded", "failed", "cancelled").contains(j.get("status").asText()));
JsonNode reply = M.readTree(j.get("output").get("output").asText());
System.out.println(j.get("charged_credits") + " " + reply.path("verdict").asText(reply.path("title").asText()));
System.out.println(reply.path("summary").asText(reply.path("disclaimer").asText()));
for (JsonNode s : reply.has("caveats") ? reply.path("caveats") : reply.path("intake")) System.out.println("- " + s.asText());
require "digest"
key = "conduct-desk:#{input["task"]}:#{Digest::SHA256.hexdigest(JSON.generate(input))[0, 16]}:a1"
job = api("POST", "/run", input, { "Idempotency-Key" => key })
j = nil
loop do
sleep 2
j = api("GET", "/jobs/#{job["job_id"]}")
break if %w[succeeded failed cancelled].include?(j["status"])
end
reply = JSON.parse(j["output"]["output"])
puts [j["charged_credits"], j["truncated"], reply["verdict"] || reply["title"]].inspect
puts reply["summary"] || reply["disclaimer"]
(reply["caveats"] || reply["intake"] || []).each { |s| puts "- #{s}" }
$key = "conduct-desk:" . $input["task"] . ":" . substr(hash("sha256", json_encode($input)), 0, 16) . ":a1";
$job = api("POST", "/run", $input, ["Idempotency-Key" => $key]);
do { sleep(2); $j = api("GET", "/jobs/" . $job["job_id"]); }
while (!in_array($j["status"], ["succeeded", "failed", "cancelled"]));
$reply = json_decode($j["output"]["output"], true);
echo $j["charged_credits"], " ", ($reply["verdict"] ?? $reply["title"] ?? ""), "\n";
echo $reply["summary"] ?? $reply["disclaimer"] ?? "", "\n";
foreach ($reply["caveats"] ?? $reply["intake"] ?? [] as $s) echo "- ", $s, "\n";
var digest = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(input.ToJsonString()));
var key = $"conduct-desk:{input["task"]}:{Convert.ToHexString(digest, 0, 8).ToLowerInvariant()}:a1";
var job = await Api.Call("POST", "/run", input, new() { ["Idempotency-Key"] = key });
JsonNode j;
do { await Task.Delay(2000); j = (await Api.Call("GET", "/jobs/" + job!["job_id"]))!; }
while (!new[] { "succeeded", "failed", "cancelled" }.Contains(j["status"]!.GetValue<string>()));
var reply = JsonNode.Parse(j["output"]!["output"]!.GetValue<string>());
Console.WriteLine($"{j["charged_credits"]} {reply!["verdict"] ?? reply["title"]}");
Console.WriteLine($"{reply["summary"] ?? reply["disclaimer"]}");
foreach (var s in (reply["caveats"] ?? reply["intake"]) as JsonArray ?? new JsonArray()) Console.WriteLine("- " + s);
Step 6 — POST /run-stream
The same run as Server-Sent Events, with the same input.json. Browsers receive progress ticks rather than text deltas; the final done event carries the reply.
# Server-Sent Events: tick/delta events while the job runs, then a final event with the job
curl -N -s -X POST "$BASE/run-stream" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: conduct-desk:audit:$(shasum -a 256 input.json | cut -c1-16):a1" --data @input.json
rev = json.load(open("input.json")) # the same run input as input.json: {"task": "audit", "event": "Event: ...; a multi-day conference ...", "roster": "Response team (4), as entered ...", "policy": "the code of conduct text", "facts": "Verdict: ..."}
# - see the input table
req = urllib.request.Request(BASE + "/run-stream", method="POST", data=json.dumps(rev).encode(),
headers={"Content-Type": "application/json", "Authorization": "Bearer " + TOKEN,
"Idempotency-Key": "conduct-desk:audit:" + hashlib.sha256(json.dumps(rev).encode()).hexdigest()[:16] + ":a1"})
with urllib.request.urlopen(req) as r:
for line in r:
line = line.decode().strip()
if line.startswith("data:"):
print(line[5:].strip()[:200])
const rev = JSON.parse(readFileSync("input.json", "utf8"));
const r = await fetch(BASE + "/run-stream", { method: "POST", body: JSON.stringify(rev), headers: {
"Content-Type": "application/json", Authorization: "Bearer " + TOKEN,
"Idempotency-Key": `conduct-desk:audit:${createHash("sha256").update(JSON.stringify(rev)).digest("hex").slice(0, 16)}:a1` } });
const dec = new TextDecoder();
for await (const chunk of r.body) for (const line of dec.decode(chunk).split("\n"))
if (line.startsWith("data:")) console.log(line.slice(5).trim().slice(0, 200));
rraw, _ := os.ReadFile("input.json") // add "bufio", "strings" to the imports
rs := sha256.Sum256(rraw)
req, _ := http.NewRequest("POST", base+"/run-stream", bytes.NewReader(rraw))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Idempotency-Key", "conduct-desk:audit:"+hex.EncodeToString(rs[:8])+":a1")
res, _ := http.DefaultClient.Do(req)
sc := bufio.NewScanner(res.Body)
for sc.Scan() { if l := sc.Text(); strings.HasPrefix(l, "data:") { fmt.Println(l[5:]) } }
String rev = java.nio.file.Files.readString(java.nio.file.Path.of("input.json"));
var rd = java.security.MessageDigest.getInstance("SHA-256").digest(rev.getBytes());
var sreq = HttpRequest.newBuilder(URI.create(BASE + "/run-stream")).header("Content-Type", "application/json")
.header("Authorization", "Bearer " + token).header("Idempotency-Key", "conduct-desk:audit:" + HexFormat.of().formatHex(rd, 0, 8) + ":a1")
.POST(HttpRequest.BodyPublishers.ofString(rev)).build();
C.send(sreq, HttpResponse.BodyHandlers.ofLines()).body().filter(l -> l.startsWith("data:")).forEach(System.out::println);
rev = File.read("input.json")
uri = URI(BASE + "/run-stream")
req = Net::HTTP::Post.new(uri, "Content-Type" => "application/json", "Authorization" => "Bearer #{TOKEN}",
"Idempotency-Key" => "conduct-desk:audit:#{Digest::SHA256.hexdigest(rev)[0, 16]}:a1")
req.body = rev
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |h|
h.request(req) { |res| res.read_body { |chunk| chunk.each_line { |l| puts l if l.start_with?("data:") } } }
end
$rev = file_get_contents("input.json");
$ch = curl_init(BASE . "/run-stream");
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_POSTFIELDS => $rev, CURLOPT_HTTPHEADER => [
"Content-Type: application/json", "Authorization: Bearer $TOKEN",
"Idempotency-Key: conduct-desk:audit:" . substr(hash("sha256", $rev), 0, 16) . ":a1"],
CURLOPT_WRITEFUNCTION => function ($ch, $chunk) { foreach (explode("\n", $chunk) as $l) if (str_starts_with($l, "data:")) echo $l, "\n"; return strlen($chunk); }]);
curl_exec($ch);
var rev = File.ReadAllText("input.json");
var rd = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(rev));
var sreq = new HttpRequestMessage(HttpMethod.Post, Api.Base + "/run-stream") { Content = new StringContent(rev, System.Text.Encoding.UTF8, "application/json") };
sreq.Headers.Add("Authorization", "Bearer " + Api.Token);
sreq.Headers.Add("Idempotency-Key", $"conduct-desk:audit:{Convert.ToHexString(rd, 0, 8).ToLowerInvariant()}:a1");
using var http = new HttpClient();
using var res = await http.SendAsync(sreq, HttpCompletionOption.ResponseHeadersRead);
using var rdr = new StreamReader(await res.Content.ReadAsStreamAsync());
for (string? l; (l = await rdr.ReadLineAsync()) != null;) if (l.StartsWith("data:")) Console.WriteLine(l);