agentera 3.0.0-dev.20 → 3.0.0-dev.21

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.
Files changed (228) hide show
  1. package/README.md +19 -0
  2. package/bundle/CHANGELOG.md +63 -70
  3. package/bundle/README.md +17 -0
  4. package/bundle/UPGRADE.md +38 -0
  5. package/bundle/references/adapters/package-surface-characterization.md +7 -0
  6. package/bundle/references/artifacts/artifact-registry-interface-model.yaml +3 -3
  7. package/bundle/references/artifacts/state-storage-authority.yaml +1446 -0
  8. package/bundle/references/cli/agent-ready-state-contract.yaml +11 -39
  9. package/bundle/references/cli/audience-namespace-cli-migration.yaml +30 -15
  10. package/bundle/references/meta/documentation-inventory.md +1 -0
  11. package/bundle/skills/agentera/capabilities/audit/schemas/artifacts.yaml +18 -10
  12. package/bundle/skills/agentera/capabilities/audit/schemas/validation.yaml +10 -10
  13. package/bundle/skills/agentera/capabilities/build/schemas/artifacts.yaml +11 -6
  14. package/bundle/skills/agentera/capabilities/discuss/schemas/artifacts.yaml +3 -2
  15. package/bundle/skills/agentera/capabilities/document/schemas/artifacts.yaml +15 -8
  16. package/bundle/skills/agentera/capabilities/document/schemas/validation.yaml +13 -13
  17. package/bundle/skills/agentera/capabilities/orchestrate/schemas/artifacts.yaml +15 -9
  18. package/bundle/skills/agentera/references/contract.md +65 -23
  19. package/bundle/skills/agentera/schemas/artifacts/decisions.yaml +15 -10
  20. package/bundle/skills/agentera/schemas/artifacts/experiments.yaml +134 -3
  21. package/bundle/skills/agentera/schemas/artifacts/health.yaml +16 -10
  22. package/bundle/skills/agentera/schemas/artifacts/objective.yaml +18 -4
  23. package/bundle/skills/agentera/schemas/artifacts/plan.yaml +23 -1
  24. package/bundle/skills/agentera/schemas/artifacts/progress.yaml +16 -10
  25. package/bundle/skills/agentera/schemas/artifacts/todo.yaml +34 -0
  26. package/dist/capabilities/audit/instructions.js +1 -1
  27. package/dist/capabilities/audit/instructions.js.map +1 -1
  28. package/dist/capabilities/build/instructions.js +1 -1
  29. package/dist/capabilities/build/instructions.js.map +1 -1
  30. package/dist/capabilities/discuss/instructions.js +1 -1
  31. package/dist/capabilities/discuss/instructions.js.map +1 -1
  32. package/dist/capabilities/document/instructions.js +1 -1
  33. package/dist/capabilities/document/instructions.js.map +1 -1
  34. package/dist/capabilities/optimize/instructions.js +1 -1
  35. package/dist/capabilities/optimize/instructions.js.map +1 -1
  36. package/dist/capabilities/orchestrate/instructions.js +1 -1
  37. package/dist/capabilities/orchestrate/instructions.js.map +1 -1
  38. package/dist/capabilities/plan/instructions.js +1 -1
  39. package/dist/capabilities/plan/instructions.js.map +1 -1
  40. package/dist/capabilities/profile/instructions.js +1 -1
  41. package/dist/capabilities/profile/instructions.js.map +1 -1
  42. package/dist/capabilities/vision/instructions.js +1 -1
  43. package/dist/capabilities/vision/instructions.js.map +1 -1
  44. package/dist/cli/appContext.js +14 -6
  45. package/dist/cli/appContext.js.map +1 -1
  46. package/dist/cli/capabilityContext/bespoke.js +3 -1
  47. package/dist/cli/capabilityContext/bespoke.js.map +1 -1
  48. package/dist/cli/capabilityContext/build.js +5 -4
  49. package/dist/cli/capabilityContext/build.js.map +1 -1
  50. package/dist/cli/capabilityContext/closeout.js +2 -1
  51. package/dist/cli/capabilityContext/closeout.js.map +1 -1
  52. package/dist/cli/capabilityContext/contract.js +29 -0
  53. package/dist/cli/capabilityContext/contract.js.map +1 -1
  54. package/dist/cli/capabilityContext/evidence.js +21 -20
  55. package/dist/cli/capabilityContext/evidence.js.map +1 -1
  56. package/dist/cli/capabilityContext/orchestration.js +3 -2
  57. package/dist/cli/capabilityContext/orchestration.js.map +1 -1
  58. package/dist/cli/capabilityContext/progress.js +9 -4
  59. package/dist/cli/capabilityContext/progress.js.map +1 -1
  60. package/dist/cli/capabilityContext/slim.js +37 -6
  61. package/dist/cli/capabilityContext/slim.js.map +1 -1
  62. package/dist/cli/capabilityContext/startup.js +30 -6
  63. package/dist/cli/capabilityContext/startup.js.map +1 -1
  64. package/dist/cli/capabilityContext/types.js +14 -4
  65. package/dist/cli/capabilityContext/types.js.map +1 -1
  66. package/dist/cli/commands/backfill.js +194 -0
  67. package/dist/cli/commands/backfill.js.map +1 -0
  68. package/dist/cli/commands/compact.js +40 -11
  69. package/dist/cli/commands/compact.js.map +1 -1
  70. package/dist/cli/commands/durability.js +85 -0
  71. package/dist/cli/commands/durability.js.map +1 -0
  72. package/dist/cli/commands/migrate.js +677 -0
  73. package/dist/cli/commands/migrate.js.map +1 -0
  74. package/dist/cli/commands/prime/collectOrientationState.js +23 -0
  75. package/dist/cli/commands/prime/collectOrientationState.js.map +1 -1
  76. package/dist/cli/commands/prime/orientationOutput.js +4 -2
  77. package/dist/cli/commands/prime/orientationOutput.js.map +1 -1
  78. package/dist/cli/commands/query.js +20 -2
  79. package/dist/cli/commands/query.js.map +1 -1
  80. package/dist/cli/commands/schema.js +247 -69
  81. package/dist/cli/commands/schema.js.map +1 -1
  82. package/dist/cli/commands/state/decisions.js +28 -10
  83. package/dist/cli/commands/state/decisions.js.map +1 -1
  84. package/dist/cli/commands/state/experimentRecords.js +156 -0
  85. package/dist/cli/commands/state/experimentRecords.js.map +1 -0
  86. package/dist/cli/commands/state/get.js +141 -0
  87. package/dist/cli/commands/state/get.js.map +1 -0
  88. package/dist/cli/commands/state/index.js +2 -2
  89. package/dist/cli/commands/state/index.js.map +1 -1
  90. package/dist/cli/commands/state/list.js +159 -0
  91. package/dist/cli/commands/state/list.js.map +1 -0
  92. package/dist/cli/commands/state/plan.js +146 -41
  93. package/dist/cli/commands/state/plan.js.map +1 -1
  94. package/dist/cli/commands/state/planTasks.js +164 -0
  95. package/dist/cli/commands/state/planTasks.js.map +1 -0
  96. package/dist/cli/commands/state/plans.js +154 -0
  97. package/dist/cli/commands/state/plans.js.map +1 -0
  98. package/dist/cli/commands/state/write.js +8 -3
  99. package/dist/cli/commands/state/write.js.map +1 -1
  100. package/dist/cli/dispatch/check.js +71 -4
  101. package/dist/cli/dispatch/check.js.map +1 -1
  102. package/dist/cli/dispatch/index.js +48 -30
  103. package/dist/cli/dispatch/index.js.map +1 -1
  104. package/dist/cli/dispatch/lifecycle.js +4 -4
  105. package/dist/cli/dispatch/lifecycle.js.map +1 -1
  106. package/dist/cli/dispatch/state.js +23 -3
  107. package/dist/cli/dispatch/state.js.map +1 -1
  108. package/dist/cli/errors.js +13 -14
  109. package/dist/cli/errors.js.map +1 -1
  110. package/dist/cli/help.js +162 -3
  111. package/dist/cli/help.js.map +1 -1
  112. package/dist/cli/orientation.js +146 -34
  113. package/dist/cli/orientation.js.map +1 -1
  114. package/dist/cli/planArtifacts.js +31 -2
  115. package/dist/cli/planArtifacts.js.map +1 -1
  116. package/dist/cli/prime-blob.js +1 -0
  117. package/dist/cli/prime-blob.js.map +1 -1
  118. package/dist/cli/startupCompletenessContract.js +3 -2
  119. package/dist/cli/startupCompletenessContract.js.map +1 -1
  120. package/dist/cli/stateQuery.js +5 -3
  121. package/dist/cli/stateQuery.js.map +1 -1
  122. package/dist/core/text.js +11 -0
  123. package/dist/core/text.js.map +1 -0
  124. package/dist/hooks/compaction/apply.js +224 -46
  125. package/dist/hooks/compaction/apply.js.map +1 -1
  126. package/dist/hooks/compaction/dryRun.js +2 -0
  127. package/dist/hooks/compaction/dryRun.js.map +1 -1
  128. package/dist/hooks/compaction/index.js +4 -4
  129. package/dist/hooks/compaction/index.js.map +1 -1
  130. package/dist/hooks/compaction/parse.js +73 -5
  131. package/dist/hooks/compaction/parse.js.map +1 -1
  132. package/dist/hooks/compaction/retention.js +22 -21
  133. package/dist/hooks/compaction/retention.js.map +1 -1
  134. package/dist/hooks/compaction/status.js +116 -23
  135. package/dist/hooks/compaction/status.js.map +1 -1
  136. package/dist/hooks/sessionStart.js +39 -7
  137. package/dist/hooks/sessionStart.js.map +1 -1
  138. package/dist/hooks/validateArtifact/index.js +2 -2
  139. package/dist/hooks/validateArtifact/index.js.map +1 -1
  140. package/dist/hooks/validateArtifact/markdown.js +9 -9
  141. package/dist/hooks/validateArtifact/markdown.js.map +1 -1
  142. package/dist/hooks/validateArtifact/traversal.js +11 -9
  143. package/dist/hooks/validateArtifact/traversal.js.map +1 -1
  144. package/dist/registries/artifactRegistry.js +147 -44
  145. package/dist/registries/artifactRegistry.js.map +1 -1
  146. package/dist/release/releaseMetadata.js +95 -1
  147. package/dist/release/releaseMetadata.js.map +1 -1
  148. package/dist/state/archiveDiscovery.js +589 -0
  149. package/dist/state/archiveDiscovery.js.map +1 -0
  150. package/dist/state/archivePublication.js +225 -0
  151. package/dist/state/archivePublication.js.map +1 -0
  152. package/dist/state/archiveRecovery.js +238 -0
  153. package/dist/state/archiveRecovery.js.map +1 -0
  154. package/dist/state/archiveReplay.js +54 -0
  155. package/dist/state/archiveReplay.js.map +1 -0
  156. package/dist/state/decisionOverlay.js +255 -0
  157. package/dist/state/decisionOverlay.js.map +1 -0
  158. package/dist/state/directRetrieval.js +322 -0
  159. package/dist/state/directRetrieval.js.map +1 -0
  160. package/dist/state/durability.js +451 -0
  161. package/dist/state/durability.js.map +1 -0
  162. package/dist/state/experimentArchive.js +64 -0
  163. package/dist/state/experimentArchive.js.map +1 -0
  164. package/dist/state/experimentIdentity.js +191 -0
  165. package/dist/state/experimentIdentity.js.map +1 -0
  166. package/dist/state/experimentRetrieval.js +447 -0
  167. package/dist/state/experimentRetrieval.js.map +1 -0
  168. package/dist/state/gitBackfill.js +561 -0
  169. package/dist/state/gitBackfill.js.map +1 -0
  170. package/dist/state/gitBackfillAuthority.js +141 -0
  171. package/dist/state/gitBackfillAuthority.js.map +1 -0
  172. package/dist/state/gitBackfillHistory.js +278 -0
  173. package/dist/state/gitBackfillHistory.js.map +1 -0
  174. package/dist/state/gitBackfillOutput.js +209 -0
  175. package/dist/state/gitBackfillOutput.js.map +1 -0
  176. package/dist/state/healthRepair.js +70 -0
  177. package/dist/state/healthRepair.js.map +1 -0
  178. package/dist/state/legacyIdentity.js +48 -0
  179. package/dist/state/legacyIdentity.js.map +1 -0
  180. package/dist/state/legacyMigration.js +516 -0
  181. package/dist/state/legacyMigration.js.map +1 -0
  182. package/dist/state/legacyMigrationParser.js +489 -0
  183. package/dist/state/legacyMigrationParser.js.map +1 -0
  184. package/dist/state/listAccounting.js +55 -0
  185. package/dist/state/listAccounting.js.map +1 -0
  186. package/dist/state/listClassification.js +18 -0
  187. package/dist/state/listClassification.js.map +1 -0
  188. package/dist/state/listRetrieval.js +782 -0
  189. package/dist/state/listRetrieval.js.map +1 -0
  190. package/dist/state/migrationAuthority.js +413 -0
  191. package/dist/state/migrationAuthority.js.map +1 -0
  192. package/dist/state/migrationEnrichment.js +35 -0
  193. package/dist/state/migrationEnrichment.js.map +1 -0
  194. package/dist/state/planIdentity.js +45 -0
  195. package/dist/state/planIdentity.js.map +1 -0
  196. package/dist/state/planRetrieval.js +314 -0
  197. package/dist/state/planRetrieval.js.map +1 -0
  198. package/dist/state/planTaskRetrieval.js +285 -0
  199. package/dist/state/planTaskRetrieval.js.map +1 -0
  200. package/dist/state/projectionPolicy.js +184 -0
  201. package/dist/state/projectionPolicy.js.map +1 -0
  202. package/dist/state/retrievalAuthority.js +326 -0
  203. package/dist/state/retrievalAuthority.js.map +1 -0
  204. package/dist/state/startupProjection.js +498 -0
  205. package/dist/state/startupProjection.js.map +1 -0
  206. package/dist/state/write/experimentPublication.js +193 -0
  207. package/dist/state/write/experimentPublication.js.map +1 -0
  208. package/dist/state/write/explain.js +28 -14
  209. package/dist/state/write/explain.js.map +1 -1
  210. package/dist/state/write/helpers.js +8 -0
  211. package/dist/state/write/helpers.js.map +1 -0
  212. package/dist/state/write/index.js +1 -0
  213. package/dist/state/write/index.js.map +1 -1
  214. package/dist/state/write/lock.js +24 -1
  215. package/dist/state/write/lock.js.map +1 -1
  216. package/dist/state/write/mutation.js +190 -0
  217. package/dist/state/write/mutation.js.map +1 -0
  218. package/dist/state/write/operations.js +36 -2
  219. package/dist/state/write/operations.js.map +1 -1
  220. package/dist/state/write/planPublication.js +172 -0
  221. package/dist/state/write/planPublication.js.map +1 -0
  222. package/dist/state/write/transaction.js +238 -225
  223. package/dist/state/write/transaction.js.map +1 -1
  224. package/dist/upgrade/migrateArtifactsV2ToV3.js +2 -2
  225. package/dist/upgrade/migrateArtifactsV2ToV3.js.map +1 -1
  226. package/dist/validate/crossCapability.js +9 -6
  227. package/dist/validate/crossCapability.js.map +1 -1
  228. package/package.json +2 -2
@@ -0,0 +1,1446 @@
1
+ schema_version: agentera.stateStorageAuthority.v1
2
+ status: active_authority
3
+ purpose: >-
4
+ Define the public bounded-retrieval vocabulary for every state collection
5
+ while keeping each collection's storage authority explicit. It also defines
6
+ the lossless numbered-archive, project path, direct state API, compatibility,
7
+ projection, and serialized-output contracts for progress, decisions, and
8
+ health, plus objective-scoped immutable archival for newly published
9
+ experiments.
10
+ authority:
11
+ source: references/artifacts/state-storage-authority.yaml
12
+ single_source_rule: >-
13
+ Runtime readers, writers, validators, tests, help, and capability source
14
+ contracts may project this authority but must not create a second map of
15
+ archive paths, API verbs, compatibility classes, mutable overlay fields,
16
+ failure classes, or byte limits.
17
+ implementation_boundary: >-
18
+ This contract does not migrate legacy state or change existing plan and
19
+ vision archive behavior. The maintenance-only Git backfill surface declared
20
+ by api.backfill may inventory reachable local history and publish only an
21
+ exact immutable archive record after explicit apply intent.
22
+
23
+ scope:
24
+ supported_artifacts:
25
+ - artifact_id: progress
26
+ current_projection_path: .agentera/progress.yaml
27
+ entry_collection: cycles
28
+ entry_number_field: number
29
+ entry_kind: cycle
30
+ - artifact_id: decisions
31
+ current_projection_path: .agentera/decisions.yaml
32
+ entry_collection: decisions
33
+ entry_number_field: number
34
+ entry_kind: decision
35
+ - artifact_id: health
36
+ current_projection_path: .agentera/health.yaml
37
+ entry_collection: audits
38
+ entry_number_field: number
39
+ entry_kind: audit
40
+ excluded_from_numbered_archive:
41
+ - plan
42
+ - vision
43
+ - todo
44
+ - changelog
45
+ - docs
46
+ - design
47
+ - objective
48
+ - experiments
49
+
50
+ retrieval:
51
+ schema_version: agentera.stateRetrievalAuthority.v1
52
+ status: plan_task_plan_and_experiment_retrieval_implemented
53
+ implementation:
54
+ plan_tasks: implemented
55
+ plans: implemented
56
+ experiments: implemented
57
+ authority_boundary: >-
58
+ This group owns public list/get envelopes, cursors, selectors, identities,
59
+ omissions, and structured retrieval failures. It does not replace storage
60
+ ownership: numbered archives remain authoritative for progress, decisions,
61
+ and health; immutable plan files remain authoritative for plan history; and
62
+ objective directories remain authoritative for experiments.
63
+ envelope:
64
+ schema_version: agentera.stateRetrieval.v1
65
+ required_fields:
66
+ - schemaVersion
67
+ - command
68
+ - status
69
+ - entries
70
+ - counts
71
+ - order
72
+ - filters
73
+ - snapshot
74
+ - source
75
+ - source_contract
76
+ entry_required_fields:
77
+ - stable_id
78
+ - addressable
79
+ - detail_availability
80
+ - compatibility
81
+ - provenance
82
+ - retrieval
83
+ counts_required_fields: [total, returned, remaining, omitted]
84
+ status_values: [ok, degraded]
85
+ cursor:
86
+ vocabulary: opaque_snapshot_cursor
87
+ first_page: omit --cursor
88
+ response_field: next_cursor
89
+ binding: [collection, selectors, filters, order, snapshot]
90
+ append_behavior: >-
91
+ Records added after the first page are excluded from that cursor snapshot.
92
+ Experiment cursors bind each original stable identity to immutable archive
93
+ content when available, so unchanged full-to-summary or summary-to-drop
94
+ projection rollover does not invalidate continuation. Without sufficient
95
+ immutable or retained detail to prove an original identity unchanged, the
96
+ cursor fails with cursor_snapshot_unavailable.
97
+ invalid_behavior: cursor_invalid
98
+ unavailable_behavior: cursor_snapshot_unavailable
99
+ caller_rules: [do_not_parse, do_not_construct, do_not_compare_internals]
100
+ omission:
101
+ required_when_any_entry_is_not_returned:
102
+ - omitted
103
+ - omitted_count
104
+ - omission_reason
105
+ - retrieval
106
+ semantics: >-
107
+ Omission is explicit in both text and structured output. A response never
108
+ silently slices a collection, truncates a scalar, or claims omitted detail
109
+ is unavailable. Every omitted addressable item has an advancing cursor or
110
+ exact get command; unaddressable legacy items retain compatibility
111
+ diagnostics and are never assigned fabricated history.
112
+ output_bounds:
113
+ maximum_limit: 100
114
+ max_serialized_utf8_bytes: 32768
115
+ scalar_truncation: forbidden
116
+ omission_unit: whole_entries
117
+ identity:
118
+ plan:
119
+ canonical_format: 'plan:<lowercase-rfc9562-uuid>'
120
+ persistence: stored in header.id when a plan is first published
121
+ transition: the identical ID is copied unchanged into the immutable archive file
122
+ legacy_format: 'legacy-plan:<sha256>'
123
+ legacy_derivation: >-
124
+ SHA-256 over RFC 8785 canonical JSON of the complete plan after the
125
+ existing read-compatibility normalization of legacy status and task
126
+ shape. The archive transition computes identity from the same normalized
127
+ document before publication. Derivation is read-only and never rewrites
128
+ active or archived bytes; a legacy identity may change while an active
129
+ legacy plan is edited because no persisted historical identity exists.
130
+ test_vectors:
131
+ - canonical_json: '{"header":{"created":"2026-07-14","status":"open","title":"Plan: Complete bounded retrieval"},"tasks":[]}'
132
+ stable_id: legacy-plan:b6f93d6fc5a0ac3ada017670ac311794ad92800fb436703f8f09e25ddce8b89a
133
+ mirrored_example_paths: [.agentera/archive/PLAN-copy-a.yaml, .agentera/archive/PLAN-copy-b.yaml]
134
+ identical_result: mirrored_provenance
135
+ collision: >-
136
+ Byte-equivalent normalized legacy plans are one logical identity with
137
+ every physical path retained as mirrored provenance. Different plan
138
+ documents carrying the same persisted ID, or a detected digest collision,
139
+ are unaddressable; list reports compatibility=degraded and get returns
140
+ ambiguous with every candidate provenance path. The CLI never chooses by
141
+ mtime, archive filename, or discovery order.
142
+ task:
143
+ format: '<plan-id>/task:<positive-integer>'
144
+ selector: --task N
145
+ scope: task numbers are unique only inside one plan identity
146
+ objective:
147
+ canonical_format: 'objective:<lowercase-rfc9562-uuid>'
148
+ persistence: stored in header.id and unchanged by title or directory rename
149
+ canonical_root: .agentera/optimize/<objective-slug>
150
+ legacy_root: .agentera/optimera/<objective-slug>
151
+ legacy_format: 'legacy-objective:<sha256>'
152
+ legacy_derivation: >-
153
+ SHA-256 over RFC 8785 canonical JSON of the legacy objective's description,
154
+ measurement, metric, baseline, gates, constraints, and scope; title,
155
+ status, closure fields, directory root, and directory slug are excluded.
156
+ This preserves identity across a title/path-only rename without rewriting
157
+ history. Editing identity inputs may change a legacy identity and is
158
+ reported as degraded compatibility.
159
+ test_vectors:
160
+ - canonical_json: '{"baseline":{"description":"100 ms"},"constraints":[],"description":"Reduce latency","gates":{},"measurement":"p95","metric":{"direction":"minimize","unit":"ms"},"scope":{"excluded":[],"included":["CLI"]}}'
161
+ title_variants: [CLI latency, Faster CLI]
162
+ root_variants: [.agentera/optimize/cli-latency, .agentera/optimera/faster-cli]
163
+ stable_id: legacy-objective:aa987d92dadce65b8b2d8f54c741a10f5d024d864cb0ef309b4321b4e19e4ceb
164
+ path_compatibility: >-
165
+ Read both optimize and optimera roots. Identical records carrying one
166
+ persisted objective ID are mirrored provenance. Different records with
167
+ the same persisted or derived ID, or unresolved candidates in both roots,
168
+ return ambiguous; canonical-root preference must not hide a collision.
169
+ experiment:
170
+ format: '<objective-id>/experiment:<non-negative-integer>'
171
+ scope: experiment numbers are unique only within one objective identity
172
+ zero: experiment 0 is valid and is normally the baseline
173
+ collision: duplicate numbers inside one objective are ambiguous and never resolved by array order
174
+ compatibility: >-
175
+ Legacy full-detail or 10/40/50 summary entries with a missing or
176
+ duplicate number remain visible in reads with addressable=false and an
177
+ explicit compatibility caveat. Reads do not assign a number, choose a
178
+ duplicate by array order, migrate a root, or rewrite retained bytes.
179
+ publication_validation: >-
180
+ Before any publication effect, require one unambiguous objective
181
+ identity, a non-negative integer number, and no retained full-detail or
182
+ summary entry with that number. Ambiguous canonical/legacy objective
183
+ candidates, missing objective identity, and duplicate experiment
184
+ identity fail validation without changing bytes.
185
+ publication:
186
+ command: agentera state experiments publish --objective OBJECTIVE_ID --number N --input EXPERIMENT.yaml --format json
187
+ authority: typed_state_writer
188
+ archive_ownership: experiment_archival
189
+ storage_scope: objective_directory
190
+ publication_order: archive_before_projection
191
+ projection_policy: uniform_10_40_50
192
+ input: one schema-valid experiment entry without the CLI-owned number field
193
+ identity_assignment: the CLI assigns the validated --number to the published entry
194
+ collision_rule: >-
195
+ An existing matching identity and byte-equivalent experiment is an
196
+ idempotent replay; the same identity with different content is a
197
+ collision and leaves the projection unchanged.
198
+ transaction: >-
199
+ Validate objective identity, canonical/legacy ambiguity, experiment
200
+ identity, existing projection schema, caller input schema, and final
201
+ projection bytes before atomically replacing experiments.yaml.
202
+ failure_atomicity: >-
203
+ Validation, staging, and pre-publication failures preserve both active
204
+ and one-line archive bytes. An interruption after atomic replacement
205
+ may report failure after publication; retrying the same command must
206
+ return the already-published entry without duplication.
207
+ scope_boundary: >-
208
+ Publication preserves the existing 10/40/50 projection contract and
209
+ durably publishes its objective-scoped immutable archive before
210
+ replacing the projection, as owned by experiment_archival.
211
+ commands:
212
+ plan_tasks:
213
+ list: agentera state plan tasks list [--plan PLAN_ID] [--limit N] [--cursor TOKEN] --format json
214
+ get: agentera state plan tasks get [--plan PLAN_ID] --task N --format json
215
+ selectors:
216
+ plan:
217
+ list_required: false
218
+ list_default: active plan resolved once and returned as filters.plan
219
+ get_required: false
220
+ get_default: active plan resolved once and returned in the response source
221
+ pattern: '^(plan:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|legacy-plan:[0-9a-f]{64})$'
222
+ task:
223
+ get_required: true
224
+ pattern: '^[1-9][0-9]*$'
225
+ plans:
226
+ list: agentera state plan list [--limit N] [--cursor TOKEN] --format json
227
+ get: agentera state plan get --plan PLAN_ID --format json
228
+ selectors:
229
+ plan:
230
+ get_required: true
231
+ pattern: '^(plan:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|legacy-plan:[0-9a-f]{64})$'
232
+ experiments:
233
+ list: agentera state experiments list --objective OBJECTIVE_ID [--limit N] [--cursor TOKEN] --format json
234
+ get: agentera state experiments get --objective OBJECTIVE_ID --number N --format json
235
+ publish: agentera state experiments publish --objective OBJECTIVE_ID --number N --input EXPERIMENT.yaml --format json
236
+ selectors:
237
+ objective:
238
+ list_required: true
239
+ get_required: true
240
+ pattern: '^(objective:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|legacy-objective:[0-9a-f]{64})$'
241
+ number:
242
+ get_required: true
243
+ pattern: '^(0|[1-9][0-9]*)$'
244
+ failures:
245
+ schema_version: agentera.stateFailure.v1
246
+ required_fields: [class, message, syntax, example, recovery]
247
+ classes:
248
+ invalid_request: malformed, duplicate, missing, or incompatible selector
249
+ unsupported_artifact: collection is not exposed by the requested grammar
250
+ not_found: a valid exact identity has no matching record
251
+ ambiguous: legacy derivation, duplicate identity, or path compatibility has multiple candidates
252
+ corrupt: selected state cannot be parsed or validated safely
253
+ incomplete: selected record exists but required detail is unavailable
254
+ cursor_invalid: cursor is malformed or bound to different selectors, filters, collection, or order
255
+ cursor_snapshot_unavailable: the exact cursor snapshot cannot be resumed
256
+ unsupported_state: authority cannot return a safe bounded envelope
257
+ exit_codes:
258
+ usage: 2
259
+ state_or_compatibility_failure: 1
260
+ legacy_diagnostic_rule: >-
261
+ Compatibility failures include candidate provenance and a working recovery
262
+ command but never synthesize an ID, objective scope, task, experiment, or
263
+ archive event.
264
+ collections:
265
+ - collection_id: progress.records
266
+ artifact_id: progress
267
+ growth: append_only_unbounded
268
+ identity: 'progress:<positive-entry-number>'
269
+ storage_ownership: immutable_numbered_archive_with_bounded_current_projection
270
+ ordering: entry_number_desc
271
+ bounds: count_1_to_100_and_serialized_utf8_budget
272
+ cursor: opaque_snapshot_cursor
273
+ omission: explicit_with_advancing_cursor_or_exact_get
274
+ get: agentera state progress get --number N --format json
275
+ - collection_id: decisions.records
276
+ artifact_id: decisions
277
+ growth: append_only_unbounded_with_declared_mutable_overlay
278
+ identity: 'decisions:<positive-entry-number>'
279
+ storage_ownership: immutable_numbered_archive_plus_decision_overlay_with_bounded_current_projection
280
+ ordering: entry_number_desc
281
+ bounds: count_1_to_100_and_serialized_utf8_budget
282
+ cursor: opaque_snapshot_cursor
283
+ omission: explicit_with_advancing_cursor_or_exact_get
284
+ get: agentera state decisions get --number N --format json
285
+ - collection_id: health.records
286
+ artifact_id: health
287
+ growth: append_only_unbounded
288
+ identity: 'health:<positive-entry-number>'
289
+ storage_ownership: immutable_numbered_archive_with_bounded_current_projection
290
+ ordering: entry_number_desc
291
+ bounds: count_1_to_100_and_serialized_utf8_budget
292
+ cursor: opaque_snapshot_cursor
293
+ omission: explicit_with_advancing_cursor_or_exact_get
294
+ get: agentera state health get --number N --format json
295
+ - collection_id: plan.plans
296
+ artifact_id: plan
297
+ growth: one_active_plus_append_only_immutable_file_archives
298
+ identity: retrieval.identity.plan
299
+ storage_ownership: active_plan_file_and_immutable_plan_archive_files
300
+ ordering: created_desc_then_plan_id_asc
301
+ bounds: count_1_to_100_and_serialized_utf8_budget
302
+ cursor: opaque_snapshot_cursor
303
+ omission: explicit_with_advancing_cursor_or_exact_get
304
+ get: retrieval.commands.plans.get
305
+ - collection_id: plan.tasks
306
+ artifact_id: plan
307
+ growth: mutable_while_plan_active_then_immutable_with_archived_plan
308
+ identity: retrieval.identity.task
309
+ storage_ownership: owning_active_plan_file
310
+ ordering: task_number_asc
311
+ bounds: count_1_to_100_and_serialized_utf8_budget
312
+ cursor: opaque_snapshot_cursor
313
+ omission: explicit_with_advancing_cursor_or_exact_get
314
+ get: retrieval.commands.plan_tasks.get
315
+ - collection_id: experiments.records
316
+ artifact_id: experiments
317
+ growth: append_only_objective_scoped_with_10_full_40_summary_50_projection
318
+ identity: retrieval.identity.experiment
319
+ storage_ownership: objective_scoped_durable_records_and_bounded_10_40_50_projection
320
+ ordering: experiment_number_desc
321
+ bounds: count_1_to_100_serialized_utf8_budget_and_projection_10_40_50
322
+ cursor: opaque_snapshot_cursor
323
+ omission: explicit_with_advancing_cursor_or_exact_get_or_legacy_unavailable_diagnostic
324
+ get: retrieval.commands.experiments.get
325
+ - collection_id: todo.items
326
+ artifact_id: todo
327
+ growth: bounded_current_working_set_with_resolved_compaction
328
+ identity: absent_legacy_markdown_item_identity
329
+ storage_ownership: TODO.md
330
+ ordering: severity_then_document_order
331
+ bounds: 10_open_40_resolved_summary_50_total_projection
332
+ cursor: none_not_publicly_pageable
333
+ omission: current_query_must_report_omission_but_exact_get_is_unavailable
334
+ get: unsupported_no_stable_identity
335
+ - collection_id: docs.entries
336
+ artifact_id: docs
337
+ growth: bounded_document_inventory
338
+ identity: canonical_document_path_when_present
339
+ storage_ownership: .agentera/docs.yaml_or_docs_mapping
340
+ ordering: document_order
341
+ bounds: artifact_budget_and_projection_output_budget
342
+ cursor: none_not_publicly_pageable
343
+ omission: current_query_must_report_omission_but_exact_get_is_unavailable
344
+ get: unsupported_no_public_get
345
+ - collection_id: changelog.entries
346
+ artifact_id: changelog
347
+ growth: append_only_public_release_history
348
+ identity: absent_markdown_entry_identity
349
+ storage_ownership: CHANGELOG.md
350
+ ordering: document_order_newest_release_first
351
+ bounds: no_collection_page_contract
352
+ cursor: none_not_publicly_pageable
353
+ omission: query_result_may_be_filtered_but_must_not_claim_exact_retrieval
354
+ get: unsupported_no_stable_identity
355
+ non_collections:
356
+ - artifact_id: vision
357
+ behavior: singleton_document_no_list_or_get_grammar
358
+ - artifact_id: design
359
+ behavior: singleton_document_no_list_or_get_grammar
360
+ - artifact_id: objective
361
+ behavior: one_selected_objective_document; identity is only a required experiments selector in this task
362
+ - artifact_id: plan_archive
363
+ behavior: storage special case represented publicly by plan.plans
364
+ - artifact_id: optimize_harness
365
+ behavior: local harness storage, not public state retrieval
366
+ gap_closure_evidence:
367
+ - surface: agentera state plan --format json / plans
368
+ declared_gap: PLAN_HISTORY_CATALOG_LIMIT capped catalog rows without collection-level omission recovery
369
+ outcome: closed
370
+ closure: active and archive-only plan_catalog responses report omitted, omitted_count, omission_reason, and executable public list/get recovery; the plan list surface owns count and serialized-byte continuation
371
+ - surface: agentera state plan --format json / source.archive_paths
372
+ declared_gap: archive paths were capped at 10 with only an omitted count and no stable recovery
373
+ outcome: closed
374
+ closure: source reports archive_paths_omitted, archive_paths_omitted_count, archive_paths_omission_reason, and plan list/get recovery instead of requiring path traversal
375
+ - surface: agentera state plan text / tasks
376
+ declared_gap: legacy text projection capped tasks at 10 and needed explicit whole-record omission recovery
377
+ outcome: closed
378
+ closure: text retains complete scalar values and whole task rows only, caps rows at 10 and total output at budgets.list.max_utf8_bytes, and reports count/byte omissions with task list/get or exact-plan recovery without ellipsis
379
+ - surface: agentera state plan --format json / tasks
380
+ declared_gap: structured plan projection needed deterministic whole-task byte omission and public recovery
381
+ outcome: closed
382
+ closure: JSON and YAML report omitted, omitted_count, omission_reason, and task list/get recovery; task list JSON/YAML enforce budgets.list.max_utf8_bytes
383
+ - surface: legacy agentera state experiments projection
384
+ declared_gap: the pre-list/get projection is objective-selected rather than a stable cross-objective collection
385
+ outcome: out_of_scope
386
+ closure: objective-scoped experiments list/get is the supported retrieval surface; adding identity or pagination to the legacy projection would duplicate that contract
387
+ plan_archive_diagnostics:
388
+ classification: pre_existing_compatibility_caveat
389
+ smoke_test_behavior: >-
390
+ A lifecycle diagnostic on an unrelated archived plan degrades list/catalog
391
+ status and remains visible, but does not fail exact retrieval of a different
392
+ valid plan. Exact get fails only when the selected candidate is invalid,
393
+ corrupt, or ambiguous. Read-only smoke tests assert diagnostics and never
394
+ repair or rewrite archive history.
395
+ known_live_diagnostics:
396
+ - plan-2026-06-04-d56-parity-closeout.yaml
397
+ - plan-2026-07-08-cliDistributionMajor-secondary-signal.yaml
398
+
399
+ consumer_matrix:
400
+ status: active_authority
401
+ purpose: >-
402
+ Mechanically account for every capability source and bundled artifact-schema
403
+ consumer of numbered decisions, progress, and health state. The artifact
404
+ schemas remain the role authority; this matrix binds each declared consumer
405
+ to the bounded startup and exact retrieval contracts below.
406
+ source_root: packages/cli/src/capabilities/<capability>/instructions.ts
407
+ bundle_root: skills/agentera/capabilities/<capability>/schemas/artifacts.yaml
408
+ required_capabilities:
409
+ - status
410
+ - vision
411
+ - discuss
412
+ - research
413
+ - plan
414
+ - build
415
+ - optimize
416
+ - audit
417
+ - document
418
+ - profile
419
+ - design
420
+ - orchestrate
421
+ access_contract:
422
+ startup: agentera prime --context <capability> --format json
423
+ list: agentera state <artifact-id> list --limit 20 --format json
424
+ get: agentera state <artifact-id> get --number N --format json
425
+ policy: >-
426
+ Use the bounded prime context first, then the bounded state list for
427
+ discovery and exact state get for requested detail. Raw artifact or Git
428
+ traversal is not a normal consumer path; it is allowed only for a named
429
+ corruption or CLI-defect diagnostic exception, and must preserve missing,
430
+ ambiguous, compacted, and satisfaction-incomplete provenance.
431
+ capabilities:
432
+ - name: status
433
+ source: packages/cli/src/capabilities/status/instructions.ts
434
+ bundle: skills/agentera/capabilities/status/schemas/artifacts.yaml
435
+ state_consumers: [decisions, progress, health]
436
+ - name: vision
437
+ source: packages/cli/src/capabilities/vision/instructions.ts
438
+ bundle: skills/agentera/capabilities/vision/schemas/artifacts.yaml
439
+ state_consumers: [decisions, progress, health]
440
+ - name: discuss
441
+ source: packages/cli/src/capabilities/discuss/instructions.ts
442
+ bundle: skills/agentera/capabilities/discuss/schemas/artifacts.yaml
443
+ state_consumers: [decisions]
444
+ - name: research
445
+ source: packages/cli/src/capabilities/research/instructions.ts
446
+ bundle: skills/agentera/capabilities/research/schemas/artifacts.yaml
447
+ state_consumers: []
448
+ - name: plan
449
+ source: packages/cli/src/capabilities/plan/instructions.ts
450
+ bundle: skills/agentera/capabilities/plan/schemas/artifacts.yaml
451
+ state_consumers: [decisions, progress, health]
452
+ - name: build
453
+ source: packages/cli/src/capabilities/build/instructions.ts
454
+ bundle: skills/agentera/capabilities/build/schemas/artifacts.yaml
455
+ state_consumers: [decisions, progress, health]
456
+ - name: optimize
457
+ source: packages/cli/src/capabilities/optimize/instructions.ts
458
+ bundle: skills/agentera/capabilities/optimize/schemas/artifacts.yaml
459
+ state_consumers: [decisions, progress]
460
+ - name: audit
461
+ source: packages/cli/src/capabilities/audit/instructions.ts
462
+ bundle: skills/agentera/capabilities/audit/schemas/artifacts.yaml
463
+ state_consumers: [decisions, progress, health]
464
+ - name: document
465
+ source: packages/cli/src/capabilities/document/instructions.ts
466
+ bundle: skills/agentera/capabilities/document/schemas/artifacts.yaml
467
+ state_consumers: [decisions, progress, health]
468
+ - name: profile
469
+ source: packages/cli/src/capabilities/profile/instructions.ts
470
+ bundle: skills/agentera/capabilities/profile/schemas/artifacts.yaml
471
+ state_consumers: [decisions]
472
+ - name: design
473
+ source: packages/cli/src/capabilities/design/instructions.ts
474
+ bundle: skills/agentera/capabilities/design/schemas/artifacts.yaml
475
+ state_consumers: [progress]
476
+ - name: orchestrate
477
+ source: packages/cli/src/capabilities/orchestrate/instructions.ts
478
+ bundle: skills/agentera/capabilities/orchestrate/schemas/artifacts.yaml
479
+ state_consumers: [decisions, progress, health]
480
+ unchanged_archive_conventions:
481
+ plan:
482
+ location: .agentera/archive/plan-*.yaml
483
+ role: existing plan lifecycle archive
484
+ numbered_entry_discovery: forbidden
485
+ execution: archived plans remain historical and non-executable
486
+ vision:
487
+ location: .agentera/archive/vision-*.yaml
488
+ role: existing replace-mode vision archive
489
+ numbered_entry_discovery: forbidden
490
+ format: unchanged
491
+
492
+ experiment_archival:
493
+ status: implemented
494
+ authority_boundary: >-
495
+ This is an objective-scoped full-detail publication archive for new
496
+ experiments. It is not part of the numbered archive authority, does not
497
+ migrate experiments into .agentera/archive, and does not reconstruct
498
+ detail already dropped by legacy projection compaction.
499
+ layout:
500
+ path_template: .agentera/<objective-root>/<objective>/archive/experiments/<experiment-number>.yaml
501
+ canonical_objective_root: optimize
502
+ readable_legacy_objective_roots: [optimera]
503
+ ownership: objective_directory
504
+ path_override: forbidden
505
+ identity:
506
+ stable_id: '<objective-id>/experiment:<non-negative-integer>'
507
+ path_selector: experiment_number
508
+ objective_binding: envelope.objective_id must equal the resolved objective header.id
509
+ content_binding: record.number must equal envelope.experiment_number
510
+ envelope:
511
+ schema_version: agentera.experimentArchive.v1
512
+ required_fields:
513
+ - schemaVersion
514
+ - stable_id
515
+ - objective_id
516
+ - experiment_number
517
+ - record
518
+ - record_sha256
519
+ - provenance
520
+ provenance_required_fields: [authority, objective_id, experiment_id, storage_scope, publication_order]
521
+ authority: references/artifacts/state-storage-authority.yaml
522
+ hash: sha256_of_canonical_record_json
523
+ publication:
524
+ order:
525
+ - validate_objective_identity
526
+ - validate_full_experiment_record
527
+ - validate_archive_envelope
528
+ - stage_and_compact_projection
529
+ - create_and_fsync_each_missing_archive_directory_entry
530
+ - publish_and_fsync_immutable_archive
531
+ - replace_and_fsync_projection
532
+ archive_before_projection: true
533
+ mutation_policy: no_overwrite_after_publication
534
+ retry_policy: >-
535
+ Byte-equivalent envelope bytes at the same stable identity are an
536
+ idempotent replay. Different bytes at that identity are an immutable
537
+ conflict and preserve both archive and projection bytes.
538
+ interruption_policy: >-
539
+ Failure before archive publication leaves archive and projection
540
+ unchanged. Failure after durable archive publication may leave the new
541
+ archive with the old projection; retry reuses that archive and publishes
542
+ the projection without duplicating detail.
543
+ directory_durability: >-
544
+ Each newly created archive path component is followed by fsync of its
545
+ parent before publication advances. In particular, creating the
546
+ experiments directory requires fsync of the archive directory before an
547
+ experiment record can be considered durably published.
548
+ exact_full_replay_recovery: >-
549
+ If the projection already contains the byte-equivalent full record but
550
+ its required archive is absent, publication reconstructs that one archive
551
+ from the exact retained detail before returning replay success. Summary-
552
+ only and dropped legacy detail remain unavailable and are never inferred.
553
+ projection:
554
+ policy: uniform_10_40_50
555
+ full_entries: 10
556
+ summary_entries: 40
557
+ total_entries: 50
558
+ archive_effect: none
559
+ compatibility:
560
+ legacy_projection_records: readable_without_archive
561
+ pre_feature_dropped_detail: unavailable_and_never_fabricated
562
+
563
+ storage:
564
+ project_root:
565
+ fixed: true
566
+ resolution: >-
567
+ The caller's selected project root. The archive is project-local and is
568
+ never resolved through AGENTERA_HOME, a profile directory, XDG data, or a
569
+ docs.yaml path override.
570
+ archive_root: .agentera/archive
571
+ archive_path_template: .agentera/archive/<artifact-id>/<entry-number>.yaml
572
+ path_override: forbidden
573
+ project_boundary: >-
574
+ The resolved archive path and every parent must remain beneath the
575
+ selected project root. URI paths, traversal segments, encoded traversal,
576
+ and symlink escapes are invalid.
577
+ archive:
578
+ record_type: immutable_numbered_entry
579
+ supported_artifact_directories: [progress, decisions, health]
580
+ filename:
581
+ entry_number: positive_integer
582
+ canonical_form: base-10 decimal without a leading plus sign or leading zero
583
+ accepted_pattern: '^[1-9][0-9]*$'
584
+ directory_name: artifact_id
585
+ extension: .yaml
586
+ publication_order: archive_before_projection
587
+ mutation_policy: no_overwrite_after_publication
588
+ retry_policy: >-
589
+ An identical artifact_id, entry_number, and canonical record is an
590
+ idempotent replay. The same identity with different canonical content is
591
+ an immutable conflict and must not replace existing bytes.
592
+ discovery_policy: >-
593
+ Only the exact supported path template is eligible. Malformed names,
594
+ unsupported artifact directories, symlinks, duplicate logical identities,
595
+ invalid envelopes, and hash mismatches are not valid records.
596
+
597
+ identity:
598
+ stable_id:
599
+ format: <artifact-id>:<entry-number>
600
+ accepted_pattern: '^(progress|decisions|health):[1-9][0-9]*$'
601
+ example: decisions:53
602
+ components:
603
+ artifact_id: one of scope.supported_artifacts.artifact_id
604
+ entry_number: positive integer from the artifact's entry_number_field
605
+ uniqueness: stable_id is unique within one project archive
606
+ ordering:
607
+ list: entry_number descending, numerically rather than lexicographically
608
+ tie_breaker: stable_id ascending (defensive only; numbers are unique per artifact)
609
+ get: exact stable_id match; no topic or summary scan is a substitute
610
+ legacy_rows:
611
+ canonical_number: >-
612
+ A positive entry_number field, or an artifact-labelled summary beginning
613
+ with Cycle N, Decision N, Audit N, or the decisions-only shorthand DNN.
614
+ The number is accepted only from that explicit position; arbitrary prose
615
+ and nested values never establish identity.
616
+ unaddressable: >-
617
+ A physical current or legacy-summary row without one explicit number.
618
+ It is list-only and uses stable_id: null and entry_number: null; no
619
+ synthetic number, position, or inferred reference is permitted.
620
+ ambiguous: >-
621
+ A row containing multiple explicit decision shorthands such as
622
+ Staging D3+D4. It remains list-only with stable_id: null and is never
623
+ assigned the first or most recent shorthand.
624
+ physical_accounting: >-
625
+ physical counts raw current rows, current archive-summary rows, and
626
+ validated or rejected numbered archive files. addressable counts those
627
+ physical rows carrying one explicit number; unaddressable and ambiguous
628
+ partition the remaining physical rows. addressable_ids counts unique
629
+ stable-ID groups. mirrored, duplicate, and conflict are non-additive
630
+ redundancy classifications over addressable rows; omitted counts rows
631
+ not emitted on the current bounded page.
632
+
633
+ envelope:
634
+ schema_version: agentera.stateArchiveEntry.v1
635
+ required_fields:
636
+ - schemaVersion
637
+ - artifact_id
638
+ - entry_number
639
+ - record
640
+ - record_sha256
641
+ field_contract:
642
+ schemaVersion: exact string agentera.stateArchiveEntry.v1
643
+ artifact_id: supported artifact ID matching the archive directory
644
+ entry_number: positive integer matching the filename and record identity field
645
+ record: complete pre-projection entry, not a compact summary
646
+ record_sha256: lowercase SHA-256 of the canonical record bytes
647
+ canonical_record:
648
+ encoding: UTF-8
649
+ serialization: canonical JSON with recursively sorted object keys and no whitespace
650
+ arrays: preserve source order
651
+ hash_input: record only, excluding the envelope
652
+ identity_checks:
653
+ - envelope.artifact_id matches the parent artifact directory
654
+ - envelope.entry_number matches the filename
655
+ - envelope.entry_number matches record.<artifact entry_number_field>
656
+ - record_sha256 matches canonical_record
657
+ forbidden_fields:
658
+ - commit
659
+ - commit_hash
660
+ - git_commit
661
+ - git_ref
662
+ - parent_commit
663
+ provenance_rule: >-
664
+ Git provenance is durability evidence returned by a later diagnostic
665
+ surface, never per-entry commit bookkeeping and never part of immutable
666
+ record identity.
667
+
668
+ overlays:
669
+ location: .agentera/overlays/decisions.yaml
670
+ project_root_fixed: true
671
+ docs_yaml_override: forbidden
672
+ schema_version: agentera.decisionOverlay.v1
673
+ supported_artifact: decisions
674
+ identity_key: decisions:<decision-number>
675
+ storage_shape: >-
676
+ A mapping keyed by stable decision ID. Each value contains only the
677
+ authority-declared mutable paths and never replaces the immutable archive
678
+ record.
679
+ mutable_paths:
680
+ - satisfaction.state
681
+ - satisfaction.evidence
682
+ - satisfaction.user_confirmation.confirmed_by
683
+ - satisfaction.user_confirmation.confirmed_at
684
+ derived_paths:
685
+ - satisfaction.review_needed
686
+ - satisfaction.source
687
+ - satisfaction.caveats
688
+ immutable_paths:
689
+ - number
690
+ - date
691
+ - question
692
+ - context
693
+ - alternatives
694
+ - choice
695
+ - reasoning
696
+ - confidence
697
+ - feeds_into
698
+ state_values: [open, provisionally_satisfied, user_confirmed_satisfied]
699
+ transition_rules:
700
+ open:
701
+ allowed_next: [open, provisionally_satisfied, user_confirmed_satisfied]
702
+ provisional_requires: non_empty_satisfaction.evidence
703
+ confirmed_requires: explicit_current_user_confirmation_metadata
704
+ provisionally_satisfied:
705
+ allowed_next: [open, provisionally_satisfied, user_confirmed_satisfied]
706
+ provisional_requires: non_empty_satisfaction.evidence
707
+ confirmed_requires: explicit_current_user_confirmation_metadata
708
+ user_confirmed_satisfied:
709
+ allowed_next: [user_confirmed_satisfied]
710
+ downgrade: forbidden_without_explicit_current_user_confirmation
711
+ decision_53_rules:
712
+ missing_satisfaction: valid legacy state; derive review_needed=true
713
+ open: review_needed=true
714
+ provisional: review_needed=true until explicit user confirmation
715
+ confirmed: review_needed=false only with confirmed_by and confirmed_at
716
+ inference: forbidden from commits, downstream references, summaries, or Git history
717
+ protected_review: unresolved decisions remain visible and never block archive storage
718
+
719
+ projections:
720
+ archive:
721
+ role: complete immutable historical detail
722
+ source_of_truth_for: historical_record_fields
723
+ omission: never omit fields from an archive record
724
+ current:
725
+ role: bounded active projection for current artifact consumers
726
+ default_capacity:
727
+ active_entries: 10
728
+ summary_entries: 40
729
+ total_entries: 50
730
+ semantics: >-
731
+ These are projection defaults, not retention or deletion limits. Entries
732
+ outside the default display capacity remain in the numbered archive;
733
+ entries whose archive cannot be verified remain full in the projection
734
+ with recovery metadata rather than being discarded.
735
+ legacy_summary_overflow:
736
+ source: legacy_summary
737
+ compatibility: degraded
738
+ detail_availability: unavailable
739
+ archive_verified: false
740
+ semantics: >-
741
+ Legacy inline summaries without a verified numbered record are bounded
742
+ like every other projection item. If omitted, omission_provenance keeps
743
+ their degraded and incomplete status explicit; omission never promotes
744
+ them to archive-backed detail or reconstructs missing fields.
745
+ paths:
746
+ progress: .agentera/progress.yaml
747
+ decisions: .agentera/decisions.yaml
748
+ health: .agentera/health.yaml
749
+ source_of_truth_for: current_projection_and_legacy_compatibility_state
750
+ archive_relationship: >-
751
+ A current entry may be full, summary-only, or absent from the projection;
752
+ archive presence and hash verification determine whether full detail is
753
+ available. Current mutable decision overlay values are composed at read
754
+ time and do not rewrite archive bytes.
755
+ summary:
756
+ role: bounded list and startup representation
757
+ required_item_fields: [stable_id, artifact_id, entry_number, addressable, classification, detail_availability, source]
758
+ nullable_item_fields:
759
+ - stable_id
760
+ - entry_number
761
+ detail_availability: [full, summary, unavailable]
762
+ source_values: [archive, current_projection, legacy_full, legacy_summary]
763
+ classification_values: [canonical, mirrored, duplicate, conflict, ambiguous, unaddressable, corrupt]
764
+ counts:
765
+ required: [physical, addressable, addressable_ids, unaddressable, ambiguous, mirrored, duplicate, conflict, omitted]
766
+ reconciliation: >-
767
+ physical = addressable + unaddressable + ambiguous;
768
+ addressable_ids is the unique logical count and is not added to the
769
+ physical count; mirrored, duplicate, and conflict are overlapping
770
+ redundancy diagnostics, not partition buckets.
771
+ omission: >-
772
+ Omitted detail is represented by omitted=true, omitted_count,
773
+ omission_reason, and a get command pointer. It is never silently
774
+ truncated, represented as a fabricated summary, or treated as missing
775
+ history without provenance.
776
+ startup:
777
+ role: bounded orientation and capability-startup projection
778
+ required_fields: [command, status, source, source_contract]
779
+ allowed_payload: >-
780
+ Counts, bounded summaries, actionable stable IDs, detail availability,
781
+ omission metadata, compatibility classification, and retrieval pointers.
782
+ forbidden_payload: [raw_archive_records, raw_yaml, unbounded_entry_arrays, Git_history_scan]
783
+ incomplete_state: >-
784
+ Preserve degraded or blocked compatibility and omission metadata in
785
+ source_contract; do not fall back to raw archive traversal merely to fill
786
+ an omitted field.
787
+
788
+ api:
789
+ namespace: agentera state
790
+ artifact_syntax: agentera state <artifact-id>
791
+ formats: [text, json, yaml]
792
+ direct_get:
793
+ command: agentera state <artifact-id> get --number N --format json
794
+ examples:
795
+ progress: agentera state progress get --number 747 --format json
796
+ decisions: agentera state decisions get --number 53 --format json
797
+ health: agentera state health get --number 29 --format json
798
+ required_selector: --number N
799
+ result: >-
800
+ One complete record composed from the immutable archive and only the
801
+ authority-declared current overlay fields, with stable_id, source,
802
+ detail_availability, compatibility, and provenance metadata.
803
+ archive_only: direct retrieval reads the exact numbered record without scanning unrelated records
804
+ list:
805
+ command: agentera state <artifact-id> list [--limit N] [--cursor TOKEN] --format json
806
+ examples:
807
+ progress: agentera state progress list --limit 20 --format json
808
+ decisions_next_page: agentera state decisions list --limit 20 --cursor TOKEN --format json
809
+ default_limit: 20
810
+ minimum_limit: 1
811
+ maximum_limit: 100
812
+ ordering: identity.ordering.list
813
+ response_fields:
814
+ required: [command, status, entries, counts, source, filters, snapshot, source_contract]
815
+ entry: [stable_id, artifact_id, entry_number, current_status, detail_availability, source, compatibility, provenance]
816
+ optional_entry: [summary, record_status, overlay_applied, retrieval]
817
+ empty_result: status=ok with entries=[] and counts.total=0; absence is not an error
818
+ durability:
819
+ command: agentera check durability [--project PATH] [--artifact ARTIFACT] [--number N] [--limit N] --format json
820
+ formats: [text, json, yaml]
821
+ selectors:
822
+ artifact: optional supported numbered archive artifact ID
823
+ number: optional positive entry number; requires artifact
824
+ limit: optional bounded result count
825
+ default_limit: 100
826
+ maximum_limit: 100
827
+ status_values: [complete, degraded, unavailable]
828
+ local_values: [verified, unavailable, corrupt]
829
+ git_values: [verified, degraded, unavailable]
830
+ response_fields:
831
+ required: [command, status, project, read_only, remote_contact, head, counts, entries, diagnostics, source_contract]
832
+ entry: [stable_id, artifact_id, entry_number, status, local, git]
833
+ guarantees:
834
+ read_only: true
835
+ remote_contact: forbidden
836
+ writes_independent: true
837
+ head_capture: >-
838
+ Capture the local HEAD before inspection and after inspection. If the
839
+ values differ, report changed_head and do not claim committed recovery.
840
+ deterministic: >-
841
+ With unchanged local files and reachable refs, repeated checks emit the
842
+ same ordered result and do not create state or contact a remote.
843
+ backfill:
844
+ command: >-
845
+ agentera state backfill [--project PATH] [--artifact ARTIFACT]
846
+ [--number N] [--commit HASH] [--path PATH] [--limit N]
847
+ [--dry-run|--apply --force] --format {text,json,yaml}
848
+ formats: [text, json, yaml]
849
+ default_limit: 100
850
+ maximum_limit: 100
851
+ maximum_commits: 500
852
+ maximum_history_bytes: 16777216
853
+ supported_artifacts: [progress, decisions, health]
854
+ reachable_refs: [HEAD, refs/heads, refs/tags]
855
+ excluded_refs: [refs/remotes, custom_refs]
856
+ apply_requires: [--apply, --force, --project PATH, --artifact ARTIFACT, --number N]
857
+ status_values: [complete, degraded, blocked, unavailable]
858
+ response:
859
+ required_fields: [command, mode, status, project, read_only, remote_contact, head, scan, counts, active_projections_unchanged, active_projection_hashes, omitted, omitted_count, omission_reason, continuation, entries, diagnostics, source_contract]
860
+ entry_fields: [entry_id, artifact_id, entry_number, commit, path, blob_id, content_hash, ambiguity_reason, eligible, reachable, provenance, operation, refusal]
861
+ modes:
862
+ inventory: >-
863
+ The default read-only mode reports up to maximum_limit final rows after
864
+ combining reachable and rewritten-history occurrences. Omitted rows
865
+ carry explicit omission metadata; returned rows include commit, path,
866
+ blob identity, stable entry ID, canonical content hash, and an explicit
867
+ ambiguity reason.
868
+ preview: >-
869
+ --dry-run is read-only and shows proposed immutable archive bytes only
870
+ for a returned exact unique candidate, together with every matching
871
+ provenance.
872
+ apply: >-
873
+ --apply --force is the only mutation mode. It requires one project,
874
+ artifact, and entry number. A prior --dry-run is optional. Apply
875
+ independently revalidates the selected project, current HEAD, allowed
876
+ ref reachability, candidate path/blob/content, and immutable archive
877
+ target immediately before publication, and never overwrites conflicts.
878
+ ambiguity_reasons:
879
+ - none
880
+ - conflicting_versions
881
+ - shallow_history
882
+ - history_rewritten
883
+ - missing_history
884
+ - corrupt_history
885
+ - changed_head
886
+ - scan_bounded
887
+ - git_unavailable
888
+ - immutable_conflict
889
+ - candidate_changed
890
+ - no_matching_pin
891
+ guarantees:
892
+ read_only_inventory_and_preview: true
893
+ apply_requires_force: true
894
+ preview_optional: true
895
+ apply_revalidation: >-
896
+ Apply repeats project, HEAD, allowed-ref reachability, candidate
897
+ provenance/content, and immutable-target checks immediately before
898
+ publication; a failed check preserves active projections and archives.
899
+ remote_contact: forbidden
900
+ custom_refs: forbidden
901
+ commit_fields_in_archive_records: forbidden
902
+ projection_writes: forbidden
903
+ immutable_conflicts: refuse_without_overwrite
904
+ retry: identical_publication_is_idempotent
905
+ failure_projection_rule: active_projections_remain_byte_identical
906
+ omission:
907
+ fields: [omitted, omitted_count, omission_reason, continuation]
908
+ complete_reason: none
909
+ bounded_reason: result_limit
910
+ continuation: >-
911
+ No cursor is issued. Use --artifact ARTIFACT --number N to retrieve an
912
+ omitted entry because --limit cannot exceed maximum_limit (100).
913
+ traceability:
914
+ provenance_fields: [commit, path, blob_id, entry_id, content_hash, reachable]
915
+ archive_record_forbids: [commit, commit_hash, git_commit, git_ref]
916
+ recovery: >-
917
+ Resolve the reported ambiguity, unavailable Git state, changed candidate,
918
+ or immutable conflict and retry the same exact selectors. A refused
919
+ operation leaves active projections and existing archives unchanged;
920
+ identical publication is an idempotent replay.
921
+ migrate:
922
+ namespace: agentera state migrate
923
+ command: >-
924
+ agentera state migrate [--project PATH] [--artifact ARTIFACT]
925
+ [--number N] [--path PATH] [--limit N]
926
+ [--dry-run|--apply --force] --format {text,json,yaml}
927
+ purpose: >-
928
+ Inventory bounded, project-local legacy state and define the only
929
+ authority for a later non-Git migration apply. This surface does not
930
+ infer missing records, contact Git, contact a remote, or remove legacy
931
+ source files.
932
+ implementation_boundary: >-
933
+ The runtime owns bounded, project-local candidate inventory and the
934
+ explicit archive, backup, projection, and mutation flow described here.
935
+ Inventory never reads Git or writes archives, backups, or projections;
936
+ migration remains independent of the optional Git backfill surface.
937
+ formats: [text, json, yaml]
938
+ default_limit: 20
939
+ maximum_limit: 100
940
+ supported_artifacts: [progress, decisions, health]
941
+ selectors:
942
+ project:
943
+ flag: --project PATH
944
+ default: current_working_directory
945
+ resolution: >-
946
+ Resolve the selected directory to a real project root before any
947
+ candidate is considered. The project root is selected explicitly or
948
+ is the caller's current working directory; AGENTERA_HOME, profile
949
+ paths, docs.yaml overrides, and Git worktrees do not replace it.
950
+ artifact:
951
+ flag: --artifact ARTIFACT
952
+ required_for_apply: true
953
+ valid_values: [progress, decisions, health]
954
+ number:
955
+ flag: --number N
956
+ pattern: '^[1-9][0-9]*$'
957
+ required_with: --artifact
958
+ meaning: exact positive legacy entry number; never a positional offset
959
+ path:
960
+ flag: --path PATH
961
+ pattern: '^[A-Za-z0-9][A-Za-z0-9._-]{0,63}\.(md|yaml|yml)$'
962
+ relative_to: selected_project_root
963
+ required_for_custom_apply: true
964
+ meaning: exact candidate path pin; inventory may omit it to enumerate candidates
965
+ limit:
966
+ flag: --limit N
967
+ default: 20
968
+ minimum: 1
969
+ maximum: 100
970
+ meaning: maximum returned candidate summaries, not a scan escape hatch
971
+ format:
972
+ flag: --format FORMAT
973
+ valid_values: [text, json, yaml]
974
+ modes:
975
+ inventory:
976
+ selector: default when neither --dry-run nor --apply is present
977
+ read_only: true
978
+ writes: forbidden
979
+ preview:
980
+ selector: --dry-run
981
+ read_only: true
982
+ writes: forbidden
983
+ output: exact proposed archive, backup, and projection operations only for addressable candidates
984
+ apply:
985
+ selector: --apply --force
986
+ read_only: false
987
+ mutation_intent: explicit_apply_and_force
988
+ selectors_required: [--artifact, --number]
989
+ mutation: >-
990
+ The runtime publishes only after revalidating the selected candidate,
991
+ project boundary, backup identity, and immutable archive identity.
992
+ invalid_combinations:
993
+ - flags: [--apply, --dry-run]
994
+ failure_class: invalid_selector
995
+ message: --apply and --dry-run are mutually exclusive
996
+ - flags: [--apply]
997
+ requires: --force
998
+ failure_class: invalid_selector
999
+ message: --apply requires explicit --force intent
1000
+ - flags: [--force]
1001
+ requires: --apply
1002
+ failure_class: invalid_selector
1003
+ message: --force requires --apply
1004
+ inventory:
1005
+ project_local: true
1006
+ bounded_scan:
1007
+ roots:
1008
+ - path: .
1009
+ maximum_depth: 1
1010
+ - path: .agentera
1011
+ maximum_depth: 1
1012
+ excluded_relative_paths:
1013
+ - .git
1014
+ - .agentera/archive
1015
+ - .agentera/overlays
1016
+ - .agentera/migration-backups
1017
+ maximum_candidate_files: 256
1018
+ maximum_file_bytes: 1048576
1019
+ maximum_total_bytes: 16777216
1020
+ ordering: normalized_relative_path_ascending
1021
+ candidate_rule: >-
1022
+ A candidate is a regular, non-symlink file directly under one declared
1023
+ scan root whose basename is ASCII and matches
1024
+ ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}\.(md|yaml|yml)$. Fixed legacy names
1025
+ are recognized first; every other accepted name is a custom candidate
1026
+ and remains project-local.
1027
+ fixed_names:
1028
+ - path: .agentera/PROGRESS.md
1029
+ artifact: progress
1030
+ - path: .agentera/DECISIONS.md
1031
+ artifact: decisions
1032
+ - path: .agentera/HEALTH.md
1033
+ artifact: health
1034
+ custom_name_rule: >-
1035
+ Custom names are discovered only within the declared roots and are
1036
+ never mapped from their basename alone. A custom candidate is
1037
+ addressable only when --path pins it, --artifact identifies the
1038
+ numbered artifact, and parsing yields exactly one supported stable
1039
+ identity for the requested --number. A candidate with zero, multiple,
1040
+ conflicting, or unsupported identities is inventory-visible but not
1041
+ apply-eligible.
1042
+ deterministic_rejections:
1043
+ unsafe_path: absolute paths, traversal segments, encoded traversal, URI paths, or symlink components
1044
+ escaping_path: realpath is outside the selected project root
1045
+ ambiguous_candidate: one candidate yields multiple artifact or entry identities, or identities conflict
1046
+ unsupported_candidate: unsupported extension, non-regular file, invalid encoding, or unsupported artifact shape
1047
+ scan_bounded: candidate or byte limits are exceeded; omitted candidates are reported, never silently dropped
1048
+ project_boundary:
1049
+ selected_root: resolved_realpath_of_project_selector
1050
+ candidate_rule: >-
1051
+ The candidate realpath and every existing parent must remain strictly
1052
+ beneath selected_root. The project root itself is not a candidate.
1053
+ reject: [absolute_candidate_path, traversal, encoded_traversal, uri_path, symlink_escape, outside_project]
1054
+ docs_mapping: forbidden
1055
+ remote_access: forbidden
1056
+ compatibility_window:
1057
+ name: v2_to_v3_local_state
1058
+ scope: numbered_progress_decisions_health_only
1059
+ supported_sources: [legacy_markdown, legacy_yaml, current_yaml_projection]
1060
+ classifications: [complete, degraded, blocked, unsupported]
1061
+ cases:
1062
+ new:
1063
+ classification: complete
1064
+ behavior: preserve current archive and projection authority
1065
+ legacy_full:
1066
+ classification: degraded
1067
+ behavior: archive exact parsed records and retain source provenance
1068
+ legacy_summary:
1069
+ classification: degraded
1070
+ behavior: preserve summary-only detail and never reconstruct absent fields
1071
+ non_git:
1072
+ classification: complete
1073
+ behavior: local inventory and publication do not require Git
1074
+ ambiguous:
1075
+ classification: blocked
1076
+ behavior: never choose between candidates; preserve all diagnostics
1077
+ corrupt:
1078
+ classification: blocked
1079
+ behavior: preserve source bytes and do not archive or project invalid records
1080
+ unsupported:
1081
+ classification: unsupported
1082
+ behavior: report a deterministic candidate diagnostic without mutation
1083
+ no_reconstruction: >-
1084
+ Missing, ambiguous, compacted, summary-only, and satisfaction-incomplete
1085
+ state remains explicitly classified. No fields, identity, satisfaction,
1086
+ provenance, or history are inferred from names, summaries, Git, or
1087
+ profile state. Decision 53 remains governed by overlays.decision_53_rules.
1088
+ backups:
1089
+ required_for_apply: true
1090
+ project_local: true
1091
+ root: .agentera/migration-backups
1092
+ path_template: .agentera/migration-backups/<sha256-relative-source>.bak
1093
+ bytes: exact_source_bytes_before_projection
1094
+ identity: sha256(relative_source_path + NUL + source_bytes)
1095
+ publication: exclusive_immutable_file
1096
+ existing_backup: >-
1097
+ An identical backup is an idempotent replay. Different bytes at the
1098
+ same backup identity are backup_conflict and block without overwrite.
1099
+ cleanup: forbidden
1100
+ required_before_projection: true
1101
+ publication:
1102
+ order:
1103
+ - validate_candidate_and_selector
1104
+ - publish_immutable_archive_record
1105
+ - publish_immutable_backup
1106
+ - publish_current_projection
1107
+ archive_before_projection: true
1108
+ archive_immutability: storage.archive.mutation_policy
1109
+ projection_failure: >-
1110
+ Leave archive, backup, and the pre-existing projection bytes unchanged
1111
+ except for successfully published immutable artifacts; retry must replay
1112
+ identical artifacts rather than restart or synthesize a new identity.
1113
+ monotonic_states: [inventory, previewed, archive_published, backup_published, projection_published]
1114
+ retry: >-
1115
+ Repeating the same project, selector, source bytes, and canonical record
1116
+ is an idempotent replay. The same stable identity with different bytes
1117
+ is immutable_conflict; no existing archive, backup, or projection bytes
1118
+ may be overwritten.
1119
+ git:
1120
+ required: false
1121
+ reads: forbidden
1122
+ remote_contact: forbidden
1123
+ completion_independent: true
1124
+ provenance: local_source_path_and_content_hash_only
1125
+ result:
1126
+ schema_version: agentera.stateMigrationResult.v1
1127
+ statuses: [complete, degraded, blocked, unavailable]
1128
+ required_fields: [schemaVersion, command, status, mode, project, read_only, mutation_intent, mutation_performed, remote_contact, inventory_performed, entries, counts, diagnostics, source_contract, omitted, omitted_count, omission_reason, retrieval]
1129
+ entry_fields: [candidate_id, path, artifact_id, entry_number, classification, detail_availability, compatibility, source, addressable, size_bytes, rejection, provenance]
1130
+ count_fields: [physical, addressable, addressable_ids, unaddressable, ambiguous, mirrored, duplicate, conflict, omitted]
1131
+ count_rules:
1132
+ physical:
1133
+ source: all_candidates
1134
+ operation: count
1135
+ addressable:
1136
+ source: visible_entries
1137
+ operation: count
1138
+ predicates: [{field: addressable, equals: true}]
1139
+ addressable_ids:
1140
+ source: visible_entries
1141
+ operation: distinct
1142
+ field: candidate_id
1143
+ unaddressable:
1144
+ source: visible_entries
1145
+ operation: count
1146
+ predicates:
1147
+ - {field: addressable, equals: false}
1148
+ - {field: classification, not_equals: ambiguous}
1149
+ ambiguous:
1150
+ source: visible_entries
1151
+ operation: count
1152
+ predicates: [{field: classification, equals: ambiguous}]
1153
+ mirrored:
1154
+ source: visible_entries
1155
+ operation: count
1156
+ predicates: [{field: classification, equals: mirrored}]
1157
+ duplicate:
1158
+ source: visible_entries
1159
+ operation: count
1160
+ predicates: [{field: classification, equals: duplicate}]
1161
+ conflict:
1162
+ source: visible_entries
1163
+ operation: count
1164
+ predicates: [{field: classification, equals: conflict}]
1165
+ omitted:
1166
+ source: omitted_count
1167
+ operation: value
1168
+ omission:
1169
+ fields: [omitted, omitted_count, omission_reason, retrieval]
1170
+ field_sources:
1171
+ omitted: has_omissions
1172
+ omitted_count: omitted_count
1173
+ omission_reason: omission_reason
1174
+ retrieval: retrieval
1175
+ complete_reason: none
1176
+ bounded_reason: scan_bounded
1177
+ output_bounded_reason: serialized_output_byte_budget
1178
+ retry: >-
1179
+ Retry with narrower project or selectors, or use the bounded list
1180
+ pointer to continue from the same normalized snapshot.
1181
+ output_retry: >-
1182
+ Retry with a smaller --limit or narrower selectors; use --path with
1183
+ --artifact and --number to address one omitted candidate. The omitted
1184
+ records remain accounted for and no state was changed by output bounding.
1185
+ retrieval: >-
1186
+ agentera state migrate --project PATH [selectors] --limit N
1187
+ semantics: >-
1188
+ Omitted candidates are represented by omitted=true, omitted_count,
1189
+ omission_reason, and a bounded retry/list pointer. Text, JSON, and YAML
1190
+ are projections of the same envelope and never contain unbounded records.
1191
+ failures:
1192
+ schema_version: agentera.stateFailure.v1
1193
+ deterministic: >-
1194
+ The same authority, project bytes, selectors, and local filesystem
1195
+ state produce the same failure class, syntax, example, and recovery.
1196
+ classes:
1197
+ - class: invalid_selector
1198
+ message: selector is missing, duplicated, malformed, or not allowed for the selected mode
1199
+ example: agentera state migrate --number 1 --format json
1200
+ recovery: add one supported --artifact selector and retry; no state was changed
1201
+ - class: project_boundary
1202
+ message: selected project or candidate path escapes the project boundary
1203
+ example: agentera state migrate --path ../secrets.yaml --format json
1204
+ recovery: select a project-local relative path; no state was changed
1205
+ - class: unsupported_candidate
1206
+ message: candidate is not a supported regular file or artifact shape
1207
+ example: agentera state migrate --path .agentera/state.txt --format json
1208
+ recovery: use a supported Markdown or YAML candidate; no state was changed
1209
+ - class: ambiguous_candidate
1210
+ message: candidate has multiple or conflicting supported identities
1211
+ example: agentera state migrate --artifact progress --number 1 --path CUSTOM.md --dry-run --format json
1212
+ recovery: resolve the candidate ambiguity before retrying; no state was changed
1213
+ - class: corrupt_candidate
1214
+ message: candidate bytes or parsed record fail the declared artifact schema
1215
+ example: agentera state migrate --artifact decisions --number 53 --dry-run --format json
1216
+ recovery: repair or preserve the source and retry only after validation; no state was changed
1217
+ - class: backup_conflict
1218
+ message: immutable backup identity already contains different source bytes
1219
+ example: agentera state migrate --artifact progress --number 1 --apply --force --format json
1220
+ recovery: preserve the existing backup and resolve the source conflict; no projection was changed
1221
+ - class: immutable_conflict
1222
+ message: immutable archive identity already contains different canonical content
1223
+ example: agentera state migrate --artifact progress --number 1 --apply --force --format json
1224
+ recovery: preserve the existing archive and resolve the identity conflict; no projection was changed
1225
+ - class: changed_candidate
1226
+ message: candidate changed between inventory, preview, and apply
1227
+ example: agentera state migrate --artifact health --number 1 --apply --force --format json
1228
+ recovery: rerun inventory and preview against the current local bytes; no projection was changed
1229
+ - class: scan_bounded
1230
+ message: bounded candidate or byte limit was exceeded
1231
+ example: agentera state migrate --limit 100 --format json
1232
+ recovery: narrow the project or selectors; omitted candidates remain reported
1233
+ guarantees:
1234
+ read_only_inventory_and_preview: true
1235
+ apply_requires_force: true
1236
+ archive_before_projection: true
1237
+ backups_before_projection: true
1238
+ monotonic_retry: true
1239
+ archive_immutability: true
1240
+ project_local: true
1241
+ remote_contact: forbidden
1242
+ git_independent: true
1243
+ cursor:
1244
+ syntax: opaque TOKEN returned as response.next_cursor
1245
+ first_page: omit --cursor to establish a snapshot
1246
+ snapshot_identity: >-
1247
+ deterministic hash of ordered candidate IDs, archive hashes, legacy
1248
+ projection hashes when no archive exists, filters, and overlay revision.
1249
+ snapshot_scope: artifact and filters are bound to the cursor; limit may change between pages
1250
+ append_behavior: >-
1251
+ Entries appended after the first page are excluded from that cursor's
1252
+ snapshot. They appear only in a new listing without the old cursor.
1253
+ continuation: >-
1254
+ Continue strictly after the last emitted numeric entry number. Never
1255
+ restart from page one, skip an entry, or duplicate an entry.
1256
+ unavailable: return cursor_snapshot_unavailable rather than silently creating a new snapshot
1257
+ opacity: callers must not parse, construct, or compare token internals
1258
+ filters:
1259
+ allowed: artifact-specific existing filters plus --limit and --cursor
1260
+ filter_binding: every filter value is included in snapshot identity
1261
+ invalid_filters: structured failure with syntax, valid values, and example
1262
+
1263
+ failures:
1264
+ schema_version: agentera.stateFailure.v1
1265
+ envelope:
1266
+ required_fields: [schemaVersion, status, error]
1267
+ status: fail
1268
+ error_required_fields: [class, message, syntax, example, recovery]
1269
+ error_optional_fields: [artifact_id, entry_number, stable_id, details, valid_values]
1270
+ exit_codes:
1271
+ invalid_input: 2
1272
+ operational_failure: 1
1273
+ classes:
1274
+ invalid_request:
1275
+ exit_class: invalid_input
1276
+ use_for: malformed syntax, missing selector, invalid limit, or invalid cursor format
1277
+ unsupported_artifact:
1278
+ exit_class: invalid_input
1279
+ use_for: artifact outside scope.supported_artifacts
1280
+ not_found:
1281
+ exit_class: operational_failure
1282
+ use_for: requested stable ID has no available current or archive record
1283
+ ambiguous:
1284
+ exit_class: operational_failure
1285
+ use_for: multiple legacy candidates or conflicting identities prevent safe selection
1286
+ corrupt:
1287
+ exit_class: operational_failure
1288
+ use_for: malformed YAML, invalid envelope, hash mismatch, unsafe path, symlink, or duplicate identity
1289
+ incomplete:
1290
+ exit_class: operational_failure
1291
+ use_for: a requested complete record is represented only by an irrecoverable legacy summary
1292
+ immutable_conflict:
1293
+ exit_class: operational_failure
1294
+ use_for: same stable ID has different canonical content; existing bytes remain untouched
1295
+ cursor_invalid:
1296
+ exit_class: invalid_input
1297
+ use_for: token is malformed, bound to another artifact, or bound to different filters
1298
+ cursor_snapshot_unavailable:
1299
+ exit_class: operational_failure
1300
+ use_for: the original snapshot cannot be reproduced exactly
1301
+ project_boundary:
1302
+ exit_class: invalid_input
1303
+ use_for: path resolution would leave the selected project root
1304
+ unsupported_state:
1305
+ exit_class: operational_failure
1306
+ use_for: state format is outside the declared compatibility authority
1307
+ guidance_rule: >-
1308
+ Every failure includes the valid command syntax, a concrete example, and a
1309
+ recovery action. A failure must not silently downgrade a complete record,
1310
+ retry an invalid cursor as a fresh listing, or invent missing history.
1311
+
1312
+ compatibility:
1313
+ classifications: [complete, degraded, blocked, unsupported]
1314
+ dimensions:
1315
+ local_read: local project state and numbered archive availability
1316
+ detail: whether full record fields are available without inference
1317
+ git_durability: optional committed-history evidence only; never a write prerequisite
1318
+ cases:
1319
+ new:
1320
+ classification: complete
1321
+ local_read: complete
1322
+ detail: complete
1323
+ git_durability: optional
1324
+ behavior: numbered archive is canonical; current projection is bounded
1325
+ legacy_full:
1326
+ classification: degraded
1327
+ local_read: complete
1328
+ detail: complete
1329
+ git_durability: unavailable_until_migrated
1330
+ behavior: full inline current/legacy entry is usable, but provenance declares noncanonical storage and migration-needed
1331
+ legacy_summary:
1332
+ classification: degraded
1333
+ local_read: complete
1334
+ detail: incomplete
1335
+ git_durability: optional
1336
+ behavior: summary and retained fields are usable; missing fields stay missing and are never reconstructed
1337
+ non_git:
1338
+ classification: complete
1339
+ local_read: complete
1340
+ detail: based_on_local_records
1341
+ git_durability: unavailable
1342
+ behavior: local archive reads and writes remain supported; no Git operation is attempted
1343
+ shallow:
1344
+ classification: degraded
1345
+ local_read: complete_when_local_records_validate
1346
+ detail: based_on_local_records
1347
+ git_durability: history_unavailable
1348
+ behavior: do not claim historical recovery beyond reachable local records
1349
+ ambiguous:
1350
+ classification: blocked
1351
+ local_read: affected_identity_blocked
1352
+ detail: not_safe_to_select
1353
+ git_durability: not_evaluated
1354
+ behavior: preserve candidates and require explicit disambiguation; never choose by recency or Git guess
1355
+ corrupt:
1356
+ classification: blocked
1357
+ local_read: affected_record_blocked
1358
+ detail: not_trusted
1359
+ git_durability: not_evaluated
1360
+ behavior: reject the affected record, preserve its bytes for diagnostics, and continue only with independently valid records
1361
+ unsupported:
1362
+ classification: unsupported
1363
+ local_read: unsupported
1364
+ detail: unavailable
1365
+ git_durability: not_evaluated
1366
+ behavior: identify the unsupported artifact or format and return valid supported values
1367
+ precedence: corrupt > ambiguous > unsupported > degraded > complete
1368
+ no_reconstruction: >-
1369
+ Compatibility reports provenance and availability only. It does not
1370
+ reconstruct missing decision fields, promote summaries to full records, or
1371
+ use Git history to satisfy a current source contract.
1372
+
1373
+ budgets:
1374
+ schema_version: agentera.stateOutputBudget.v1
1375
+ measurement:
1376
+ encoding: UTF-8
1377
+ bytes: serialized byte length after encoding, including the final newline
1378
+ json_serializer: JSON.stringify(value, null, 2) plus newline
1379
+ yaml_serializer: YAML.stringify(value) as emitted by the CLI
1380
+ measure_before_emit: true
1381
+ list:
1382
+ max_utf8_bytes: 32768
1383
+ benchmark:
1384
+ small:
1385
+ entries: 100
1386
+ max_latency_ms: 5000
1387
+ max_heap_delta_bytes: 67108864
1388
+ large:
1389
+ entries: 1000
1390
+ max_latency_ms: 15000
1391
+ max_heap_delta_bytes: 268435456
1392
+ response_max_utf8_bytes: 32768
1393
+ index_decision:
1394
+ decision: no_index
1395
+ trigger: >-
1396
+ Defer a persistent index until the large fixture exceeds any declared
1397
+ latency, heap, or response threshold on a reproducible authority test.
1398
+ projection:
1399
+ max_utf8_bytes: 32768
1400
+ applies_to: current, summary, and migration result responses
1401
+ required_when_over_budget: [omitted, omitted_count, omission_reason, retrieval]
1402
+ omission_semantics: >-
1403
+ Remove optional detail entries in deterministic numeric order from the
1404
+ response, retain required identity/count/source fields, and expose a next
1405
+ retrieval pointer. Never split UTF-8, truncate a scalar, or silently drop
1406
+ an entry. If required/source fields themselves exceed the budget, emit a
1407
+ measured minimal degraded envelope with projection output-budget error
1408
+ metadata rather than returning an over-budget payload.
1409
+ startup:
1410
+ source_manifest: scripts/json_output_surface_manifest.yaml
1411
+ source_work:
1412
+ schema_version: agentera.startupSourceWorkBudget.v1
1413
+ measurement: >-
1414
+ Count current projection entry rows and archive files inspected by the
1415
+ source-side metadata query. Full archive records are never retained by
1416
+ startup consumers.
1417
+ small:
1418
+ max_current_entries: 100
1419
+ max_archive_files: 100
1420
+ max_latency_ms: 5000
1421
+ max_heap_delta_bytes: 67108864
1422
+ large:
1423
+ max_current_entries: 1000
1424
+ max_archive_files: 1000
1425
+ max_latency_ms: 15000
1426
+ max_heap_delta_bytes: 268435456
1427
+ serialized_output:
1428
+ prime_capability_context_max_utf8_bytes: 50000
1429
+ surfaces:
1430
+ prime_briefing:
1431
+ manifest_id: prime-briefing
1432
+ max_utf8_bytes: 35000
1433
+ prime_dashboard:
1434
+ manifest_id: prime-dashboard
1435
+ max_utf8_bytes: 35000
1436
+ prime_sparse:
1437
+ manifest_id: prime-fields-sparse
1438
+ max_utf8_bytes: 28000
1439
+ required_when_over_budget: [omitted, omitted_count, omission_reason, retrieval]
1440
+ omission_semantics: >-
1441
+ Omit optional historical detail and retain counts, actionable IDs,
1442
+ compatibility, source_contract, and exact get/list command pointers. The
1443
+ caller must be able to distinguish omitted detail from unavailable detail.
1444
+ validation:
1445
+ authority: this file plus the referenced JSON surface manifest
1446
+ drift_rule: tests fail if manifest IDs or byte values disagree with this contract