@alphazede/bearing-lite 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/hooks/closeout.cjs +17 -0
- package/hooks/owner-stops.cjs +154 -0
- package/hooks/transition-order.cjs +12 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/schemas/authority.schema.json +55 -34
- package/schemas/journey.schema.json +141 -47
- package/skills/bearing-lite/SKILL.md +3 -3
- package/skills/bearing-lite/references/lineups.md +5 -0
- package/skills/bearing-lite/references/owner-stops.md +122 -0
- package/skills/bearing-lite/references/review-policy.md +5 -0
- package/skills/explorer/SKILL.md +3 -3
- package/skills/map-the-route/SKILL.md +2 -1
- package/skills/scribe/SKILL.md +4 -0
package/README.md
CHANGED
|
@@ -151,6 +151,16 @@ explain orientation; they never authorize a transition.
|
|
|
151
151
|
|
|
152
152
|
## Roles and authority
|
|
153
153
|
|
|
154
|
+
Owner questions follow [the owner-stop policy](skills/bearing-lite/references/owner-stops.md).
|
|
155
|
+
The integrated approval records bounded continuation with exclusions and expiry.
|
|
156
|
+
The Router applies approved policy and fallbacks, batches nonblocking questions,
|
|
157
|
+
and continues ready independent work while dependent work waits. Approval shows
|
|
158
|
+
the first-package summary or subsequent changes with the complete package available.
|
|
159
|
+
Local receipt metrics distinguish questions, round trips, response intervals and
|
|
160
|
+
fully blocked time; no telemetry leaves the checkout. The transition preflight
|
|
161
|
+
and scheduling remain procedural, including on skills-only hosts. A legacy
|
|
162
|
+
Journey without explicit timing coverage reports unavailable, not zero wait.
|
|
163
|
+
|
|
154
164
|
| Role | What it is | Executes | Notes |
|
|
155
165
|
|---|---|---|---|
|
|
156
166
|
| **Router** | Stateful planning controller | no | User-facing; planning-state writer; Expedition sequencing |
|
package/hooks/closeout.cjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
const { ownerWaitMetrics } = require("./owner-stops.cjs");
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* Bearing Lite return/closeout adapter (CONTRACT-HOOK-01).
|
|
6
8
|
* Advisory for ordinary handoff reminders; may BLOCK only protected completion.
|
|
@@ -154,6 +156,21 @@ function evaluate(input) {
|
|
|
154
156
|
return result("ADVISE", "channel_open", RECOVERY_CHANNEL);
|
|
155
157
|
}
|
|
156
158
|
|
|
159
|
+
// Explicit invocation by Router; native Stop mappings do not supply Journey JSON.
|
|
160
|
+
if (input.action_kind === "owner_wait_summary") {
|
|
161
|
+
if (input.mode === "protected_completion" || input.protected_completion === true) {
|
|
162
|
+
return unavailable("owner_wait_summary_is_not_completion");
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
const metrics = ownerWaitMetrics(input.journey, input.as_of);
|
|
166
|
+
return { ...result("ADVISE", "owner_wait:" + metrics.status,
|
|
167
|
+
"Render metrics and coverage in the wave or closeout receipt; no authority is granted"),
|
|
168
|
+
owner_wait: metrics };
|
|
169
|
+
} catch {
|
|
170
|
+
return unavailable("owner_wait_records_invalid");
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
157
174
|
const mode =
|
|
158
175
|
input.mode === "protected_completion" || input.protected_completion === true
|
|
159
176
|
? "protected_completion"
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Procedural owner-stop preflight and local receipt metrics; never grants authority.
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const object = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
6
|
+
const text = (v) => typeof v === "string" && v.trim().length > 0;
|
|
7
|
+
const classes = ["A", "B", "C", "D", "E", "F"];
|
|
8
|
+
const exclusions = ["scope_change", "budget_exhaustion", "owner_hold", "owner_only_actions"];
|
|
9
|
+
|
|
10
|
+
function timestamp(value) {
|
|
11
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(value)) {
|
|
12
|
+
throw new Error("invalid_utc_timestamp");
|
|
13
|
+
}
|
|
14
|
+
const n = Date.parse(value);
|
|
15
|
+
if (!Number.isFinite(n) || new Date(n).toISOString() !== (value.includes(".") ? value : value.replace("Z", ".000Z"))) {
|
|
16
|
+
throw new Error("invalid_utc_timestamp");
|
|
17
|
+
}
|
|
18
|
+
return n;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function evaluateOwnerStop(input) {
|
|
22
|
+
const unknown = (reason) => ({ disposition: "NEEDS_MORE_EVIDENCE", reason });
|
|
23
|
+
if (!object(input) || !classes.includes(input.class) || typeof input.blocking !== "boolean" || !text(input.evidence_ref)) {
|
|
24
|
+
return unknown("owner_stop_input_missing");
|
|
25
|
+
}
|
|
26
|
+
if (["C", "E", "F"].includes(input.class)) {
|
|
27
|
+
return { disposition: input.blocking ? "ASK" : "QUEUE", reason: "owner_boundary" };
|
|
28
|
+
}
|
|
29
|
+
const a = input.authority;
|
|
30
|
+
const grant = a?.continuation;
|
|
31
|
+
if (!object(a) || a.effective !== true || a.state !== "active" || !text(a.id) ||
|
|
32
|
+
!object(a.approval_receipt) || Object.keys(a.approval_receipt).length === 0 ||
|
|
33
|
+
!object(grant) || grant.granted !== true || !text(grant.owner_decision_id) ||
|
|
34
|
+
!Array.isArray(a.granting_owner_decisions) || !a.granting_owner_decisions.includes(grant.owner_decision_id) ||
|
|
35
|
+
!Array.isArray(a.expiry_conditions) || !a.expiry_conditions.length || !a.expiry_conditions.every(text) ||
|
|
36
|
+
!Array.isArray(grant.exclusions) || !exclusions.every((item) => grant.exclusions.includes(item))) {
|
|
37
|
+
return unknown("continuation_grant_missing");
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const now = timestamp(input.checked_at);
|
|
41
|
+
if (grant.expires_at !== null && timestamp(grant.expires_at) <= now) return unknown("continuation_expired");
|
|
42
|
+
} catch {
|
|
43
|
+
return unknown("continuation_expiry_unverified");
|
|
44
|
+
}
|
|
45
|
+
const checks = ["scope", "budget", "exclusions", "expiry", "owner_hold"];
|
|
46
|
+
if (input.class === "A") checks.push("policy");
|
|
47
|
+
if (input.class === "B") checks.push("fallback");
|
|
48
|
+
if (!object(input.checks) || !checks.every((key) => input.checks[key] === true) || !text(input.resolution_ref)) {
|
|
49
|
+
return unknown("continuation_conditions_unverified");
|
|
50
|
+
}
|
|
51
|
+
return { disposition: "CONTINUE", reason: "approved_resolution", authority_id: a.id };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function unionLength(intervals) {
|
|
55
|
+
let total = 0;
|
|
56
|
+
let end = -Infinity;
|
|
57
|
+
for (const [start, stop] of intervals.sort((a, b) => a[0] - b[0])) {
|
|
58
|
+
total += Math.max(0, stop - Math.max(start, end));
|
|
59
|
+
end = Math.max(end, stop);
|
|
60
|
+
}
|
|
61
|
+
return total;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function ownerWaitMetrics(journey, asOf) {
|
|
65
|
+
if (!object(journey)) throw new Error("journey_missing");
|
|
66
|
+
if (journey.owner_wait_tracking === undefined || journey.owner_wait_tracking === false) {
|
|
67
|
+
return { status: "unavailable", reason: "owner_wait_not_tracked" };
|
|
68
|
+
}
|
|
69
|
+
if (journey.owner_wait_tracking !== true || !Array.isArray(journey.decisions) ||
|
|
70
|
+
!Array.isArray(journey.open_decisions) || !Array.isArray(journey.owner_blocked_intervals)) {
|
|
71
|
+
throw new Error("owner_wait_records_missing");
|
|
72
|
+
}
|
|
73
|
+
const now = timestamp(asOf);
|
|
74
|
+
const counts = Object.fromEntries(classes.map((key) => [key, 0]));
|
|
75
|
+
const metrics = { status: "measured", as_of: asOf, decisions_asked: 0, round_trips: 0,
|
|
76
|
+
queued: 0, pending: 0, cancelled: 0, by_class: counts,
|
|
77
|
+
response_ms: 0, pending_response_ms: 0, response_window_ms: 0, blocked_ms: 0 };
|
|
78
|
+
const ids = new Set();
|
|
79
|
+
const rounds = new Map();
|
|
80
|
+
const responses = [];
|
|
81
|
+
const windows = new Map();
|
|
82
|
+
for (const q of [...journey.decisions, ...journey.open_decisions]) {
|
|
83
|
+
if (!object(q) || q.record_type !== "owner_stop") continue;
|
|
84
|
+
if (!text(q.id) || ids.has(q.id)) throw new Error("duplicate_or_missing_decision_id");
|
|
85
|
+
ids.add(q.id);
|
|
86
|
+
if (!classes.includes(q.class) || !["queued", "asked", "answered", "cancelled"].includes(q.status) ||
|
|
87
|
+
!text(q.question) || !text(q.evidence_ref) || !text(q.why_owner) ||
|
|
88
|
+
typeof q.blocking !== "boolean" || !Array.isArray(q.affected_slices) || !q.affected_slices.every(text) ||
|
|
89
|
+
!["asked_at", "answered_at", "cancelled_at", "round_trip_id"].every((key) => Object.hasOwn(q, key))) {
|
|
90
|
+
throw new Error("invalid_owner_stop_record");
|
|
91
|
+
}
|
|
92
|
+
const asked = q.asked_at === null ? null : timestamp(q.asked_at);
|
|
93
|
+
const answered = q.answered_at === null ? null : timestamp(q.answered_at);
|
|
94
|
+
const cancelled = q.cancelled_at === null ? null : timestamp(q.cancelled_at);
|
|
95
|
+
const created = timestamp(q.created_at);
|
|
96
|
+
if (created > now || (asked !== null && (asked < created || asked > now))) throw new Error("invalid_question_time");
|
|
97
|
+
if (q.status === "queued" && (asked !== null || answered !== null || cancelled !== null)) throw new Error("invalid_queued_question");
|
|
98
|
+
if (q.status === "asked" && (asked === null || answered !== null || cancelled !== null)) throw new Error("invalid_pending_question");
|
|
99
|
+
if (q.status === "answered" && (asked === null || answered === null || cancelled !== null || !text(q.answer_ref))) throw new Error("invalid_answered_question");
|
|
100
|
+
if (q.status === "cancelled" && (cancelled === null || answered !== null)) throw new Error("invalid_cancelled_question");
|
|
101
|
+
const end = answered ?? cancelled ?? now;
|
|
102
|
+
if (end < (asked ?? created) || end > now) throw new Error("invalid_response_time");
|
|
103
|
+
if (q.status === "queued") metrics.queued++;
|
|
104
|
+
if (q.status === "asked") metrics.pending++;
|
|
105
|
+
if (q.status === "cancelled") metrics.cancelled++;
|
|
106
|
+
if (asked === null) {
|
|
107
|
+
if (q.round_trip_id !== null) throw new Error("unasked_round_trip");
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (!text(q.round_trip_id)) throw new Error("round_trip_missing");
|
|
111
|
+
if (rounds.has(q.round_trip_id) && rounds.get(q.round_trip_id) !== asked) {
|
|
112
|
+
throw new Error("inconsistent_round_trip_time");
|
|
113
|
+
}
|
|
114
|
+
rounds.set(q.round_trip_id, asked);
|
|
115
|
+
metrics.decisions_asked++;
|
|
116
|
+
counts[q.class]++;
|
|
117
|
+
responses.push([asked, end]);
|
|
118
|
+
windows.set(q.id, [asked, end]);
|
|
119
|
+
if (answered !== null) metrics.response_ms += end - asked;
|
|
120
|
+
if (q.status === "asked") metrics.pending_response_ms += now - asked;
|
|
121
|
+
}
|
|
122
|
+
const blocked = [];
|
|
123
|
+
for (const interval of journey.owner_blocked_intervals) {
|
|
124
|
+
if (!object(interval) || !Array.isArray(interval.decision_ids) || !interval.decision_ids.length ||
|
|
125
|
+
!interval.decision_ids.every(text) || new Set(interval.decision_ids).size !== interval.decision_ids.length ||
|
|
126
|
+
!Object.hasOwn(interval, "ended_at")) throw new Error("invalid_blocked_interval");
|
|
127
|
+
const start = timestamp(interval.started_at);
|
|
128
|
+
const end = interval.ended_at === null ? now : timestamp(interval.ended_at);
|
|
129
|
+
if (start > end || end > now) throw new Error("invalid_blocked_time");
|
|
130
|
+
for (const id of interval.decision_ids) {
|
|
131
|
+
const window = windows.get(id);
|
|
132
|
+
if (!window || start < window[0] || end > window[1]) throw new Error("blocked_interval_outside_question");
|
|
133
|
+
}
|
|
134
|
+
blocked.push([start, end]);
|
|
135
|
+
}
|
|
136
|
+
metrics.round_trips = rounds.size;
|
|
137
|
+
metrics.response_window_ms = unionLength(responses);
|
|
138
|
+
metrics.blocked_ms = unionLength(blocked);
|
|
139
|
+
return metrics;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
module.exports = { evaluateOwnerStop, ownerWaitMetrics };
|
|
143
|
+
|
|
144
|
+
if (require.main === module) {
|
|
145
|
+
try {
|
|
146
|
+
const [file, asOf] = process.argv.slice(2);
|
|
147
|
+
if (!file || !asOf) throw new Error("usage: owner-stops.cjs <journey.json> <as-of-UTC>");
|
|
148
|
+
console.log(JSON.stringify(ownerWaitMetrics(JSON.parse(fs.readFileSync(file, "utf8")), asOf)));
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.log(JSON.stringify({ status: "invalid", reason: error.code ? "journey_unreadable" :
|
|
151
|
+
/^[a-z_]+$/.test(error.message) ? error.message : "invalid_journey_input" }));
|
|
152
|
+
process.exitCode = 1;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -12,6 +12,7 @@ const OUTCOMES = Object.freeze(["ADVISE", "REROUTE", "BLOCK", "UNAVAILABLE"]);
|
|
|
12
12
|
const ENFORCEMENT = "procedural";
|
|
13
13
|
const { evaluatePlanningReview } = require("./planning-review.cjs");
|
|
14
14
|
const { evaluateAssuranceBudget } = require("./assurance-budget.cjs");
|
|
15
|
+
const { evaluateOwnerStop } = require("./owner-stops.cjs");
|
|
15
16
|
|
|
16
17
|
const RECOVERY_UNAVAILABLE =
|
|
17
18
|
"Keep the current state, run the transition checklist procedurally, and record the result before retrying";
|
|
@@ -132,6 +133,17 @@ function evaluate(input) {
|
|
|
132
133
|
return result("ADVISE", "channel_open", RECOVERY_CHANNEL);
|
|
133
134
|
}
|
|
134
135
|
|
|
136
|
+
if (input.action_kind === "owner_stop_check") {
|
|
137
|
+
const stop = evaluateOwnerStop(input.owner_stop);
|
|
138
|
+
return {
|
|
139
|
+
...result(stop.disposition === "NEEDS_MORE_EVIDENCE" ? "UNAVAILABLE" :
|
|
140
|
+
stop.disposition === "ASK" ? "REROUTE" : "ADVISE",
|
|
141
|
+
"owner_stop:" + stop.disposition + ":" + stop.reason,
|
|
142
|
+
"Apply references/owner-stops.md; this check grants no action or dispatch authority"),
|
|
143
|
+
owner_stop: stop,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
135
147
|
if (input.action_kind === "planning_review_transition") {
|
|
136
148
|
const verdict = evaluatePlanningReview(input.planning_review);
|
|
137
149
|
if (verdict.outcome === "PASS") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alphazede/bearing-lite",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Skills-first Agent Plugin for planning, routing, bounded execution, and independent review of repository work—without CLI, MCP, server, or hidden runtime state.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-plugins",
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "bearing-lite",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.2",
|
|
5
5
|
"description": "Skills-first portable plugin that routes repository work through the smallest valid planning stages and agent roles, using project Markdown as the only task record.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "William Rumph / AlphaZede",
|
|
@@ -23,28 +23,22 @@
|
|
|
23
23
|
"approval_receipt"
|
|
24
24
|
],
|
|
25
25
|
"properties": {
|
|
26
|
-
"schema_version": {
|
|
27
|
-
"schema": {
|
|
28
|
-
"id": {
|
|
29
|
-
"state": {
|
|
30
|
-
"subject": {
|
|
31
|
-
"repositories": {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
},
|
|
35
|
-
"baseline": { "type": "object", "minProperties": 1, "additionalProperties": true },
|
|
36
|
-
"granting_owner_decisions": {
|
|
37
|
-
"type": "array",
|
|
38
|
-
"items": { "type": "string", "minLength": 1 }
|
|
39
|
-
},
|
|
26
|
+
"schema_version": {"type": "string", "minLength": 1},
|
|
27
|
+
"schema": {"type": "string", "minLength": 1, "description": "Envelope schema identity"},
|
|
28
|
+
"id": {"type": "string", "minLength": 1, "description": "Authority envelope ID"},
|
|
29
|
+
"state": {"type": "string", "minLength": 1},
|
|
30
|
+
"subject": {"type": "object", "minProperties": 1, "additionalProperties": true},
|
|
31
|
+
"repositories": {"type": "array", "items": {"type": "object", "additionalProperties": true}},
|
|
32
|
+
"baseline": {"type": "object", "minProperties": 1, "additionalProperties": true},
|
|
33
|
+
"granting_owner_decisions": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
|
40
34
|
"allowed": {
|
|
41
35
|
"type": "object",
|
|
42
36
|
"additionalProperties": true,
|
|
43
37
|
"required": ["scope", "actions", "paths"],
|
|
44
38
|
"properties": {
|
|
45
|
-
"scope": {
|
|
46
|
-
"actions": {
|
|
47
|
-
"paths": {
|
|
39
|
+
"scope": {"type": "array", "items": {"type": "string"}},
|
|
40
|
+
"actions": {"type": "array", "items": {"type": "string"}},
|
|
41
|
+
"paths": {"type": "array", "items": {"type": "string"}}
|
|
48
42
|
}
|
|
49
43
|
},
|
|
50
44
|
"prohibited": {
|
|
@@ -52,24 +46,51 @@
|
|
|
52
46
|
"additionalProperties": true,
|
|
53
47
|
"required": ["scope", "actions", "paths"],
|
|
54
48
|
"properties": {
|
|
55
|
-
"scope": {
|
|
56
|
-
"actions": {
|
|
57
|
-
"paths": {
|
|
49
|
+
"scope": {"type": "array", "items": {"type": "string"}},
|
|
50
|
+
"actions": {"type": "array", "items": {"type": "string"}},
|
|
51
|
+
"paths": {"type": "array", "items": {"type": "string"}}
|
|
58
52
|
}
|
|
59
53
|
},
|
|
60
|
-
"role_grants": {
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
"effective": { "type": "boolean", "description": "Machine-enforced effectiveness. Boolean only: a string is not an effectiveness decision." },
|
|
65
|
-
"expiry_conditions": {
|
|
66
|
-
"type": "array",
|
|
67
|
-
"items": { "type": "string", "minLength": 1 }
|
|
68
|
-
},
|
|
69
|
-
"supersedes": {
|
|
70
|
-
"type": "array",
|
|
71
|
-
"items": { "type": "string" }
|
|
54
|
+
"role_grants": {"type": "array", "items": {"type": "object", "additionalProperties": true}},
|
|
55
|
+
"effective": {
|
|
56
|
+
"type": "boolean",
|
|
57
|
+
"description": "Machine-enforced effectiveness. Boolean only: a string is not an effectiveness decision."
|
|
72
58
|
},
|
|
73
|
-
"
|
|
74
|
-
|
|
59
|
+
"expiry_conditions": {"type": "array", "items": {"type": "string", "minLength": 1}},
|
|
60
|
+
"supersedes": {"type": "array", "items": {"type": "string"}},
|
|
61
|
+
"approval_receipt": {"type": "object", "additionalProperties": true},
|
|
62
|
+
"continuation": {
|
|
63
|
+
"type": "object",
|
|
64
|
+
"additionalProperties": false,
|
|
65
|
+
"required": ["granted", "owner_decision_id", "exclusions", "expires_at"],
|
|
66
|
+
"properties": {
|
|
67
|
+
"granted": {"type": "boolean"},
|
|
68
|
+
"owner_decision_id": {"type": "string", "minLength": 1},
|
|
69
|
+
"exclusions": {
|
|
70
|
+
"type": "array",
|
|
71
|
+
"uniqueItems": true,
|
|
72
|
+
"items": {"type": "string", "minLength": 1},
|
|
73
|
+
"allOf": [
|
|
74
|
+
{"contains": {"const": "scope_change"}},
|
|
75
|
+
{"contains": {"const": "budget_exhaustion"}},
|
|
76
|
+
{"contains": {"const": "owner_hold"}},
|
|
77
|
+
{"contains": {"const": "owner_only_actions"}}
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
"expires_at": {"type": ["string", "null"], "format": "date-time", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?Z$"}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"allOf": [
|
|
85
|
+
{
|
|
86
|
+
"if": {"required": ["continuation"]},
|
|
87
|
+
"then": {
|
|
88
|
+
"properties": {
|
|
89
|
+
"expiry_conditions": {"minItems": 1},
|
|
90
|
+
"granting_owner_decisions": {"minItems": 1},
|
|
91
|
+
"approval_receipt": {"minProperties": 1}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
]
|
|
75
96
|
}
|
|
@@ -5,29 +5,18 @@
|
|
|
5
5
|
"description": "Append-only decisions and authority-event history plus the generation-bound checkout lease. The full mutable file digest is not the stable SEIT execution baseline. Extra lifecycle metadata is allowed at the document root. Lease identity fields stay closed.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": true,
|
|
8
|
-
"required": [
|
|
9
|
-
"schema_version",
|
|
10
|
-
"journey",
|
|
11
|
-
"checkout_lease",
|
|
12
|
-
"decisions",
|
|
13
|
-
"open_decisions",
|
|
14
|
-
"planning_receipts",
|
|
15
|
-
"lineup_selection"
|
|
16
|
-
],
|
|
8
|
+
"required": ["schema_version", "journey", "checkout_lease", "decisions", "open_decisions", "planning_receipts", "lineup_selection"],
|
|
17
9
|
"properties": {
|
|
18
|
-
"schema_version": {
|
|
10
|
+
"schema_version": {"type": "string", "minLength": 1},
|
|
19
11
|
"journey": {
|
|
20
12
|
"type": "object",
|
|
21
13
|
"additionalProperties": true,
|
|
22
14
|
"required": ["id", "title", "status", "planning_repository"],
|
|
23
15
|
"properties": {
|
|
24
|
-
"id": {
|
|
25
|
-
"title": {
|
|
26
|
-
"status": {
|
|
27
|
-
|
|
28
|
-
"enum": ["planning", "implementation", "complete", "cancelled"]
|
|
29
|
-
},
|
|
30
|
-
"planning_repository": { "type": "string", "minLength": 1 }
|
|
16
|
+
"id": {"type": "string", "minLength": 1},
|
|
17
|
+
"title": {"type": "string", "minLength": 1},
|
|
18
|
+
"status": {"type": "string", "enum": ["planning", "implementation", "complete", "cancelled"]},
|
|
19
|
+
"planning_repository": {"type": "string", "minLength": 1}
|
|
31
20
|
}
|
|
32
21
|
},
|
|
33
22
|
"checkout_lease": {
|
|
@@ -45,57 +34,162 @@
|
|
|
45
34
|
"state"
|
|
46
35
|
],
|
|
47
36
|
"properties": {
|
|
48
|
-
"journey": {
|
|
49
|
-
"controller": {
|
|
50
|
-
"repository": {
|
|
51
|
-
"checkout": {
|
|
52
|
-
"branch": {
|
|
53
|
-
"candidate_revision": {
|
|
54
|
-
"acquired_at": {
|
|
55
|
-
"generation": {
|
|
56
|
-
"state": {
|
|
57
|
-
"released_at": {
|
|
58
|
-
"release_reason": {
|
|
59
|
-
},
|
|
60
|
-
"if": {
|
|
61
|
-
"properties": {
|
|
62
|
-
"state": { "const": "released" }
|
|
63
|
-
}
|
|
37
|
+
"journey": {"type": "string", "minLength": 1},
|
|
38
|
+
"controller": {"type": "string", "minLength": 1},
|
|
39
|
+
"repository": {"type": "string", "minLength": 1},
|
|
40
|
+
"checkout": {"type": "string", "minLength": 1},
|
|
41
|
+
"branch": {"type": "string", "minLength": 1},
|
|
42
|
+
"candidate_revision": {"type": "string", "minLength": 1},
|
|
43
|
+
"acquired_at": {"type": "string", "minLength": 1},
|
|
44
|
+
"generation": {"type": "integer", "minimum": 1},
|
|
45
|
+
"state": {"enum": ["active", "released"]},
|
|
46
|
+
"released_at": {"type": "string", "format": "date-time"},
|
|
47
|
+
"release_reason": {"type": "string", "minLength": 1}
|
|
64
48
|
},
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
}
|
|
49
|
+
"if": {"properties": {"state": {"const": "released"}}},
|
|
50
|
+
"then": {"required": ["released_at", "release_reason"]}
|
|
68
51
|
},
|
|
69
52
|
"history": {
|
|
70
53
|
"type": "object",
|
|
71
54
|
"additionalProperties": true,
|
|
72
55
|
"description": "Optional append-only Journey history wrapper",
|
|
73
56
|
"properties": {
|
|
74
|
-
"decisions": {
|
|
75
|
-
"authority_events": {
|
|
57
|
+
"decisions": {"type": "array", "items": {"type": "object", "additionalProperties": true}},
|
|
58
|
+
"authority_events": {"type": "array", "items": {"type": "object", "additionalProperties": true}}
|
|
76
59
|
}
|
|
77
60
|
},
|
|
78
61
|
"decisions": {
|
|
79
62
|
"type": "array",
|
|
80
63
|
"description": "Append-only confirmed owner decisions",
|
|
81
|
-
"items": {
|
|
64
|
+
"items": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"additionalProperties": true,
|
|
67
|
+
"allOf": [
|
|
68
|
+
{
|
|
69
|
+
"if": {"required": ["record_type"], "properties": {"record_type": {"const": "owner_stop"}}},
|
|
70
|
+
"then": {"$ref": "#/$defs/ownerStop"}
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
82
74
|
},
|
|
83
75
|
"authority_events": {
|
|
84
76
|
"type": "array",
|
|
85
77
|
"description": "Append-only authority grant, amend, revoke, or supersede events",
|
|
86
|
-
"items": {
|
|
78
|
+
"items": {"type": "object", "additionalProperties": true}
|
|
87
79
|
},
|
|
88
80
|
"open_decisions": {
|
|
89
81
|
"type": "array",
|
|
90
|
-
"items": {
|
|
82
|
+
"items": {
|
|
83
|
+
"type": "object",
|
|
84
|
+
"additionalProperties": true,
|
|
85
|
+
"allOf": [
|
|
86
|
+
{
|
|
87
|
+
"if": {"required": ["record_type"], "properties": {"record_type": {"const": "owner_stop"}}},
|
|
88
|
+
"then": {"$ref": "#/$defs/ownerStop"}
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
91
92
|
},
|
|
92
|
-
"planning_receipts": {
|
|
93
|
+
"planning_receipts": {"type": "array", "items": {"type": "object", "additionalProperties": true}},
|
|
94
|
+
"lineup_selection": {"type": "object", "additionalProperties": true},
|
|
95
|
+
"owner_wait_tracking": {"type": "boolean", "description": "Explicit coverage marker; absence is unavailable, never zero owner wait."},
|
|
96
|
+
"owner_blocked_intervals": {
|
|
93
97
|
"type": "array",
|
|
94
|
-
"items": {
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
"items": {
|
|
99
|
+
"type": "object",
|
|
100
|
+
"additionalProperties": false,
|
|
101
|
+
"required": ["decision_ids", "started_at", "ended_at"],
|
|
102
|
+
"properties": {
|
|
103
|
+
"decision_ids": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "minLength": 1}},
|
|
104
|
+
"started_at": {"type": "string", "format": "date-time", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?Z$"},
|
|
105
|
+
"ended_at": {"type": ["string", "null"], "format": "date-time", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?Z$"}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"$defs": {
|
|
111
|
+
"ownerStop": {
|
|
97
112
|
"type": "object",
|
|
98
|
-
"additionalProperties": true
|
|
113
|
+
"additionalProperties": true,
|
|
114
|
+
"required": [
|
|
115
|
+
"record_type",
|
|
116
|
+
"id",
|
|
117
|
+
"class",
|
|
118
|
+
"question",
|
|
119
|
+
"why_owner",
|
|
120
|
+
"evidence_ref",
|
|
121
|
+
"affected_slices",
|
|
122
|
+
"blocking",
|
|
123
|
+
"status",
|
|
124
|
+
"created_at",
|
|
125
|
+
"asked_at",
|
|
126
|
+
"answered_at",
|
|
127
|
+
"cancelled_at",
|
|
128
|
+
"round_trip_id"
|
|
129
|
+
],
|
|
130
|
+
"properties": {
|
|
131
|
+
"record_type": {"const": "owner_stop"},
|
|
132
|
+
"id": {"type": "string", "minLength": 1},
|
|
133
|
+
"class": {"enum": ["A", "B", "C", "D", "E", "F"]},
|
|
134
|
+
"question": {"type": "string", "minLength": 1},
|
|
135
|
+
"why_owner": {"type": "string", "minLength": 1},
|
|
136
|
+
"evidence_ref": {"type": "string", "minLength": 1},
|
|
137
|
+
"affected_slices": {"type": "array", "uniqueItems": true, "items": {"type": "string", "minLength": 1}},
|
|
138
|
+
"blocking": {"type": "boolean"},
|
|
139
|
+
"status": {"enum": ["queued", "asked", "answered", "cancelled"]},
|
|
140
|
+
"created_at": {"type": "string", "format": "date-time", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?Z$"},
|
|
141
|
+
"asked_at": {"type": ["string", "null"], "format": "date-time", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?Z$"},
|
|
142
|
+
"answered_at": {"type": ["string", "null"], "format": "date-time", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?Z$"},
|
|
143
|
+
"cancelled_at": {"type": ["string", "null"], "format": "date-time", "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?Z$"},
|
|
144
|
+
"round_trip_id": {"type": ["string", "null"], "minLength": 1},
|
|
145
|
+
"answer_ref": {"type": "string", "minLength": 1}
|
|
146
|
+
},
|
|
147
|
+
"allOf": [
|
|
148
|
+
{
|
|
149
|
+
"if": {"properties": {"status": {"const": "queued"}}},
|
|
150
|
+
"then": {
|
|
151
|
+
"properties": {
|
|
152
|
+
"asked_at": {"type": "null"},
|
|
153
|
+
"answered_at": {"type": "null"},
|
|
154
|
+
"cancelled_at": {"type": "null"},
|
|
155
|
+
"round_trip_id": {"type": "null"}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"if": {"properties": {"status": {"const": "asked"}}},
|
|
161
|
+
"then": {
|
|
162
|
+
"properties": {
|
|
163
|
+
"asked_at": {"type": "string"},
|
|
164
|
+
"round_trip_id": {"type": "string", "minLength": 1},
|
|
165
|
+
"answered_at": {"type": "null"},
|
|
166
|
+
"cancelled_at": {"type": "null"}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"if": {"properties": {"status": {"const": "answered"}}},
|
|
172
|
+
"then": {
|
|
173
|
+
"properties": {
|
|
174
|
+
"asked_at": {"type": "string"},
|
|
175
|
+
"answered_at": {"type": "string"},
|
|
176
|
+
"cancelled_at": {"type": "null"},
|
|
177
|
+
"round_trip_id": {"type": "string", "minLength": 1}
|
|
178
|
+
},
|
|
179
|
+
"required": ["answer_ref"]
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"if": {"properties": {"status": {"const": "cancelled"}}},
|
|
184
|
+
"then": {"properties": {"cancelled_at": {"type": "string"}, "answered_at": {"type": "null"}}}
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"allOf": [
|
|
190
|
+
{
|
|
191
|
+
"if": {"required": ["owner_wait_tracking"], "properties": {"owner_wait_tracking": {"const": true}}},
|
|
192
|
+
"then": {"required": ["owner_blocked_intervals"]}
|
|
99
193
|
}
|
|
100
|
-
|
|
194
|
+
]
|
|
101
195
|
}
|
|
@@ -3,7 +3,7 @@ name: bearing-lite
|
|
|
3
3
|
description: Bearing Lite Router for Journeys. Not for ordinary work, assigned packets, implementation, or publication.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Router alone writes Journey planning state, owns owner conversation, and owns Expedition sequencing;
|
|
7
7
|
planning nodes return owner questions. Plugin hosts are partial; skill-copy is skills-only.
|
|
8
8
|
|
|
9
9
|
1. Say `Preparing this Journey.` Acquire or resume a generation-bound checkout lease before
|
|
@@ -19,14 +19,14 @@ planning nodes return owner questions. Plugin hosts are partial; skill-copy is s
|
|
|
19
19
|
4. Run Repository Fit → Set Bearings → Gather Supplies; unresolved material intent blocks Map the Route.
|
|
20
20
|
5. Invoke Map the Route after settled intent. Do not ask for lineup or route
|
|
21
21
|
before it; carry owner-supplied lineup and `review_cadence: at-end` as proposals.
|
|
22
|
-
6. Enforce `references/review-policy.md`. Show one integrated
|
|
22
|
+
6. Enforce `references/review-policy.md` and `references/owner-stops.md`. Show one integrated
|
|
23
23
|
approval-or-change gate for outcome, design, route, lineup, role states,
|
|
24
24
|
reasoning, cadence, and plan. Record the approved Journey type and snapshot.
|
|
25
25
|
Never add a staged lineup or route-review gate.
|
|
26
26
|
Dispatch only after approval.
|
|
27
27
|
7. Crewmate and Explorer may continue in-wave. `work_class: light` slices go to the
|
|
28
28
|
Light Implementer; a `reclassify: judgement` return re-dispatches to the Crewmate.
|
|
29
|
-
Use
|
|
29
|
+
Use visible wave receipts and update implementation and review once per wave.
|
|
30
30
|
|
|
31
31
|
Return `READY`, `WAITING_ON`, `OWNER_DECISION_REQUIRED`, or `COMPLETE`.
|
|
32
32
|
`max_assurance_rounds` is 1 per declared phase or wave-end, not per Journey;
|
|
@@ -41,6 +41,11 @@ never a deviation.
|
|
|
41
41
|
|
|
42
42
|
Only verified primary unavailability activates its approved fallback. If
|
|
43
43
|
both are unavailable, return `OWNER_DECISION_REQUIRED`.
|
|
44
|
+
Activation within the frozen ordered fallbacks is a dated execution receipt,
|
|
45
|
+
not a lineup amendment or a new owner approval. Verify the approved activation
|
|
46
|
+
condition and remaining eligible routes before escalating exhaustion. A new
|
|
47
|
+
identity or changed fallback condition requires an owner amendment; follow
|
|
48
|
+
`owner-stops.md` for classification and batching.
|
|
44
49
|
|
|
45
50
|
This catalog is the single lineup source. A legacy
|
|
46
51
|
`~/.agents/bearing-lite/default-role-lineup.md` is never read or created;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Owner decisions and continuation
|
|
2
|
+
|
|
3
|
+
One integrated approval covers the approved work and its continuation grant.
|
|
4
|
+
Before asking, identify the unresolved decision, affected slices, evidence,
|
|
5
|
+
and why the current policy or authority does not answer it. Never invent an
|
|
6
|
+
extra role, review gate, approval checkpoint, or scope to resolve uncertainty.
|
|
7
|
+
|
|
8
|
+
| Class | Decision | Router behavior |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| A | Existing policy | Apply the cited rule and record a dated execution receipt. A real policy conflict is a C boundary decision. |
|
|
11
|
+
| B | Approved fallback | Verify unavailability under the frozen fallback condition; activate the next eligible approved route and record evidence. Changing the lineup or fallback condition is C. |
|
|
12
|
+
| C | Bound, scope, or policy conflict | Ask for the smallest amendment when it blocks ready work. Never reset a spent bound. |
|
|
13
|
+
| D | Continue approved work | Use the effective continuation grant; never ask again while its conditions hold. Missing or expired authority is F. |
|
|
14
|
+
| E | Integrated plan approval | Present the package once for approval or change; execution waits for explicit approval. |
|
|
15
|
+
| F | Authority reserved to the owner | Ask only when the action is not already expressly authorized. Owner holds remain effective until explicitly lifted. |
|
|
16
|
+
|
|
17
|
+
A/B/D continuation requires verified authority, scope, budget, exclusions,
|
|
18
|
+
expiry, and owner-hold checks. Missing evidence is `NEEDS_MORE_EVIDENCE`, not
|
|
19
|
+
permission and not automatically an owner question. Recover discoverable
|
|
20
|
+
evidence first; escalate a real unresolved boundary as C or F. Fallback
|
|
21
|
+
activation is an execution receipt, not an authority amendment. Only the
|
|
22
|
+
owner changes the frozen lineup or grants authority.
|
|
23
|
+
|
|
24
|
+
## Approval and authority
|
|
25
|
+
|
|
26
|
+
Map the Route includes `authority.json.continuation` in the integrated gate:
|
|
27
|
+
`granted`, `owner_decision_id`, named `exclusions`, and `expires_at` (UTC or
|
|
28
|
+
null for event-based expiry). The surrounding envelope retains allowed and
|
|
29
|
+
prohibited actions/paths, role grants, approval receipt, and nonempty
|
|
30
|
+
`expiry_conditions`. Record explicit approval against the exact package;
|
|
31
|
+
the continuation decision ID must occur in `granting_owner_decisions`.
|
|
32
|
+
No grant is inferred from silence, a lineup selection, or passing checks.
|
|
33
|
+
|
|
34
|
+
Always exclude scope change, budget exhaustion, owner holds, and owner-only
|
|
35
|
+
actions from the continuation grant. A separate explicit action grant can
|
|
36
|
+
authorize an otherwise owner-only action; continuation cannot create it.
|
|
37
|
+
Revocation, supersession, expiry, or changed authority invalidates the grant.
|
|
38
|
+
An older envelope without continuation remains valid historical data but
|
|
39
|
+
provides no standing continuation grant. Do not manufacture a retroactive one.
|
|
40
|
+
|
|
41
|
+
For first approval show outcome, scope/exclusions, role responsibilities,
|
|
42
|
+
route, bounds, risks, open decisions and proof coverage in a concise summary.
|
|
43
|
+
For revisions show changed requirements, design, proof cases, slices,
|
|
44
|
+
lineup, authority and bounds against the last owner-reviewed package, citing
|
|
45
|
+
both revisions/digests. Explain invalidated approvals and unresolved decisions.
|
|
46
|
+
Keep the complete frozen `review.html` accessible in both cases; a diff or
|
|
47
|
+
freeze PASS is neither approval nor proof of semantic completeness. An
|
|
48
|
+
unchanged package does not need reapproval. A changed package returns to the
|
|
49
|
+
same gate, never an extra gate.
|
|
50
|
+
|
|
51
|
+
## Queue and continue
|
|
52
|
+
|
|
53
|
+
Keep pending questions in the existing `journey.json.open_decisions` array
|
|
54
|
+
as typed `record_type: owner_stop` records. Preserve stable IDs when moving
|
|
55
|
+
answered records to `decisions`; append owner answers to normal history.
|
|
56
|
+
Automatic resolutions and unsolicited owner directions remain normal dated
|
|
57
|
+
receipts, not fabricated questions. Required fields are defined by
|
|
58
|
+
`schemas/journey.schema.json` and checked by the metrics helper.
|
|
59
|
+
|
|
60
|
+
Queue nonblocking questions until wave end and present one batch with the
|
|
61
|
+
wave receipt. Queue nonblocking owner-only closeout actions until Journey
|
|
62
|
+
end. Required credentials, publication prerequisites, or other owner-only
|
|
63
|
+
dependencies surface immediately when they block ready work. Do not defer
|
|
64
|
+
safety/integrity intervention or an explicit owner stop. Each actual
|
|
65
|
+
presentation has a stable `round_trip_id`; questions in the same batch share
|
|
66
|
+
that ID and the exact same presentation timestamp.
|
|
67
|
+
Record `asked_at` when presented, not when drafted or queued; `answered_at`
|
|
68
|
+
when the owner answers. Cancellation uses `cancelled_at`, never a fabricated
|
|
69
|
+
answer. Times are UTC with a `Z` suffix and either whole seconds or exactly
|
|
70
|
+
three fractional digits (milliseconds); normalize host timestamps before
|
|
71
|
+
recording. Re-presenting an unanswered question keeps its ID and
|
|
72
|
+
original asked time; it is not another distinct question.
|
|
73
|
+
|
|
74
|
+
While waiting, walk the approved slice graph. Dispatch only READY slices
|
|
75
|
+
with satisfied dependencies, active authority, valid lease, available route,
|
|
76
|
+
and verified independence from the question and other running slices.
|
|
77
|
+
Disjoint writes alone do not prove independence: check shared runtime,
|
|
78
|
+
resources, integration order, and read/write dependencies. `parallel_safe`
|
|
79
|
+
is evidence to inspect, not permission. Respect host concurrency limits and
|
|
80
|
+
never dispatch completed or already-running work again. Keep dependent work
|
|
81
|
+
pending. Owner holds apply to their stated scope, including the whole Journey
|
|
82
|
+
when so directed; they cannot be bypassed by calling work independent.
|
|
83
|
+
|
|
84
|
+
## Deterministic checks and measurement
|
|
85
|
+
|
|
86
|
+
Before a proposed stop, run `hooks/transition-order.cjs` with
|
|
87
|
+
`action_kind: owner_stop_check` and `owner_stop` containing `class`,
|
|
88
|
+
`blocking`, `evidence_ref`, `resolution_ref`, `authority`, `checked_at`,
|
|
89
|
+
and `checks`. Checks are explicit booleans: `scope`, `budget`, `exclusions`,
|
|
90
|
+
`expiry`, `owner_hold`, plus `policy` for A or `fallback` for B. Router must
|
|
91
|
+
verify them against the actual frozen inputs; the helper does not authenticate
|
|
92
|
+
receipts or interpret arbitrary path globs or expiry prose. C/E/F need the
|
|
93
|
+
class, evidence reference and blocking flag; return ASK or QUEUE. A/B/D
|
|
94
|
+
return CONTINUE only with the grant and all required checks. This is a
|
|
95
|
+
procedural transition adapter, not a new registered host event, permission
|
|
96
|
+
grant, scheduler, or security boundary. Skills-only hosts execute the same
|
|
97
|
+
checklist and disclose unavailable deterministic checks.
|
|
98
|
+
|
|
99
|
+
New Journeys set `owner_wait_tracking: true` and initialize
|
|
100
|
+
`owner_blocked_intervals: []`. Record intervals only while no authorized ready
|
|
101
|
+
work can progress specifically because of unanswered owner questions. Each
|
|
102
|
+
interval lists their `decision_ids`, `started_at`, and nullable `ended_at`.
|
|
103
|
+
End the interval as soon as work can progress, even if some questions remain
|
|
104
|
+
unanswered. Do not treat every dependency wait, off-hours gap, or commit gap as
|
|
105
|
+
owner-blocked time. Never backfill unknown times. Legacy Journeys without
|
|
106
|
+
tracking report `unavailable`, not zero waiting.
|
|
107
|
+
|
|
108
|
+
Run `node <plugin root>/hooks/owner-stops.cjs <journey.json> <as-of-UTC>` at
|
|
109
|
+
wave receipts and final closeout. It validates typed records, rejects duplicate
|
|
110
|
+
IDs or inconsistent times, counts `decisions_asked`, distinct approval
|
|
111
|
+
`round_trips`, pending/queued/cancelled questions and A–F counts, and reports
|
|
112
|
+
`response_ms` (sum of completed response intervals), `pending_response_ms`,
|
|
113
|
+
`response_window_ms` (union of asked-to-answer/cancellation/as-of intervals),
|
|
114
|
+
and `blocked_ms` (union of the explicitly recorded fully blocked intervals).
|
|
115
|
+
Overlapping questions are not additive wall-clock wait. Local records only:
|
|
116
|
+
no telemetry or network transmission. Closeout renders these metrics and
|
|
117
|
+
coverage limitations; it must not claim measured savings from legacy gaps.
|
|
118
|
+
|
|
119
|
+
Operational target after settled scope: zero unnecessary stops per wave;
|
|
120
|
+
one integrated approval batch and one closeout batch per unchanged Journey
|
|
121
|
+
when closeout needs owner authority. Exceptions are recorded, never suppressed
|
|
122
|
+
to hit a quota. Forecast savings only from verified classified observations.
|
|
@@ -35,3 +35,8 @@ confirmation or rereview returns `OWNER_AMENDMENT_REQUIRED`.
|
|
|
35
35
|
This gate reviews planning artifacts before dispatch. It never invokes a
|
|
36
36
|
reviewer. Implementation assurance remains governed separately by
|
|
37
37
|
`max_assurance_rounds` and task `required_assurance` / `assurance_rounds`.
|
|
38
|
+
|
|
39
|
+
Owner presentation and continuation follow `owner-stops.md`: one integrated
|
|
40
|
+
gate includes the bounded grant, first-approval summary or revision diff, open
|
|
41
|
+
decisions, and access to the full frozen package. This adds no reviewer,
|
|
42
|
+
review round, or approval checkpoint and does not alter the bounds above.
|
package/skills/explorer/SKILL.md
CHANGED
|
@@ -13,7 +13,6 @@ description: >
|
|
|
13
13
|
Wave authority. Coordinates more and implements less than Crewmate.
|
|
14
14
|
|
|
15
15
|
## Inputs and match
|
|
16
|
-
|
|
17
16
|
- **Inputs:** approved baseline, wave objective, packet graph, dependencies,
|
|
18
17
|
scope, authority, lineup from the recorded Journey snapshot, visible wave
|
|
19
18
|
receipt, acceptance, and compact return schema.
|
|
@@ -21,7 +20,6 @@ Wave authority. Coordinates more and implements less than Crewmate.
|
|
|
21
20
|
- **Non-match:** one bounded packet needs no orchestration, multiple waves conflict, or assurance alone is requested.
|
|
22
21
|
|
|
23
22
|
## Algorithm
|
|
24
|
-
|
|
25
23
|
1. Continue this wave when identity, authority, route, and generation are
|
|
26
24
|
unchanged; otherwise start fresh. Verify wave readiness, packet boundaries,
|
|
27
25
|
dependencies, and approved identities from the recorded Journey snapshot,
|
|
@@ -42,6 +40,9 @@ Wave authority. Coordinates more and implements less than Crewmate.
|
|
|
42
40
|
4. Inspect compact returns against write sets and acceptance; integrate
|
|
43
41
|
evidence without implementing. Update `implementation.json` and `review.html`
|
|
44
42
|
once per wave, plus owner-decision or blocker changes.
|
|
43
|
+
Apply `../bearing-lite/references/owner-stops.md` for queued questions,
|
|
44
|
+
blocking prerequisites, proven-independent progress and owner holds; never
|
|
45
|
+
add unapproved roles or gates.
|
|
45
46
|
5. Dispatch declared assurance automatically at wave-end on this wave's
|
|
46
47
|
integrated candidate. Deterministic checks always run. Honor
|
|
47
48
|
`max_assurance_rounds` of 1 per declared phase or wave from visible
|
|
@@ -53,7 +54,6 @@ Wave authority. Coordinates more and implements less than Crewmate.
|
|
|
53
54
|
`COMPLETE`, deployment checks do not reopen assurance.
|
|
54
55
|
|
|
55
56
|
## Return and recovery
|
|
56
|
-
|
|
57
57
|
Return `READY`, `REROUTED`, `WAITING_ON`, or `OWNER_DECISION_REQUIRED` with
|
|
58
58
|
verdict, candidate_ref, changed_paths, tests, findings, and blocker. Reroute only from new evidence; three attempts per packet.
|
|
59
59
|
|
|
@@ -46,7 +46,8 @@ Fresh planning node. The Router writes Journey state and owns owner conversation
|
|
|
46
46
|
requirements. Two `review.html` states: `planning-review` and `final-closeout`.
|
|
47
47
|
5. Give every slice stable requirement/design/SEIT IDs, dependencies, exact
|
|
48
48
|
write set, authority, role, session rule, evidence, recovery, and stop rule.
|
|
49
|
-
6.
|
|
49
|
+
6. Follow `../bearing-lite/references/owner-stops.md`.
|
|
50
|
+
Open and verify HTML, then request exactly one integrated owner review
|
|
50
51
|
of outcome, design, route, lineup, cadence, and plan. Dispatch remains
|
|
51
52
|
prohibited until approval. An owner change regenerates affected artifacts,
|
|
52
53
|
then returns to this same gate; never insert a lineup or route-review pause.
|
package/skills/scribe/SKILL.md
CHANGED
|
@@ -22,6 +22,10 @@ Event side lane. Transcribes; cannot activate authority.
|
|
|
22
22
|
|
|
23
23
|
1. Append owner decisions, authority events, ledger snapshots, lineup
|
|
24
24
|
selections, and configuration digest to `journey.json` history.
|
|
25
|
+
Follow `../bearing-lite/references/owner-stops.md` for typed owner-stop
|
|
26
|
+
records: preserve question and round-trip IDs, record actual asked/answered
|
|
27
|
+
UTC times and explicit fully blocked intervals, and never infer missing
|
|
28
|
+
times. Automatic resolutions and owner steering are not invented questions.
|
|
25
29
|
2. Do not activate authority or invent unresolved choices.
|
|
26
30
|
3. Do not write Journey selections into `lineups.json` unless the owner
|
|
27
31
|
asks to save a reusable profile.
|