Watch
2
design: default-headless intake + tri-role relabel-down discipline #619
Closed
opened 2026-07-06 16:58:20 +00:00 by coilysiren
·
3 comments
No Branch/Tag specified
main
release
docs/readme-agents-surface
fix/pr-repair-verb-lookup
aos/claude/aw85-docs-bands
aos/claude/aw85-declare-band
aos/claude/bk79-autonomy-label-scope
fix/gofmt-runner
chore/umbra-rename
aos/claude/mg96-fm
claude/agents-temp-clone-note
aos/claude/qa57
remove-format-exec-gate-refusal
fix/ward-1649-ci-fixture
fix/detached-ci-exec
issue-1626-generic-agent-broker
issue-1177
issue-1160
issue-1501
ward-salvage/ward-12486bc7
ward-salvage/ward-babfa2ba
ward-salvage/ward-a832df03
ward-salvage/ward-85c795b2
ward-salvage/ward-b87f8859
issue-1484
ward-salvage/ward-86b72dcf
ward-salvage/ward-b7b26d1d
recovery/2026-07-28-triaged-branch-archive
recovery/2026-07-27-local-work
issue-1584
issue-1571
issue-1524
ward-salvage/ward-3800c2d1
ward-salvage/ward-70175da3
ward-salvage/ward-bcbfef78
issue-1298
issue-737-signoz-deferred
ward-salvage/ward-c6aa5da9
ward-salvage/ward-94dd7346
ward-salvage/ward-58aa3fe3
ward-salvage/ward-ff6c509f
ward-salvage/ward-e80f0460
ward-salvage/ward-3e2e4760
ward-salvage/ward-649addd7
ward-salvage/ward-890e4d29
ward-salvage/ward-645b750b
ward-salvage/ward-bf851a72
ward-salvage/ward-98c8652f
ward-salvage/ward-bb10b620
ward-salvage/ward-1ee9be1c
ward-salvage/ward-d18595f6
ward-salvage/ward-5f914692
ward-salvage/ward-6ca05cbd
ward-salvage/ward-14f676cf
ward-salvage/ward-de811c20
ward-salvage/ward-eba3e824
ward-salvage/ward-16eb4ad0
ward-salvage/ward-c58e9c43
ward-salvage/ward-7487270b
v0.890.0
v0.889.0
v0.888.0
v0.887.0
v0.886.0
v0.885.0
v0.884.0
v0.883.0
v0.882.0
v0.881.0
v0.880.0
v0.879.0
v0.878.0
v0.877.0
v0.876.0
v0.875.0
v0.874.0
v0.873.0
v0.872.0
v0.871.0
v0.870.0
v0.869.0
v0.868.0
v0.867.0
v0.866.0
v0.865.0
v0.864.0
v0.863.0
v0.862.0
v0.861.0
v0.860.0
v0.859.0
v0.858.0
v0.857.0
v0.856.0
v0.855.0
v0.854.0
v0.853.0
v0.852.0
v0.851.0
v0.850.0
v0.849.0
v0.848.0
v0.847.0
v0.846.0
v0.845.0
v0.844.0
v0.843.0
v0.842.0
v0.841.0
v0.840.0
v0.839.0
v0.838.0
v0.837.0
v0.836.0
v0.835.0
v0.834.0
v0.833.0
v0.832.0
v0.830.0
v0.831.0
v0.829.0
v0.828.0
v0.827.0
v0.826.0
v0.825.0
v0.824.0
v0.823.0
v0.822.0
v0.821.0
v0.820.0
v0.819.0
v0.818.0
v0.817.0
v0.816.0
v0.815.0
v0.814.0
v0.813.0
v0.812.0
v0.811.0
v0.810.0
v0.809.0
v0.808.0
v0.807.0
v0.806.0
v0.805.0
v0.804.0
v0.803.0
v0.802.0
v0.801.0
v0.800.0
v0.799.0
v0.798.0
v0.797.0
v0.796.0
v0.795.0
v0.794.0
v0.793.0
v0.792.0
v0.791.0
v0.790.0
v0.789.0
v0.788.0
v0.787.0
v0.786.0
v0.785.0
v0.784.0
v0.783.0
v0.782.0
v0.781.0
v0.780.0
v0.779.0
v0.778.0
v0.777.0
v0.775.0-tmp
v0.776.0
v0.775.0
v0.774.0
v0.773.0
v0.772.0
v0.771.0
v0.770.0
v0.769.0
v0.768.0
v0.767.0
v0.766.0
v0.765.0
v0.764.0
v0.763.0
v0.762.0
v0.761.0
v0.760.0
v0.759.0
v0.758.0
v0.757.0
v0.756.0
v0.755.0
v0.754.0
v0.753.0
v0.752.0
v0.751.0
v0.750.0
v0.749.0
v0.748.0
v0.747.0
v0.746.0
v0.745.0
v0.744.0
v0.743.0
v0.742.0
v0.741.0
v0.740.0
v0.739.0
v0.738.0
v0.737.0
v0.736.0
v0.735.0
v0.734.0
v0.733.0
v0.732.0
v0.731.0
v0.730.0
v0.729.0
v0.728.0
v0.727.0
v0.726.0
v0.725.0
v0.724.0
v0.723.0
v0.722.0
v0.721.0
v0.720.0
v0.719.0
v0.718.0
v0.717.0
v0.716.0
v0.715.0
v0.714.0
v0.713.0
v0.712.0
v0.711.0
v0.710.0
v0.709.0
v0.708.0
v0.707.0
v0.706.0
v0.705.0
v0.704.0
v0.703.0
v0.702.0
v0.701.0
v0.700.0
v0.699.0
v0.698.0
v0.697.0
v0.696.0
v0.695.0
v0.694.0
v0.693.0
v0.692.0
v0.691.0
v0.690.0
v0.689.0
v0.688.0
v0.687.0
v0.686.0
v0.685.0
v0.684.0
v0.683.0
v0.682.0
v0.681.0
v0.680.0
v0.679.0
v0.678.0
v0.677.0
v0.676.0
v0.675.0
v0.674.0
v0.673.0
v0.672.0
v0.671.0
v0.670.0
v0.669.0
v0.668.0
v0.667.0
v0.666.0
v0.665.0
v0.664.0
v0.663.0
v0.662.0
v0.661.0
v0.660.0
v0.659.0
v0.658.0
v0.657.0
v0.656.0
v0.655.0
v0.654.0
v0.653.0
v0.652.0
v0.651.0
v0.650.0
v0.649.0
v0.648.0
v0.647.0
v0.646.0
v0.645.0
v0.644.0
v0.643.0
v0.642.0
v0.641.0
v0.640.0
v0.639.0
v0.638.0
v0.637.0
v0.636.0
v0.635.0
v0.634.0
v0.633.0
v0.632.0
v0.631.0
v0.630.0
v0.629.0
v0.628.0
v0.627.0
v0.626.0
v0.625.0
v0.624.0
v0.623.0
v0.622.0
v0.621.0
v0.620.0
v0.619.0
v0.618.0
v0.617.0
v0.616.0
v0.615.0
v0.614.0
v0.613.0
v0.612.0
v0.611.0
v0.610.0
v0.609.0
v0.608.0
v0.607.0
v0.606.0
v0.605.0
v0.604.0
v0.603.0
v0.602.0
v0.601.0
v0.600.0
v0.599.0
v0.598.0
v0.597.0
v0.596.0
v0.595.0
v0.594.0
v0.593.0
v0.592.0
v0.591.0
v0.590.0
v0.589.0
v0.588.0
v0.587.0
v0.586.0
v0.585.0
v0.584.0
v0.583.0
v0.582.0
v0.581.0
v0.580.0
v0.579.0
v0.578.0
v0.577.0
v0.576.0
v0.575.0
v0.574.0
v0.573.0
v0.572.0
v0.571.0
v0.570.0
v0.569.0
v0.568.0
v0.567.0
v0.566.0
v0.565.0
v0.564.0
v0.563.0
v0.562.0
v0.561.0
v0.560.0
v0.559.0
v0.558.0
v0.557.0
v0.556.0
v0.555.0
v0.554.0
v0.553.0
v0.552.0
v0.551.0
v0.550.0
v0.549.0
v0.548.0
v0.547.0
v0.546.0
v0.545.0
v0.544.0
v0.543.0
v0.542.0
v0.541.0
v0.540.0
v0.539.0
v0.538.0
v0.537.0
v0.536.0
v0.535.0
v0.534.0
v0.533.0
v0.532.0
v0.531.0
v0.530.0
v0.529.0
v0.528.0
v0.527.0
v0.526.0
v0.525.0
v0.524.0
v0.523.0
v0.522.0
v0.521.0
v0.520.0
v0.519.0
v0.518.0
v0.517.0
v0.516.0
v0.515.0
v0.514.0
v0.513.0
v0.512.0
v0.511.0
v0.510.0
v0.509.0
v0.508.0
v0.507.0
v0.506.0
v0.505.0
v0.504.0
v0.503.0
v0.502.0
v0.501.0
v0.500.0
v0.499.0
v0.498.0
v0.497.0
v0.496.0
v0.495.0
v0.494.0
v0.493.0
v0.492.0
v0.491.0
v0.490.0
v0.489.0
v0.488.0
v0.487.0
v0.486.0
v0.485.0
v0.484.0
v0.483.0
v0.482.0
v0.481.0
v0.480.0
v0.479.0
v0.478.0
v0.477.0
v0.476.0
v0.475.0
v0.474.0
v0.473.0
v0.472.0
v0.471.0
v0.470.0
v0.469.0
v0.468.0
v0.467.0
v0.466.0
v0.465.0
v0.464.0
v0.463.0
v0.462.0
v0.461.0
v0.460.0
v0.459.0
v0.458.0
v0.457.0
v0.456.0
v0.455.0
v0.454.0
v0.453.0
v0.452.0
v0.451.0
v0.450.0
v0.449.0
v0.448.0
v0.447.0
v0.446.0
v0.445.0
v0.444.0
v0.443.0
v0.442.0
v0.441.0
v0.440.0
v0.439.0
v0.438.0
v0.437.0
v0.436.0
v0.435.0
v0.434.0
v0.433.0
v0.432.0
v0.431.0
v0.430.0
v0.429.0
v0.428.0
v0.427.0
v0.426.0
v0.425.0
v0.424.0
v0.423.0
v0.422.0
v0.421.0
v0.420.0
v0.419.0
v0.418.0
v0.417.0
v0.416.0
v0.415.0
v0.414.0
v0.413.0
v0.412.0
v0.411.0
v0.410.0
v0.409.0
v0.408.0
v0.407.0
v0.406.0
v0.405.0
v0.404.0
v0.403.0
v0.402.0
v0.401.0
v0.400.0
v0.399.0
v0.398.0
v0.397.0
v0.396.0
v0.395.0
v0.394.0
v0.393.0
v0.392.0
v0.391.0
v0.390.0
v0.389.0
v0.388.0
v0.387.0
v0.386.0
v0.385.0
v0.384.0
v0.383.0
v0.382.0
v0.381.0
v0.380.0
v0.379.0
v0.378.0
v0.377.0
v0.376.0
v0.375.0
v0.374.0
v0.373.0
v0.372.0
v0.371.0
v0.370.0
v0.369.0
v0.368.0
v0.367.0
v0.366.0
v0.365.0
v0.364.0
v0.363.0
v0.362.0
v0.361.0
v0.360.0
v0.359.0
v0.358.0
v0.357.0
v0.356.0
v0.355.0
v0.354.0
v0.353.0
v0.352.0
v0.351.0
v0.350.0
v0.349.0
v0.348.0
v0.347.0
v0.346.0
v0.345.0
v0.344.0
v0.343.0
v0.342.0
v0.341.0
v0.340.0
v0.339.0
v0.338.0
v0.337.0
v0.336.0
v0.335.0
v0.334.0
v0.333.0
v0.332.0
v0.331.0
v0.330.0
v0.329.0
v0.328.0
v0.327.0
v0.326.0
v0.325.0
v0.324.0
v0.323.0
v0.322.0
v0.321.0
v0.320.0
v0.319.0
v0.318.0
v0.317.0
v0.316.0
v0.315.0
v0.314.0
v0.313.0
v0.312.0
v0.311.0
v0.310.0
v0.309.0
v0.308.0
v0.307.0
v0.306.0
v0.305.0
v0.304.0
v0.303.0
v0.302.0
v0.301.0
v0.300.0
v0.299.0
v0.298.0
v0.297.0
v0.296.0
v0.295.0
v0.294.0
v0.293.0
v0.292.0
v0.291.0
v0.290.0
v0.289.0
v0.288.0
v0.287.0
v0.286.0
v0.285.0
v0.284.0
v0.283.0
v0.282.0
v0.281.0
v0.280.0
v0.279.0
v0.278.0
v0.277.0
v0.276.0
v0.275.0
v0.274.0
v0.273.0
v0.272.0
v0.271.0
v0.270.0
v0.269.0
v0.268.0
v0.267.0
v0.266.0
v0.265.0
v0.264.0
v0.263.0
v0.262.0
v0.261.0
v0.260.0
v0.259.0
v0.258.0
v0.257.0
v0.256.0
v0.255.0
v0.254.0
v0.253.0
v0.252.0
v0.251.0
v0.250.0
v0.249.0
v0.248.0
v0.247.0
v0.246.0
v0.245.0
v0.244.0
v0.243.0
v0.242.0
v0.241.0
v0.240.0
v0.239.0
v0.238.0
v0.237.0
v0.236.0
v0.235.0
v0.234.0
v0.233.0
v0.232.0
v0.231.0
v0.230.0
v0.229.0
v0.228.0
v0.227.0
v0.226.0
v0.225.0
v0.224.0
v0.223.0
v0.222.0
v0.221.0
v0.220.0
v0.219.0
v0.218.0
v0.217.0
v0.216.0
v0.215.0
v0.214.0
v0.213.0
v0.212.0
v0.211.0
v0.210.0
v0.209.0
v0.208.0
v0.207.0
v0.206.0
v0.205.0
v0.204.0
v0.203.0
v0.202.0
v0.201.0
v0.200.0
v0.199.0
v0.198.0
v0.197.0
v0.196.0
v0.195.0
v0.194.0
v0.193.0
v0.192.0
v0.191.0
v0.190.0
v0.189.0
v0.188.0
v0.187.0
v0.186.0
v0.185.0
v0.184.0
v0.183.0
v0.182.0
v0.181.0
v0.180.0
v0.179.0
v0.178.0
v0.177.0
v0.176.0
v0.175.0
v0.174.0
v0.173.0
v0.172.0
v0.171.0
v0.170.0
v0.169.0
v0.168.0
v0.167.0
v0.166.0
v0.165.0
v0.164.0
v0.163.0
v0.162.0
v0.161.0
v0.160.0
v0.159.0
v0.158.0
v0.157.0
v0.156.0
v0.155.0
v0.154.0
v0.153.0
v0.152.0
v0.151.0
v0.150.0
v0.149.0
v0.148.0
v0.147.0
v0.146.0
v0.145.0
v0.144.0
v0.143.0
v0.142.0
v0.141.0
v0.140.0
v0.139.0
v0.138.0
v0.137.0
v0.136.0
v0.135.0
v0.134.0
v0.133.0
v0.132.0
v0.131.0
v0.130.0
v0.129.0
v0.128.0
v0.127.0
v0.126.0
v0.125.0
v0.124.0
v0.123.0
v0.122.0
v0.121.0
v0.120.0
v0.119.0
v0.118.0
v0.117.0
v0.116.0
v0.115.0
v0.114.0
v0.113.0
v0.112.0
v0.111.0
v0.110.0
v0.109.0
v0.108.0
v0.107.0
v0.106.0
v0.105.0
v0.104.0
v0.103.0
v0.102.0
v0.101.0
v0.100.0
v0.99.0
v0.98.0
v0.97.0
v0.96.0
v0.95.0
v0.94.0
v0.93.0
v0.92.0
v0.91.0
v0.90.0
v0.89.0
v0.88.0
v0.87.0
v0.86.0
v0.85.0
v0.84.0
v0.83.0
v0.82.0
v0.81.0
v0.80.0
v0.79.0
v0.78.0
v0.77.0
v0.76.0
v0.75.0
v0.74.0
v0.73.0
v0.72.0
v0.71.0
v0.70.0
v0.69.0
v0.68.0
v0.67.0
v0.66.0
v0.65.0
v0.64.0
v0.63.0
v0.62.0
v0.61.0
v0.60.0
v0.59.0
v0.58.0
v0.57.0
v0.56.0
v0.55.0
v0.54.0
v0.53.0
v0.52.0
v0.51.0
v0.50.0
v0.49.0
v0.48.0
v0.47.0
v0.46.0
v0.45.0
v0.44.0
v0.43.0
v0.42.0
v0.41.0
v0.40.0
v0.39.0
v0.38.0
v0.37.0
v0.36.0
v0.35.0
v0.34.0
v0.33.0
v0.32.0
v0.31.0
v0.30.0
v0.29.0
v0.28.0
v0.27.0
v0.26.0
v0.25.0
v0.24.0
v0.23.0
v0.22.0
v0.21.0
v0.20.0
v0.19.0
v0.18.0
v0.17.0
v0.16.0
v0.15.0
v0.14.0
v0.13.0
v0.12.0
v0.11.0
v0.10.0
v0.9.0
v0.8.0
v0.7.0
v0.6.0
v0.5.8
v0.5.7
v0.5.6
v0.5.5
v0.5.4
v0.5.3
v0.5.2
v0.5.1
v0.5.0
v0.4.0
v0.3.0
v0.2.2
v0.2.1
v0.2.0
v0.1.3
v0.1.2
v0.1.1
v0.1.0
v0.0.18
v0.0.17
v0.0.16
v0.0.15
v0.0.14
v0.0.13
v0.0.12
v0.0.11
v0.0.10
v0.0.9
v0.0.8
v0.0.7
v0.0.6
v0.0.5
v0.0.4
v0.0.3
v0.0.2
v0.0.1
Labels
Clear labels
burndown-2026-06
Backlog burndown June 2026
pressure-test
Cold-read release pressure-test findings and coordination
sunday-sprint
Burn-down by Sunday 2026-06-07
autonomy
async-consult
A human needs to consult on the issue to upgrade it to headless
autonomy
epic
This issue has many units of sub work - its size makes it meaningfully exclusive with other autonomy types
autonomy
headless
The agent can perform the work on its own
autonomy
live-collab
The agent and the human need to work together in realtime
coherence-core
Core review set for the warded control plane coherence milestone. These issues form the release spine; adjacent milestone issues are stretch or supporting work.
priority
P0
priority tier
priority
P1
priority tier
priority
P2
priority tier
priority
P3
priority tier
priority
P4
priority tier
qa-fixture
Disposable issue admitted to the bounded Ward QA verification lane.
role/advocate
requires work from the Developer Advocate seat
role/director
requires work from the Portfolio Director seat
role/exec
requires work from the exec role
role/frontend
requires work from the Frontend Engineer seat
role/gamedev
requires work from the Game Developer seat
role/human
requires a person, and specifically not an agent seat
role/platform
requires work from the Platform Engineer seat
role/qa
requires work from the QA role
role/science
requires work from the Applied Scientist seat
role/sysadmin
requires work from the Systems Administrator seat
state
ambient
ambient and ephemeral work, held as a maintained document rather than a queue
No labels
burndown-2026-06
pressure-test
sunday-sprint
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/advocate
role/director
role/exec
role/frontend
role/gamedev
role/human
role/platform
role/qa
role/science
role/sysadmin
state
ambient
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/ward#619
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Intent (Kai)
Flip the intake default so the director files issues
headlessby default, instead of today's fail-closed "unlabeled -> consult". Kai's own guardrail: default-headless is only safe if it is paired with a relabel-down discipline - engineers and advisors must learn to relabel an issue down (headless -> interactive/consult) when they determine it cannot actually be carried autonomously. Without that, "everything ends up incorrectly headless."This is a design brief, not an implementation ticket. Post a concrete plan as a comment for Kai to approve before any implementation dispatches.
Current state (fail-closed - this inverts it)
cmd/ward/agent.go:583-626, ward#607 / agentic-os#246):modeCeilingLevels = [consult, interactive, headless]; an unlabeled issue isconsult (unlabeled default), the floor.agentSurfaceCeilinggates only the engineer role atheadless; director and advisor are ungated.cmd/ward/agent_director_triage.go): a startup pass surveys open issues missing a mode label and promotes only a confident headless/interactive;triageModefails closed to consult otherwise. The consult/interactive/headless definitions the survey uses are the prompt at lines 171-176 - reuse them as the shared vocabulary.OpFileIssue, currently stamps no label - this is what forces--forcetoday), and the freeform intake that files-then-carries (cmd/ward/agent_route.go).Design questions to resolve in the plan
headlessat creation, and how it interacts with the existingtriageModepass. Does default-headless replace fail-closed triage, or only seed the label that triage/agents then correct? Name the interaction explicitly - do not leave two systems fighting over the same label.headless, setinteractiveorconsult; who acts (an engineer that hits the wall mid-run; an advisor whose research concludes the issue is human-gated); and the escalation shape (post a comment explaining why it was downgraded, then stop - never--forcea bad autonomous change past the wall).agentSeedPrompt/role bodies inagent.go,agent_engineer.go,agent_advisor.go), the wardAGENTS.mdcontainer doctrine, or a skill. Capability check: engineers/advisors hold a write-tier token directly (not the broker), and the ward-kdl write guardfile already grantscan add/set/remove issue-label- confirm the advisor role's tier actually includes issue-label add/remove, and flag it if not.Dependency note
The director read-only surface relabeling through the broker needs cli-guard#193 / ward#618 (the broker label op). Engineers and advisors do not - they relabel directly with their own token. So Piece 1 does not block on the broker work; call that out so the plan does not over-couple.
Deliverable
A comment carrying: the resolved answers to the five questions above, the recommended decomposition into landable engineer issues (with the exact doctrine text to add and the files each touches), and an explicit call on whether the fail-closed -> fail-open inversion is worth it or whether a middle path (e.g. default-headless only for a trusted intake class) is safer.
🔎 ward agent advisor
ward agent advisor --driver clauderan a one-shot standard research pass on this question:Design: default-headless intake + tri-role relabel-down discipline
TL;DR recommendation: land the relabel-down discipline (Piece 1) first and unconditionally - it is additive and correct even under today's fail-closed default. For Piece 2, do not flip the broad LLM-judged backlog default to fail-open. Take the middle path: default-headless only for the trusted intake class (issues the director itself files in the act of dispatching them), and leave the backlog-survey (
triageMode) fail-closed. That captures Kai's intent ("the director files issues headless by default") on exactly the issues where headless is safe, without headless-stamping a heterogeneous backlog the moment the discipline ships.Capability confirmed (the one blocking question): yes - both the engineer and the advisor in-container hold a write-capable
FORGEJO_TOKENand the embeddedward ops forgejosurface includesadd/set/remove issue-label(cmd/ward/opsassets/forgejo.guardfile.generated.kdl:247-249, mirroring the write guardfile at.ward/ward-kdl/ward-kdl-write/ward-kdl.forgejo.write.guardfile.kdl:70-74). The advisor container is filesystem-read-only (plan.ReadOnly = true, no git push wiring) but that removes only code-push, not forge-label capability - a label add/remove is a forge API call throughward ops forgejo, not agit push. So an advisor can relabel down and comment with no code change. The only path that cannot relabel is the director read-only surface via the broker (writeTierOpsincmd/ward/broker_exec.go:160-165is FileIssue/EditIssue/CommentIssue/Dispatch only - no label op), which is exactly the cli-guard#193 / ward#618 dependency the issue flags.Answers to the five design questions
1. Scope of "headless by default" - and the two-systems interaction
There are three distinct filing/labeling surfaces today, and they must not fight over the label:
agent_director_triage.go) - a host-side LLM survey that promotes only a confident headless/interactive andtriageModefails closed to consult (lines 85-92). Usescl.addIssueLabelsdirectly, fully capable.agent_route.go) - files an intake record + a scoped child via the host client (signed.createIssue), then carries the child headless. It stamps no mode label on the child today.OpFileIssue, which stamps no label (this is what forces--forceon the follow-on engineer dispatch, sinceissueModeCeilingreads unlabeled asconsultand the engineer ceiling gate wantsheadless).Named interaction (no fighting): keep
issueModeCeiling's unlabeled default fail-closed toconsultas a permanent defense-in-depth floor (an issue that somehow escapes labeling stays gated, never silently headless). Default-headless is a seed at creation on the filing paths, not a change to how the ceiling reads an unlabeled issue. Agents are the only downward-correction mechanism after that. This gives one writer per moment (filing stamps headless, agents relabel down) and one reader (the ceiling gate), never two systems racing on the same label.Recommendation on which paths stamp headless:
agent_route.go, host-sideaddIssueLabelsright after the child is created) - it is already carried headless, so labeling it headless just makes the forge state honest and removes the--forceneed on any re-dispatch.triageMode's backlog default. Do not invert it to fail-open (see the verdict below).2. Downgrade criteria (single-sourced to the triage vocabulary)
The canonical consult/interactive/headless definitions live in
triagePrompt(agent_director_triage.go:170-176). Extract them into an exported Go const (modeLadderDefs) sotriagePrompt, the seed prompt, and the doctrine all cite one source. An engineer/advisor downgrades out ofheadlesswhen any of these hold (each anchored to a ladder rung):These are the same signals the container doctrine already treats as walls ("run until a wall worth a human"); relabel-down is what an agent does at that wall instead of
--force-ing past it.3. Downgrade mechanics + escalation
Who acts:
Mechanics (in-container, token already present, no broker):
(On a GitHub target:
gh issue edit <N> --remove-label headless --add-label interactive.)Escalation shape: post a comment naming the exact signal that made it un-headless, then stop - do not commit a partial/speculative change to "make progress", and never
--forcepast the gate. A downgraded issue is a handoff to a human, and the comment is that handoff. This is a floor-only move: relabel down only. Relabeling up toward headless to clear the dispatch gate for yourself is forbidden - raising the ceiling is the director's or a human's call.4. Where the per-role instruction lives
One primary home, read by all three roles, plus thin pointers:
cmd/ward/containerassets/AGENTS.container.md(the embedded container doctrine mounted into every role's container bywriteContainerAssets). Exact text below. This is the one file all three roles reliably read.modeLadderDefsconst into the seed viaagentSeedPromptWorkflow(cmd/ward/agent.go) for engineer/direct headless runs, and intoaskPrompt/interactivePrompt/replyResearchPrompt(agent_advisor.go,agent_reply.go) for the advisor, so the ladder definitions are never re-authored in prose.docs/agent-dispatch-contract.mdgets a cross-link, and a shortdocs/relabel-down.mdwalkthrough completes the docs trifecta.Capability check result: no guardfile change needed. Both engineer and advisor already carry the
issue-label add/set/removesurface + a live token in-container (confirmed above). The doctrine just needs to hand them the exact command. Flag: the director surface (broker) genuinely lacks the op - that stays a ward#618 item and is out of scope for Piece 1.5. Safe decomposition (prerequisite ordering)
Kai's framing is right: Piece 1 gates Piece 2. Recommended landable engineer issues, in dependency order:
Issue A - Piece 1: tri-role relabel-down doctrine + single-sourced vocabulary (no dependency; safe and good even today)
cmd/ward/agent_director_triage.go- extract lines 170-176 intoconst modeLadderDefs;triagePromptreferences it (pure refactor, no behavior change).cmd/ward/containerassets/AGENTS.container.md- add the "Relabel an issue down" section (exact text below).cmd/ward/agent.go-agentSeedPromptWorkflowinjectsmodeLadderDefs+ a one-line relabel-down pointer on headless runs.cmd/ward/agent_advisor.go+cmd/ward/agent_reply.go- add the relabel-down clause toaskPrompt/interactivePrompt/replyResearchPromptso the advisor relabels down + comments when research concludes human-gated.docs/agent-dispatch-contract.md(cross-link) + newdocs/relabel-down.md; updatedocs/FEATURES.md.agent_test.go/agent_director_test.goto assert the seed carries the relabel-down clause and the extracted const.Issue B - Piece 2 (middle path): stamp headless on the director's own intake (depends on A)
cmd/ward/agent_route.go- after the child issue is created (line 134),signed.addIssueLabels(ctx, target.Owner, target.Name, childNum, []string{"headless"}), best-effort like triage.triageModefail-closed - add a code comment recording that this is deliberate (the middle-path call), so a later reader does not "finish the inversion" by accident.Issue C - cli-guard: broker label op (separate repo; unblocks the director-surface capture path only)
coilyco-flight-deck/cli-guard- add a label op to the brokerOpset + Executor/Authorizer (cli-guard#193). Downstream ward#618 then wiresbroker_exec.gowriteTierOpsto serve it and the director surface stamps headless at capture. Piece 1 does not wait on this - engineers and advisors relabel with their own token, per the dependency note.Exact doctrine text for
AGENTS.container.mdAdd after the "Where the wall still is" section:
The advisor is read-only for code, not for the forge - it may add/remove a label and comment. Frame the advisor's clause accordingly ("if your research concludes the issue is human-gated, relabel it down and say why in your posted answer").
The verdict: is the fail-closed -> fail-open inversion worth it?
Partially - take the middle path, not the full inversion.
--forcefriction. This is the core of Kai's intent and it is safe once Piece 1 exists.triageMode's backlog-survey default from consult to headless. That is a fail-open change over a large heterogeneous backlog judged by a low-confidence LLM pass - precisely the "everything ends up incorrectly headless" failure Kai names, and the relabel-down discipline only catches issues an agent actually gets dispatched on, not the long tail that sits labeled-but-untouched. Keep the confident-promotion behavior; keep the unconfident default at consult.Net: the inversion is right where the label is a byproduct of a fresh, deliberate dispatch decision, and wrong where it is a bulk guess about dormant backlog. Piece 1 (relabel-down) is unconditionally worth landing first; Piece 2 should be scoped to the trusted intake class only.
Awaiting Kai's approval before dispatching implementation. On approval, the recommended firing order is Issue A, then Issue B, with Issue C (cli-guard#193 / ward#618) tracked in parallel since Piece 1 does not block on it.
Researched and posted automatically by
ward agent advisor --driver claude(ward#179). This is one-shot research, not a carried change - verify before acting on it.— Claude (she/her), via
ward agentScope extension: the dormant-backlog half of the same discipline (from a live incident)
Kai raised this after a director lost its dispatch-broker connection mid-drain and a follow-on seat re-fired the "ready" batch. The postmortem is the argument for widening #619, so it belongs here rather than in a fresh ticket.
What happened. A read-only director surface re-dispatched engineers on issues that still carried a
headlesslabel from an earlier triage flip. Several were old (filed hundreds of issues behind HEAD), two were already closed, and the dispatches passed--no-preflight. Two runs finished and pushed tomainbefore they were stopped by hand. Not harmful, but awkward: an engineer rewrote live code against a stale premise, and one landed via a duplicate of #617.Root cause (one bug, three faces). A freshness judgment gets cached at some earlier moment and trusted at dispatch without rechecking current reality:
headlesslabel is cached at triage.director-startup-triage.mdline 39-40 makes it policy: "presence of a label is the freshness signal, no time-based re-triage." A stamp never expires.--no-preflightcaches "I decided this is GO" with no tie to the code state it was judged against.#619's relabel-down discipline fixes freshness for issues an agent gets dispatched on. The advisor plan above says so directly: it "only catches issues an agent actually gets dispatched on, not the long tail that sits labeled-but-untouched." That long tail is exactly what bit us. So #619 should grow three more pieces, all instances of compute freshness at dispatch, not at triage:
Piece 3 - dormant-backlog drift re-triage (closes the "no time-based re-triage" hole)
Invalidate a mode label when the code it was judged against has drifted, and re-judge. Drift, not wall-clock (time is a weak proxy): stamp each triage label with the HEAD commit or issue-number it was computed at, and when the distance since exceeds a threshold, drop the label back into the untriaged pool so the startup pass re-judges it. This is the minimal change to
agent_director_triage.go's skip-already-triaged rule: skip a labeled issue only while its stamp is within drift tolerance, not forever.Piece 4 - pre-flight hardening + retire the wholesale skip
--no-preflightcan never skip: the issue must be open (a closed issue is an automatic NO-GO - nothing should have dispatched an engineer at a closed ticket), plus the Piece 3 drift check.--no-preflightexists to route around: pre-flight must reason from the resolved repo, not the host dispatcher cwd (the goose-wrong-cwd NO-GO). Fix the gate and the bypass loses its reason to exist.Piece 5 - director per-dispatch effort estimate (builds on the now-landed #617)
#617 shipped static per-role effort (director high, engineer medium, baked in the fleet KDL). Add a dynamic layer: the director emits an effort guess for this ticket at dispatch, overriding the role default. The value is the forcing function - producing the estimate requires a fresh read that sizes the ticket, which is the same medicine as mandatory pre-flight. A refused or low-confidence estimate is itself a hold signal: "I can't size this" means "I do not understand it well enough to fire it," so downgrade to consult rather than dispatch.
Sequencing. Piece 1 (relabel-down) still lands first and unblocks the rest. Pieces 3-5 are independent of each other and of the broker label op (#618). Piece 4's open-state floor check is the smallest and highest-value single fix - it alone would have stopped today's worst case.
Housekeeping fallout from the incident: #617 is now superseded by the #620 merge (per-role config landed); it needs closing, and the landed director effort value needs a check (it may have captured the pre-correction
mediumrather than the correctedhigh, since the engineer freezes the issue body at launch).Correction to Piece 1's capability claim (from the #621 relabel attempt)
The advisor design above states engineers/advisors can relabel with their own in-container token and do not need the broker label op for relabel-down. Empirically that is false for a run dispatched from the read-only director surface: a ref-mode advisor at #621 had every
issue-label add/removerefusedout of tier- its writes route through the broker, not a direct token. So either (a) surface-originated dispatches are broker-gated where normal host dispatches are not, or (b) the direct-token claim is wrong generally. This needs verifying, because it decides whether the director-surface relabel-down path is blocked on #618 after all. Until resolved, treat #618 as load-bearing for any relabel that originates from the director surface.