@imunitic/synapse 0.9.0 → 0.11.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.
- package/commands/synapse-design-note.md +2 -2
- package/commands/synapse-note.md +2 -2
- package/commands/synapse-status.md +38 -21
- package/harness/codex/skills/synapse-design-note/SKILL.md +2 -2
- package/harness/codex/skills/synapse-note/SKILL.md +2 -2
- package/harness/codex/skills/synapse-status/SKILL.md +38 -22
- package/package.json +4 -4
- package/schema/vault-design-note/v1.yaml +30 -17
- package/schema/vault-note/v1.yaml +24 -11
- package/schema/vault-task-note/v1.yaml +35 -21
- package/skills/synapse-node-format/SKILL.md +1 -1
- package/skills/synapse-task/SKILL.md +1 -2
|
@@ -217,8 +217,8 @@ unquoted all-digit value is parsed as an integer, which fails a `type: string` s
|
|
|
217
217
|
field. `title`, `project`, `note_id`, and both timestamps are quoted above.
|
|
218
218
|
|
|
219
219
|
Resolve tags through the `synapse-vault` skill's configured vocabulary procedure. Fetch machine
|
|
220
|
-
local time once (`
|
|
221
|
-
|
|
220
|
+
local time once (`synapse now`) — never infer it — and use the exact same value for `created` and
|
|
221
|
+
`updated`.
|
|
222
222
|
|
|
223
223
|
No `Notes`/changelog section — it stays a small, single-conclusion note; there's no long-running
|
|
224
224
|
edit history here worth tracking separately.
|
package/commands/synapse-note.md
CHANGED
|
@@ -174,8 +174,8 @@ or supplied directly by a caller like `/synapse-task-note`):
|
|
|
174
174
|
2. Resolve tags through the `synapse-vault` skill's configured
|
|
175
175
|
`synapse-tag-vocabulary.conf` procedure. Choose only entries already in that vocabulary; an
|
|
176
176
|
empty list is valid when no tag applies, but the `tags` field itself is mandatory.
|
|
177
|
-
3. Fetch machine local time once: `
|
|
178
|
-
|
|
177
|
+
3. Fetch machine local time once: `synapse now` — never use inferred time. Use the
|
|
178
|
+
exact same value for `created` and `updated`.
|
|
179
179
|
4. Build the file content. A bare note needs a concise Summary. A task note needs lead prose and
|
|
180
180
|
at least one real flat checklist item before it can be written; never create an invalid empty
|
|
181
181
|
skeleton and promise to populate it later.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Print a read-only report of what in Synapse Vault currently needs a human decision -- design notes still Discussing, design notes marked Ready with no compiled task yet, design notes with open questions, task notes with unchecked items, and task notes stuck in REVIEW. Use whenever the user wants a status check on the vault ("what's outstanding", "what needs my attention", "vault status", "what did we leave open"). Never modifies anything -- a report only, not a task-management action. Not for creating, continuing, or listing a specific note kind (that's synapse-note/synapse-design-note/synapse-task-note's own --list modes) -- this is the one cross-cutting view over all of them at once.
|
|
2
|
+
description: Print a read-only report of what in Synapse Vault currently needs a human decision -- design notes still Discussing, design notes marked Ready with no compiled task yet, Ready design notes with open questions still outstanding, task notes with unchecked items, and task notes stuck in REVIEW. Use whenever the user wants a status check on the vault ("what's outstanding", "what needs my attention", "vault status", "what did we leave open"). Never modifies anything -- a report only, not a task-management action. Not for creating, continuing, or listing a specific note kind (that's synapse-note/synapse-design-note/synapse-task-note's own --list modes) -- this is the one cross-cutting view over all of them at once.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# Synapse Status: Vault-Wide Attention Report
|
|
@@ -64,34 +64,52 @@ synapse vault-search --fields frontmatter.title,frontmatter.note_id <<'EOF'
|
|
|
64
64
|
EOF
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
**3.
|
|
68
|
-
at least one bullet -- a heading with nothing under
|
|
69
|
-
`/synapse-design-note` now follows) doesn't count as
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
**3. `Ready` design notes with a non-empty `## Open Questions`, excluding ones whose compiled task is
|
|
68
|
+
already `DONE`.** Match the heading followed by at least one bullet -- a heading with nothing under
|
|
69
|
+
it (fully pruned, per the Ready-gate convention `/synapse-design-note` now follows) doesn't count as
|
|
70
|
+
open. A `Discussing` note with open questions isn't actionable yet (it's still being worked out in
|
|
71
|
+
conversation, surfaced already by query 1), and a note whose compiled task has already shipped is
|
|
72
|
+
stale noise -- so this query narrows to the two states that actually need a human decision: `Ready`
|
|
73
|
+
with open questions and no compiled task, or `Ready` with open questions and a compiled task that
|
|
74
|
+
hasn't reached `DONE`. `vault-search` has no cross-note join, so this takes two queries: the first
|
|
75
|
+
finds `Ready`-with-open-questions design notes and pulls each one's compiled-task title (if any)
|
|
76
|
+
straight out of its own `content`; the second resolves those titles' status against `tasks/`.
|
|
73
77
|
|
|
74
78
|
```
|
|
75
79
|
synapse vault-search --fields frontmatter.title,frontmatter.note_id,content <<'EOF'
|
|
76
80
|
{"and": [
|
|
77
81
|
{"glob": ["designs/*", {"var": "path"}]},
|
|
82
|
+
{"regexp": ["## Status\nReady", {"var": "content"}]},
|
|
78
83
|
{"regexp": ["## Open Questions\n- ", {"var": "content"}]}
|
|
79
84
|
]}
|
|
80
85
|
EOF
|
|
81
86
|
```
|
|
82
87
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
For each match, pull the target of a `> Compiled task: [[...]]` line out of its `content`, if present
|
|
89
|
+
-- parsed straight out of the wikilink text rather than resolved through any vault-wide link index.
|
|
90
|
+
Collect the distinct compiled-task titles found across all matches. If none of the matches have a
|
|
91
|
+
`Compiled task:` line, skip the second query entirely -- every match stays in (no compiled task means
|
|
92
|
+
the "either" branch is already satisfied). Otherwise, resolve those titles' status in one follow-up
|
|
93
|
+
call:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
synapse vault-search --fields frontmatter.title,frontmatter.status <<'EOF'
|
|
97
|
+
{"and": [
|
|
98
|
+
{"glob": ["tasks/*", {"var": "path"}]},
|
|
99
|
+
{"in": [{"var": "frontmatter.title"}, ["{title one}", "{title two}"]]}
|
|
100
|
+
]}
|
|
101
|
+
EOF
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Keep a match from the first query only if it has no `Compiled task:` line, or its compiled task's
|
|
105
|
+
title isn't found in the second query's results with `frontmatter.status` equal to `DONE` -- a title
|
|
106
|
+
the second query didn't return at all (a stale or broken link) counts as "not `DONE`" and stays in,
|
|
107
|
+
since a broken link is itself worth a human noticing rather than a reason to drop the note silently.
|
|
90
108
|
|
|
91
109
|
A `regexp` pattern containing a literal newline (`\n`) must be written with a single backslash, byte-
|
|
92
110
|
for-byte, in the JSON text piped to `vault-search` -- the heredocs above are unquoted-delimiter
|
|
93
111
|
(`<<'EOF'`), so nothing here re-escapes it; `\\n` would reach the JSON parser as a literal backslash
|
|
94
|
-
followed by `n`, never matching a real line break, and every
|
|
112
|
+
followed by `n`, never matching a real line break, and every `regexp` query in this command would
|
|
95
113
|
silently stop finding anything under a multi-line pattern.
|
|
96
114
|
|
|
97
115
|
**4. Open task notes with at least one unchecked item.** Task notes carry `status:` in frontmatter,
|
|
@@ -127,11 +145,10 @@ one is that a human can act on a line directly ("open sb-068") without the title
|
|
|
127
145
|
step — followed by the title, plus whatever other identifying detail that category needs. A note
|
|
128
146
|
somehow missing its id (pre-dates the field, or the backfill hasn't reached it yet) drops the bracket
|
|
129
147
|
entirely rather than printing an empty one, the same graceful-degradation the title-less case already
|
|
130
|
-
gets.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
notes, so put the status first, before the id, so it's the first thing scanned:
|
|
148
|
+
gets. Every section's heading already implies status now (the "Discussing" section only ever holds
|
|
149
|
+
`Discussing` notes, "Open questions" only ever holds `Ready` ones per query 3 above), but Open
|
|
150
|
+
questions still spans both compiled and uncompiled notes, so its line also names the compiled task
|
|
151
|
+
(or says there isn't one) -- the one piece of state that section doesn't already imply:
|
|
135
152
|
|
|
136
153
|
```
|
|
137
154
|
## Discussing
|
|
@@ -141,7 +158,7 @@ notes, so put the status first, before the id, so it's the first thing scanned:
|
|
|
141
158
|
- [{note_id}] {title}
|
|
142
159
|
|
|
143
160
|
## Open questions
|
|
144
|
-
-
|
|
161
|
+
- [{note_id}] {title} — {compiled task title, or "not compiled"}
|
|
145
162
|
|
|
146
163
|
## In progress (unchecked items)
|
|
147
164
|
- [{task_id}] {title} ({N} unchecked)
|
|
@@ -220,8 +220,8 @@ Open Questions (optional)`: the schema and `/synapse-status`'s own query both ma
|
|
|
220
220
|
heading text, and a suffixed one is invisible to both.
|
|
221
221
|
|
|
222
222
|
Resolve tags through the `synapse-vault` skill's configured vocabulary procedure. Fetch machine
|
|
223
|
-
local time once (`
|
|
224
|
-
|
|
223
|
+
local time once (`synapse now`) — never infer it — and use the exact same value for `created` and
|
|
224
|
+
`updated`.
|
|
225
225
|
|
|
226
226
|
No `Notes`/changelog section — it stays a small, single-conclusion note; there's no long-running
|
|
227
227
|
edit history here worth tracking separately.
|
|
@@ -193,8 +193,8 @@ or supplied directly by a caller like the synapse-task-note skill):
|
|
|
193
193
|
2. Resolve tags through the `synapse-vault` skill's configured
|
|
194
194
|
`synapse-tag-vocabulary.conf` procedure. Choose only configured entries; an empty list is valid
|
|
195
195
|
when no tag applies, but the field itself is mandatory.
|
|
196
|
-
3. Fetch machine local time once: `
|
|
197
|
-
|
|
196
|
+
3. Fetch machine local time once: `synapse now` — never use inferred time. Use the
|
|
197
|
+
exact same value for `created` and `updated`.
|
|
198
198
|
4. Build the file content. Bare notes require a concise Summary. Task notes require lead prose and
|
|
199
199
|
at least one real flat checklist item before the first write.
|
|
200
200
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: synapse-status
|
|
3
|
-
description: Print a read-only report of what in Synapse Vault currently needs a human decision -- design notes still Discussing, design notes marked Ready with no compiled task yet, design notes with open questions, task notes with unchecked items, and task notes stuck in REVIEW. Use whenever the user wants a status check on the vault ("what's outstanding", "what needs my attention", "vault status", "what did we leave open"). Never modifies anything -- a report only, not a task-management action. Not for creating, continuing, or listing a specific note kind (that's the synapse-note/synapse-design-note/synapse-task-note skills' own --list modes) -- this is the one cross-cutting view over all of them at once.
|
|
3
|
+
description: Print a read-only report of what in Synapse Vault currently needs a human decision -- design notes still Discussing, design notes marked Ready with no compiled task yet, Ready design notes with open questions still outstanding, task notes with unchecked items, and task notes stuck in REVIEW. Use whenever the user wants a status check on the vault ("what's outstanding", "what needs my attention", "vault status", "what did we leave open"). Never modifies anything -- a report only, not a task-management action. Not for creating, continuing, or listing a specific note kind (that's the synapse-note/synapse-design-note/synapse-task-note skills' own --list modes) -- this is the one cross-cutting view over all of them at once.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Synapse Status: Vault-Wide Attention Report
|
|
@@ -66,35 +66,52 @@ synapse vault-search --fields frontmatter.title,frontmatter.note_id <<'EOF'
|
|
|
66
66
|
EOF
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
**3.
|
|
70
|
-
at least one bullet -- a heading with nothing under
|
|
71
|
-
Ready-gate convention) doesn't count as open.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
**3. `Ready` design notes with a non-empty `## Open Questions`, excluding ones whose compiled task is
|
|
70
|
+
already `DONE`.** Match the heading followed by at least one bullet -- a heading with nothing under
|
|
71
|
+
it (fully pruned, per the design-note skill's own Ready-gate convention) doesn't count as open. A
|
|
72
|
+
`Discussing` note with open questions isn't actionable yet (it's still being worked out in
|
|
73
|
+
conversation, surfaced already by query 1), and a note whose compiled task has already shipped is
|
|
74
|
+
stale noise -- so this query narrows to the two states that actually need a human decision: `Ready`
|
|
75
|
+
with open questions and no compiled task, or `Ready` with open questions and a compiled task that
|
|
76
|
+
hasn't reached `DONE`. `vault-search` has no cross-note join, so this takes two queries: the first
|
|
77
|
+
finds `Ready`-with-open-questions design notes and pulls each one's compiled-task title (if any)
|
|
78
|
+
straight out of its own `content`; the second resolves those titles' status against `tasks/`.
|
|
75
79
|
|
|
76
80
|
```
|
|
77
81
|
synapse vault-search --fields frontmatter.title,frontmatter.note_id,content <<'EOF'
|
|
78
82
|
{"and": [
|
|
79
83
|
{"glob": ["designs/*", {"var": "path"}]},
|
|
84
|
+
{"regexp": ["## Status\nReady", {"var": "content"}]},
|
|
80
85
|
{"regexp": ["## Open Questions\n- ", {"var": "content"}]}
|
|
81
86
|
]}
|
|
82
87
|
EOF
|
|
83
88
|
```
|
|
84
89
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
For each match, pull the target of a `> Compiled task: [[...]]` line out of its `content`, if present
|
|
91
|
+
-- parsed straight out of the wikilink text rather than resolved through any vault-wide link index.
|
|
92
|
+
Collect the distinct compiled-task titles found across all matches. If none of the matches have a
|
|
93
|
+
`Compiled task:` line, skip the second query entirely -- every match stays in (no compiled task means
|
|
94
|
+
the "either" branch is already satisfied). Otherwise, resolve those titles' status in one follow-up
|
|
95
|
+
call:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
synapse vault-search --fields frontmatter.title,frontmatter.status <<'EOF'
|
|
99
|
+
{"and": [
|
|
100
|
+
{"glob": ["tasks/*", {"var": "path"}]},
|
|
101
|
+
{"in": [{"var": "frontmatter.title"}, ["{title one}", "{title two}"]]}
|
|
102
|
+
]}
|
|
103
|
+
EOF
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Keep a match from the first query only if it has no `Compiled task:` line, or its compiled task's
|
|
107
|
+
title isn't found in the second query's results with `frontmatter.status` equal to `DONE` -- a title
|
|
108
|
+
the second query didn't return at all (a stale or broken link) counts as "not `DONE`" and stays in,
|
|
109
|
+
since a broken link is itself worth a human noticing rather than a reason to drop the note silently.
|
|
93
110
|
|
|
94
111
|
A `regexp` pattern containing a literal newline (`\n`) must be written with a single backslash, byte-
|
|
95
112
|
for-byte, in the JSON text piped to `vault-search` -- the heredocs above are unquoted-delimiter
|
|
96
113
|
(`<<'EOF'`), so nothing here re-escapes it; `\\n` would reach the JSON parser as a literal backslash
|
|
97
|
-
followed by `n`, never matching a real line break, and every
|
|
114
|
+
followed by `n`, never matching a real line break, and every `regexp` query in this skill would
|
|
98
115
|
silently stop finding anything under a multi-line pattern.
|
|
99
116
|
|
|
100
117
|
**4. Open task notes with at least one unchecked item.** Task notes carry `status:` in frontmatter,
|
|
@@ -129,11 +146,10 @@ One section per category, in the order above. Each line leads with the note's ow
|
|
|
129
146
|
one is that a human can act on a line directly ("open sb-068") without the title as an intermediate
|
|
130
147
|
step — followed by the title. A note somehow missing its id (pre-dates the field) drops the bracket
|
|
131
148
|
entirely rather than printing an empty one, the same graceful-degradation the title-less case already
|
|
132
|
-
gets.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
notes, so put the status first, before the id, so it's the first thing scanned:
|
|
149
|
+
gets. Every section's heading already implies status now (the "Discussing" section only ever holds
|
|
150
|
+
`Discussing` notes, "Open questions" only ever holds `Ready` ones per query 3 above), but Open
|
|
151
|
+
questions still spans both compiled and uncompiled notes, so its line also names the compiled task
|
|
152
|
+
(or says there isn't one) -- the one piece of state that section doesn't already imply:
|
|
137
153
|
|
|
138
154
|
```
|
|
139
155
|
## Discussing
|
|
@@ -143,7 +159,7 @@ notes, so put the status first, before the id, so it's the first thing scanned:
|
|
|
143
159
|
- [{note_id}] {title}
|
|
144
160
|
|
|
145
161
|
## Open questions
|
|
146
|
-
-
|
|
162
|
+
- [{note_id}] {title} — {compiled task title, or "not compiled"}
|
|
147
163
|
|
|
148
164
|
## In progress (unchecked items)
|
|
149
165
|
- [{task_id}] {title} ({N} unchecked)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imunitic/synapse",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Memory for Claude Code, Codex CLI, and OpenCode: a durable markdown vault plus a per-repo code graph.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"*.conf.template"
|
|
24
24
|
],
|
|
25
25
|
"optionalDependencies": {
|
|
26
|
-
"@imunitic/synapse-darwin-arm64": "0.
|
|
27
|
-
"@imunitic/synapse-linux-x64": "0.
|
|
28
|
-
"@imunitic/synapse-linux-arm64": "0.
|
|
26
|
+
"@imunitic/synapse-darwin-arm64": "0.11.0",
|
|
27
|
+
"@imunitic/synapse-linux-x64": "0.11.0",
|
|
28
|
+
"@imunitic/synapse-linux-arm64": "0.11.0"
|
|
29
29
|
},
|
|
30
30
|
"license": "SEE LICENSE IN LICENSE"
|
|
31
31
|
}
|
|
@@ -79,25 +79,38 @@ body:
|
|
|
79
79
|
section_order: relative
|
|
80
80
|
|
|
81
81
|
checks:
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
-
|
|
94
|
-
|
|
95
|
-
|
|
82
|
+
- eq:
|
|
83
|
+
- var: filename.stem
|
|
84
|
+
- var: frontmatter.title
|
|
85
|
+
message: 'filename.stem: must equal frontmatter.title'
|
|
86
|
+
- on_create:
|
|
87
|
+
var: id_is_unique
|
|
88
|
+
message: 'frontmatter.note_id: identity already exists'
|
|
89
|
+
- in:
|
|
90
|
+
- var: frontmatter.project
|
|
91
|
+
- var: vocabularies.synapse-projects
|
|
92
|
+
message: 'frontmatter.project: not in synapse-projects.conf'
|
|
93
|
+
- all:
|
|
94
|
+
- var: frontmatter.tags
|
|
95
|
+
- in:
|
|
96
|
+
- var: ''
|
|
97
|
+
- var: vocabularies.synapse-tag-vocabulary
|
|
98
|
+
message: 'frontmatter.tags: every tag must be in synapse-tag-vocabulary.conf'
|
|
99
|
+
- lte:
|
|
100
|
+
- var: created_epoch
|
|
101
|
+
- var: updated_epoch
|
|
102
|
+
message: 'frontmatter.updated: must not precede frontmatter.created'
|
|
103
|
+
- on_create:
|
|
104
|
+
eq:
|
|
105
|
+
- var: created_epoch
|
|
106
|
+
- var: updated_epoch
|
|
107
|
+
message: 'frontmatter.created: must equal frontmatter.updated on creation'
|
|
96
108
|
|
|
97
109
|
lints:
|
|
98
|
-
- no_hard_wrap:
|
|
110
|
+
- no_hard_wrap:
|
|
111
|
+
var: body.prose
|
|
99
112
|
severity: warn
|
|
100
113
|
- no_id_prefix_in_title:
|
|
101
|
-
|
|
102
|
-
|
|
114
|
+
- var: frontmatter.title
|
|
115
|
+
- var: frontmatter.note_id
|
|
103
116
|
severity: warn
|
|
@@ -55,17 +55,30 @@ body:
|
|
|
55
55
|
section_order: relative
|
|
56
56
|
|
|
57
57
|
checks:
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
- eq:
|
|
59
|
+
- var: filename.stem
|
|
60
|
+
- var: frontmatter.title
|
|
61
|
+
message: 'filename.stem: must equal frontmatter.title'
|
|
62
|
+
- on_create:
|
|
63
|
+
var: id_is_unique
|
|
64
|
+
message: 'frontmatter.note_id: identity already exists'
|
|
65
|
+
- all:
|
|
66
|
+
- var: frontmatter.tags
|
|
67
|
+
- in:
|
|
68
|
+
- var: ''
|
|
69
|
+
- var: vocabularies.synapse-tag-vocabulary
|
|
70
|
+
message: 'frontmatter.tags: every tag must be in synapse-tag-vocabulary.conf'
|
|
71
|
+
- lte:
|
|
72
|
+
- var: created_epoch
|
|
73
|
+
- var: updated_epoch
|
|
74
|
+
message: 'frontmatter.updated: must not precede frontmatter.created'
|
|
75
|
+
- on_create:
|
|
76
|
+
eq:
|
|
77
|
+
- var: created_epoch
|
|
78
|
+
- var: updated_epoch
|
|
79
|
+
message: 'frontmatter.created: must equal frontmatter.updated on creation'
|
|
68
80
|
|
|
69
81
|
lints:
|
|
70
|
-
- no_hard_wrap:
|
|
82
|
+
- no_hard_wrap:
|
|
83
|
+
var: body.prose
|
|
71
84
|
severity: warn
|
|
@@ -73,29 +73,43 @@ body:
|
|
|
73
73
|
section_order: relative
|
|
74
74
|
|
|
75
75
|
checks:
|
|
76
|
-
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
76
|
+
- eq:
|
|
77
|
+
- var: filename.stem
|
|
78
|
+
- var: frontmatter.title
|
|
79
|
+
message: 'filename.stem: must equal frontmatter.title'
|
|
80
|
+
- on_create:
|
|
81
|
+
var: id_is_unique
|
|
82
|
+
message: 'frontmatter.task_id: identity already exists'
|
|
83
|
+
- in:
|
|
84
|
+
- var: frontmatter.project
|
|
85
|
+
- var: vocabularies.synapse-projects
|
|
86
|
+
message: 'frontmatter.project: not in synapse-projects.conf'
|
|
87
|
+
- all:
|
|
88
|
+
- var: frontmatter.tags
|
|
89
|
+
- in:
|
|
90
|
+
- var: ''
|
|
91
|
+
- var: vocabularies.synapse-tag-vocabulary
|
|
92
|
+
message: 'frontmatter.tags: every tag must be in synapse-tag-vocabulary.conf'
|
|
93
|
+
- lte:
|
|
94
|
+
- var: created_epoch
|
|
95
|
+
- var: updated_epoch
|
|
96
|
+
message: 'frontmatter.updated: must not precede frontmatter.created'
|
|
97
|
+
- on_create:
|
|
98
|
+
eq:
|
|
99
|
+
- var: created_epoch
|
|
100
|
+
- var: updated_epoch
|
|
101
|
+
message: 'frontmatter.created: must equal frontmatter.updated on creation'
|
|
102
|
+
- on_create:
|
|
103
|
+
eq:
|
|
104
|
+
- var: frontmatter.status
|
|
105
|
+
- TODO
|
|
106
|
+
message: 'frontmatter.status: must equal TODO on creation'
|
|
94
107
|
|
|
95
108
|
lints:
|
|
96
|
-
- no_hard_wrap:
|
|
109
|
+
- no_hard_wrap:
|
|
110
|
+
var: body.prose
|
|
97
111
|
severity: warn
|
|
98
112
|
- no_id_prefix_in_title:
|
|
99
|
-
|
|
100
|
-
|
|
113
|
+
- var: frontmatter.title
|
|
114
|
+
- var: frontmatter.task_id
|
|
101
115
|
severity: warn
|
|
@@ -63,7 +63,7 @@ to orient someone already inside. A node without one is an error, not a default.
|
|
|
63
63
|
- **`sources_digest`:** `sha256` over the sorted `path:hash` lines of `sources` (see "Computing
|
|
64
64
|
`sources_digest`" below). Lets a staleness check answer "has this node changed" by reading one
|
|
65
65
|
field instead of every hash.
|
|
66
|
-
- **`built_at`:** machine local time (`
|
|
66
|
+
- **`built_at`:** machine local time (`synapse now --built-at`) — never inferred.
|
|
67
67
|
- **`stale`:** `false` — freshly built.
|
|
68
68
|
- **Body:** `summary` (plain-English, the explanation a senior engineer would give walking
|
|
69
69
|
someone through this subsystem), `crux` (the few lines that carry the actual logic — **authored
|
|
@@ -60,8 +60,7 @@ into `status:` either — always go through this skill, which caps at
|
|
|
60
60
|
2. Inspect its checklist items (`- [ ]` / `- [x]`).
|
|
61
61
|
3. Determine the new `status:` value: `IN-PROGRESS` if any unchecked,
|
|
62
62
|
`REVIEW` if all checked.
|
|
63
|
-
4. Fetch machine local time: `
|
|
64
|
-
time.
|
|
63
|
+
4. Fetch machine local time: `synapse now` — never use inferred time.
|
|
65
64
|
5. Update `status:` and `updated:` with two `synapse frontmatter set`
|
|
66
65
|
calls, one per field: `synapse frontmatter set <path> status <value>`
|
|
67
66
|
then `synapse frontmatter set <path> updated "{now}"`. Each call
|