space-architect 9.8.0 → 9.9.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/lib/space_architect/cli/architect.rb +54 -0
- data/lib/space_architect/iteration_emission.rb +25 -2
- data/lib/space_architect/version.rb +1 -1
- data/skill/architect/SKILL.md +4 -2
- data/skill/architect-discuss/SKILL.md +1 -1
- data/skill/architect-discuss/dispatch.md +12 -6
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bf5117e5de28d8f40811d45561c37ccd7852a1dc27758af06f08cc565aa90b65
|
|
4
|
+
data.tar.gz: 9c5fe91d46305b83d8f0fe3f17a689238ad6e81d620f95009b96c9f74da38b14
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4698ad55f2c91d9a71fd996ad3523c6155aefad548c2ac9dba8a1f51bc115f2cfdad0223cc0353aefda83eed5c874625b02a58fc2b065feb124adaf0202c0674
|
|
7
|
+
data.tar.gz: d031b8fc81071a4c8a68892d07af6f8b4b0bf0c458a605c437fb513dd982fd7f79afb8cae8ee82bdd6281e5bd05cbdad8bb2c22edaa07f753e7a6a73e1fd9b14
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,30 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [9.9.0] - 2026-10-30
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`architect ping` (I11)** — phase pings for driver-mode loops: `architect
|
|
13
|
+
ping ITERATION PHASE` emits an iteration phase transition (spec-launched,
|
|
14
|
+
builders-settled, judge-running) to the configured space server via the I16
|
|
15
|
+
emission surface. Vocabulary-first validation (unknown phase = 422-style
|
|
16
|
+
error naming the set), `--note` rides along, `--space` overrides the cwd
|
|
17
|
+
walk, and an unconfigured emission stack is inert — one inform line, exit 0.
|
|
18
|
+
A ping never gates the loop: every failure mode is one line.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Narration cadence (I11)** — shipped skills and docs carry the three-kind
|
|
23
|
+
cadence: narrations are exactly verdict-landed, exception, and
|
|
24
|
+
plan-complete; builders-settled and judge-settled stop being narration
|
|
25
|
+
kinds (the driver pings those transitions instead). Back-to-back rule:
|
|
26
|
+
when two narration-worthy events are back-to-back, one narration lands —
|
|
27
|
+
the more-final kind absorbs the earlier. dispatch.md's narrator contract
|
|
28
|
+
now asks for composed prose (situates the project, the iteration's place,
|
|
29
|
+
what happened and what it means), never transcribed STATUS lines, run ids,
|
|
30
|
+
or gate vectors.
|
|
31
|
+
|
|
8
32
|
## [9.8.0] - 2026-10-30
|
|
9
33
|
|
|
10
34
|
### Removed
|
|
@@ -904,6 +904,59 @@ module Space::Architect
|
|
|
904
904
|
end
|
|
905
905
|
end
|
|
906
906
|
|
|
907
|
+
# I11: the phase ping — one small "where is the loop now" POST per
|
|
908
|
+
# playbook step; the between-command currency that lets narrations stay
|
|
909
|
+
# rare prose. An automated playbook step, deliberately quieter than
|
|
910
|
+
# emit: unconfigured is one inert stdout line; a POST failure NEVER
|
|
911
|
+
# fails the command (exit 0 — the Emitter's single stderr line is the
|
|
912
|
+
# whole report); the token never appears in any output. Writes nothing
|
|
913
|
+
# to disk — a ping is a fact about the loop, not a loop step, so the
|
|
914
|
+
# entry lookup is read-only (no ArchitectProject mutation).
|
|
915
|
+
class Ping < BaseCommand
|
|
916
|
+
desc "POST one phase ping for an iteration (spec-launched/builders-settled/judge-running; best-effort — never fails the loop step)"
|
|
917
|
+
phase 53, "Project"
|
|
918
|
+
argument :iteration, required: true, desc: "Iteration name"
|
|
919
|
+
argument :phase, required: true, desc: "Phase ping kind: spec-launched, builders-settled, or judge-running"
|
|
920
|
+
option :space, default: nil, desc: "Space identifier (default: $PWD)"
|
|
921
|
+
option :note, default: nil, desc: "Optional note carried in the ping payload (nil/empty omitted)"
|
|
922
|
+
|
|
923
|
+
def call(iteration:, phase:, space: nil, note: nil, **opts)
|
|
924
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
925
|
+
handle_errors do
|
|
926
|
+
# Vocabulary is validated BEFORE space resolution — a typo'd phase
|
|
927
|
+
# must name the known set, not space-resolution noise.
|
|
928
|
+
unless IterationEmission::PHASE_KINDS.include?(phase)
|
|
929
|
+
raise Space::Core::Error,
|
|
930
|
+
"unknown phase '#{phase}' — one of: #{IterationEmission::PHASE_KINDS.join(', ')}"
|
|
931
|
+
end
|
|
932
|
+
|
|
933
|
+
render(store.find(space)) do |sp|
|
|
934
|
+
# Read-only slice of the space.yaml iteration record — the exact
|
|
935
|
+
# entry lookup and error text of ArchitectProject#slice_entry,
|
|
936
|
+
# mirrored here rather than instantiated: the ping path never
|
|
937
|
+
# mutates anything on disk (a ping is a fact, not a loop step).
|
|
938
|
+
entry = ((sp.data["project"] || {})["iterations"] || []).find { |s| s["name"] == iteration }
|
|
939
|
+
unless entry
|
|
940
|
+
raise Space::Core::Error,
|
|
941
|
+
"Iteration '#{iteration}' not recorded in space.yaml — run `architect new #{iteration}` first"
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
emitter = IterationEmission.emitter_for(sp)
|
|
945
|
+
if emitter
|
|
946
|
+
res = emitter.post("phase", IterationEmission.build_phase(
|
|
947
|
+
ordinal: entry["ordinal"], name: entry["name"], kind: phase, note: note))
|
|
948
|
+
# res nil: the Emitter already printed its one stderr line —
|
|
949
|
+
# a failed ping stays off stdout and never fails the step.
|
|
950
|
+
terminal.say "pinged #{iteration} #{phase} → #{res[:status]}" if res
|
|
951
|
+
else
|
|
952
|
+
terminal.say "emission off (unconfigured)"
|
|
953
|
+
end
|
|
954
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
955
|
+
end
|
|
956
|
+
end
|
|
957
|
+
end
|
|
958
|
+
end
|
|
959
|
+
|
|
907
960
|
# Pretty-print a pi agent run.jsonl as it streams — the ported runlog
|
|
908
961
|
# printer. No space resolution: the stream is the whole input.
|
|
909
962
|
class Runlog < BaseCommand
|
|
@@ -1498,6 +1551,7 @@ Space::Architect::CLI::Registry.register "install-agents", Space::Architect::C
|
|
|
1498
1551
|
Space::Architect::CLI::Registry.register "runlog", Space::Architect::CLI::Architect::Runlog
|
|
1499
1552
|
Space::Architect::CLI::Registry.register "looplog", Space::Architect::CLI::Architect::Looplog
|
|
1500
1553
|
Space::Architect::CLI::Registry.register "emit", Space::Architect::CLI::Architect::Emit
|
|
1554
|
+
Space::Architect::CLI::Registry.register "ping", Space::Architect::CLI::Architect::Ping
|
|
1501
1555
|
Space::Architect::CLI::Registry.register "bug-report", Space::Architect::CLI::Architect::BugReport
|
|
1502
1556
|
Space::Architect::CLI::Registry.register "cost", Space::Architect::CLI::Architect::Cost
|
|
1503
1557
|
Space::Architect::CLI::Registry.register "brief" do |b|
|
|
@@ -14,6 +14,10 @@ module Space::Architect
|
|
|
14
14
|
# ```rulings block parser. ArchitectProject's five hook call sites guard
|
|
15
15
|
# through `emitter&.post` inside a rescue-all belt; nothing here may ever
|
|
16
16
|
# raise into a loop command or change its exit code, stdout, or commits.
|
|
17
|
+
# I11 extends the same layer additively: the phase mouth (a fifth server
|
|
18
|
+
# mouth) and the `architect ping` payload — one small "where is the loop
|
|
19
|
+
# now" fact per playbook step, the between-command currency that lets
|
|
20
|
+
# narrations stay rare prose.
|
|
17
21
|
module IterationEmission
|
|
18
22
|
# Frozen tuning (mirrors the spec; session-sink pins its own constants the
|
|
19
23
|
# same way): per attempt 2s open / 5s read, at most 2 attempts, retry on
|
|
@@ -22,13 +26,20 @@ module Space::Architect
|
|
|
22
26
|
READ_TIMEOUT = 5
|
|
23
27
|
MAX_ATTEMPTS = 2
|
|
24
28
|
|
|
25
|
-
# The
|
|
26
|
-
|
|
29
|
+
# The server mouths (I15's four frozen; I11 appends the fifth): POST
|
|
30
|
+
# <host>/iterations/ingest/<mouth>.
|
|
31
|
+
MOUTHS = %w[freeze lane verdict integration phase].freeze
|
|
27
32
|
|
|
28
33
|
# Iteration/lane status vocabularies (frozen): nothing else is emitted.
|
|
29
34
|
ITERATION_STATUSES = %w[frozen integrated].freeze
|
|
30
35
|
LANE_STATUSES = %w[complete integrated].freeze
|
|
31
36
|
|
|
37
|
+
# The phase-ping vocabulary (I11, CLI-frozen): nothing else pings. Sibling
|
|
38
|
+
# of the narration kinds — narrations stay rare prose at verdict-landed
|
|
39
|
+
# (+ exception, plan-complete); these pings carry the between-command
|
|
40
|
+
# "where is the loop now" currency.
|
|
41
|
+
PHASE_KINDS = %w[spec-launched builders-settled judge-running].freeze
|
|
42
|
+
|
|
32
43
|
# The space-slug rule (architect_project.rb :1642), with the emission-layer
|
|
33
44
|
# fallback: space.data["id"] when the title is absent or slugifies empty.
|
|
34
45
|
def self.slug_for(space)
|
|
@@ -269,6 +280,18 @@ module Space::Architect
|
|
|
269
280
|
}
|
|
270
281
|
end
|
|
271
282
|
|
|
283
|
+
# One phase ping (I11, the phase mouth): the iteration identity plus where
|
|
284
|
+
# the loop stands. The iteration hash carries ONLY ordinal + name — the
|
|
285
|
+
# mouth's other iteration keys belong to the other mouths and the ping
|
|
286
|
+
# path never sends them. note rides when given; nil/empty is omitted
|
|
287
|
+
# entirely (compact_scalars discipline).
|
|
288
|
+
def self.build_phase(ordinal:, name:, kind:, note: nil)
|
|
289
|
+
{
|
|
290
|
+
"iteration" => compact_scalars("ordinal" => ordinal, "name" => name),
|
|
291
|
+
"phase" => compact_scalars("kind" => kind, "note" => note)
|
|
292
|
+
}
|
|
293
|
+
end
|
|
294
|
+
|
|
272
295
|
# ---- the ```rulings block (S3) ------------------------------------------
|
|
273
296
|
#
|
|
274
297
|
# A fenced YAML block inside the ## Verdict body — the ```gates/```lanes
|
data/skill/architect/SKILL.md
CHANGED
|
@@ -84,8 +84,10 @@ the space durable across sessions:
|
|
|
84
84
|
`build/<id>-<lane>/run.jsonl`).
|
|
85
85
|
- **judge** — a fresh session that runs the cold gates and rules per-AC
|
|
86
86
|
verdicts; nobody grades their own work.
|
|
87
|
-
- **narrator** — writes one `notes/narrative-*`
|
|
88
|
-
|
|
87
|
+
- **narrator** — writes rare prose: one best-effort `notes/narrative-*` per
|
|
88
|
+
iteration at verdict-landed (plus exception, plan-complete), written for a
|
|
89
|
+
human whose context went stale; never a gate — the between-command currency
|
|
90
|
+
is `architect ping` phase pings.
|
|
89
91
|
|
|
90
92
|
**The workspace**
|
|
91
93
|
|
|
@@ -56,7 +56,7 @@ project — loads them.
|
|
|
56
56
|
| **spec** | subagent | one iteration's Grounds/Specification/Acceptance Criteria; rehearses; freezes; writes the `notes/spec-digest-*` handoff |
|
|
57
57
|
| **builder** | subagent per lane | implementation in the lane worktree; raw-results report; never commits |
|
|
58
58
|
| **judge** | subagent, fresh session | mechanical post-flight, cold gates, per-AC verdicts, PHASE 0 rulings, integration |
|
|
59
|
-
| **narrator** | subagent | one `notes/narrative-*` file per
|
|
59
|
+
| **narrator** | subagent | rare prose: one `notes/narrative-*` file per iteration at verdict-landed (plus exception, plan-complete), written for a human whose context went stale — never a gate; the between-command currency is `architect ping` phase pings |
|
|
60
60
|
|
|
61
61
|
## Visibility while a loop runs
|
|
62
62
|
|
|
@@ -11,7 +11,9 @@ completion wakes, not `architect dispatch` headless runs. Per iteration:
|
|
|
11
11
|
ENTRY verbatim. Writes Grounds/Specification/Acceptance Criteria via
|
|
12
12
|
`architect section`, rehearses, freezes, assembles each lane's prompt in a
|
|
13
13
|
scratch file, records the scratch paths in its report, and writes the
|
|
14
|
-
`notes/spec-digest-*` handoff. `timeoutMs` 3600000 (1h).
|
|
14
|
+
`notes/spec-digest-*` handoff. `timeoutMs` 3600000 (1h). Once the spec
|
|
15
|
+
spawn is confirmed running, ping the phase — best-effort bash, never a
|
|
16
|
+
gate: `architect ping <iteration> spec-launched || true`.
|
|
15
17
|
2. **provision** — the driver runs `architect provision <iteration>` via
|
|
16
18
|
bash; the CLI materializes every declared lane's worktree + lane branch.
|
|
17
19
|
3. **prompt copy** — the driver copies each spec-assembled scratch prompt
|
|
@@ -20,14 +22,18 @@ completion wakes, not `architect dispatch` headless runs. Per iteration:
|
|
|
20
22
|
4. **builder per lane** — agent `architect-builder`, cwd = that lane's
|
|
21
23
|
worktree, task = read `build/<id>-<lane>/prompt.md` before anything else.
|
|
22
24
|
`timeoutMs` 7200000 (2h). The lane-prompt template below is the contract
|
|
23
|
-
the spec assembles against.
|
|
25
|
+
the spec assembles against. When every builder is tended to completion,
|
|
26
|
+
ping the phase — best-effort bash, never a gate:
|
|
27
|
+
`architect ping <iteration> builders-settled || true`.
|
|
24
28
|
5. **judge** — agent `architect-judge`, cwd = the space root, task = judge the
|
|
25
29
|
iteration by id. `timeoutMs` 7200000 (2h). The judge is a fresh session —
|
|
26
30
|
§1 fresh-session judgment holds structurally: the judge session never
|
|
27
|
-
dispatched or built anything.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
dispatched or built anything. Once the judge spawn is confirmed running,
|
|
32
|
+
ping the phase — best-effort bash, never a gate:
|
|
33
|
+
`architect ping <iteration> judge-running || true`.
|
|
34
|
+
6. **narrator** — one `architect-narrator` spawn per narration
|
|
35
|
+
(verdict-landed, exception, plan-complete), `timeoutMs` 300000 (5m),
|
|
36
|
+
best-effort, never a gate on the loop.
|
|
31
37
|
|
|
32
38
|
Spawn contract (all paths): every spawn pins its model explicitly
|
|
33
39
|
(provider/id[:thinking]) and carries an explicit `timeoutMs` — never the
|