provenance-cli 0.1.0__tar.gz → 0.2.0__tar.gz
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.
- provenance_cli-0.2.0/.agents/skills/spec-capture-expectations/SKILL.md +140 -0
- provenance_cli-0.2.0/.agents/skills/spec-drift-sync/SKILL.md +152 -0
- provenance_cli-0.2.0/.agents/skills/spec-entry-format/SKILL.md +302 -0
- provenance_cli-0.2.0/.agents/skills/spec-request-flow/SKILL.md +174 -0
- provenance_cli-0.2.0/.claude/skills/spec-capture-expectations/SKILL.md +140 -0
- provenance_cli-0.2.0/.claude/skills/spec-drift-sync/SKILL.md +152 -0
- provenance_cli-0.2.0/.claude/skills/spec-entry-format/SKILL.md +302 -0
- provenance_cli-0.2.0/.claude/skills/spec-request-flow/SKILL.md +174 -0
- provenance_cli-0.2.0/.editorconfig +22 -0
- provenance_cli-0.2.0/.gitattributes +19 -0
- provenance_cli-0.2.0/.github/workflows/ci.yml +31 -0
- provenance_cli-0.2.0/.github/workflows/publish-pypi.yml +27 -0
- provenance_cli-0.2.0/.gitignore +71 -0
- provenance_cli-0.2.0/.python-version +1 -0
- provenance_cli-0.2.0/AGENTS.md +43 -0
- provenance_cli-0.2.0/CLAUDE.md +43 -0
- provenance_cli-0.2.0/PKG-INFO +133 -0
- provenance_cli-0.2.0/README.md +107 -0
- provenance_cli-0.2.0/docs/README.md +13 -0
- provenance_cli-0.2.0/docs/agent-setup.md +110 -0
- provenance_cli-0.2.0/docs/architecture.md +2002 -0
- provenance_cli-0.2.0/docs/cli.md +238 -0
- provenance_cli-0.2.0/docs/development.md +62 -0
- provenance_cli-0.2.0/docs/publishing.md +65 -0
- provenance_cli-0.2.0/docs/spec-format.md +219 -0
- provenance_cli-0.2.0/install.sh +83 -0
- provenance_cli-0.2.0/prov/.spec/code-index.json +184 -0
- provenance_cli-0.2.0/prov/.spec/graph.json +1977 -0
- provenance_cli-0.2.0/prov/CONTEXT.md +40 -0
- provenance_cli-0.2.0/prov/agent.md +119 -0
- provenance_cli-0.2.0/prov/cli.md +96 -0
- provenance_cli-0.2.0/prov/core.md +48 -0
- provenance_cli-0.2.0/prov/format.md +83 -0
- provenance_cli-0.2.0/prov/install.md +96 -0
- provenance_cli-0.2.0/prov/storage.md +66 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/pyproject.toml +11 -6
- provenance_cli-0.2.0/scripts/build.sh +17 -0
- provenance_cli-0.2.0/scripts/dev-install.sh +21 -0
- provenance_cli-0.2.0/scripts/install-spec-pre-commit.sh +237 -0
- provenance_cli-0.2.0/scripts/publish.sh +25 -0
- provenance_cli-0.2.0/src/prov/__init__.py +11 -0
- provenance_cli-0.2.0/src/prov/__main__.py +7 -0
- provenance_cli-0.2.0/src/prov/cli.py +258 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/check_slug.py +1 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/context.py +1 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/diff.py +1 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/domain.py +1 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/find.py +1 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/impact.py +5 -4
- provenance_cli-0.2.0/src/prov/commands/init.py +111 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/orient.py +36 -16
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/rebuild.py +1 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/reconcile.py +1 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/scope.py +5 -4
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/sync.py +1 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/validate.py +2 -1
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/write.py +1 -0
- provenance_cli-0.2.0/src/prov/format.py +100 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/indexing.py +54 -11
- provenance_cli-0.2.0/src/prov/installer.py +170 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/model.py +1 -0
- provenance_cli-0.2.0/src/prov/prompts/spec-agent.md +581 -0
- provenance_cli-0.2.0/src/prov/rules/project-rules.md +41 -0
- provenance_cli-0.2.0/src/prov/rules/spec-agent-protocol.md +116 -0
- provenance_cli-0.2.0/src/prov/rules/spec-skill-router.md +88 -0
- provenance_cli-0.2.0/src/prov/skills/spec-capture-expectations/SKILL.md +140 -0
- provenance_cli-0.2.0/src/prov/skills/spec-drift-sync/SKILL.md +152 -0
- provenance_cli-0.2.0/src/prov/skills/spec-entry-format/SKILL.md +302 -0
- provenance_cli-0.2.0/src/prov/skills/spec-request-flow/SKILL.md +174 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/spec_io.py +5 -3
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/writer.py +1 -0
- provenance_cli-0.2.0/tests/test_backlinks.py +79 -0
- provenance_cli-0.2.0/tests/test_installer.py +170 -0
- provenance_cli-0.2.0/uv.lock +324 -0
- provenance_cli-0.1.0/PKG-INFO +0 -423
- provenance_cli-0.1.0/README.md +0 -397
- provenance_cli-0.1.0/setup.cfg +0 -4
- provenance_cli-0.1.0/src/prov/__init__.py +0 -4
- provenance_cli-0.1.0/src/prov/cli.py +0 -105
- provenance_cli-0.1.0/src/prov/commands/init.py +0 -41
- provenance_cli-0.1.0/src/provenance_cli.egg-info/PKG-INFO +0 -423
- provenance_cli-0.1.0/src/provenance_cli.egg-info/SOURCES.txt +0 -29
- provenance_cli-0.1.0/src/provenance_cli.egg-info/dependency_links.txt +0 -1
- provenance_cli-0.1.0/src/provenance_cli.egg-info/entry_points.txt +0 -2
- provenance_cli-0.1.0/src/provenance_cli.egg-info/top_level.txt +0 -1
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/LICENSE +0 -0
- {provenance_cli-0.1.0 → provenance_cli-0.2.0}/src/prov/commands/__init__.py +0 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-capture-expectations
|
|
3
|
+
version: "1.0"
|
|
4
|
+
description: "Extract implicit user expectations and compile them into the spec. Use when starting a session or picking up a new task, when user words imply a behavior, constraint, or rule not yet in the spec, when a request reveals an assumption, edge case, or threshold to write down, or when deciding whether to add or update a spec entry."
|
|
5
|
+
triggers:
|
|
6
|
+
- session start or picking up a new task
|
|
7
|
+
- user words imply a behavior, constraint, or rule not yet in the spec
|
|
8
|
+
- request reveals an assumption, edge case, or threshold to write down
|
|
9
|
+
- deciding whether to add or update a spec entry
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Mission
|
|
13
|
+
|
|
14
|
+
On every task, extract implicit user expectations and compile them into the spec so the spec remains the single, correct record of what the user expects — not what was guessed or left in conversation.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Pre-requisites
|
|
19
|
+
|
|
20
|
+
- **Spec directory** present: `prov/`, `spec/`, or `specs/`.
|
|
21
|
+
- **Read access** to existing spec files (to check what is already captured).
|
|
22
|
+
- **Write access** to spec files when adding or updating entries (only after user confirms in Phase 3 of the request flow).
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Instructions
|
|
27
|
+
|
|
28
|
+
### Step 1 — Before acting, run the five questions
|
|
29
|
+
|
|
30
|
+
For the current request, answer (see Reference for detail):
|
|
31
|
+
|
|
32
|
+
1. Is there a behavior implied here that is not yet in the spec?
|
|
33
|
+
2. Would a future reader of the spec infer the same thing the user expects?
|
|
34
|
+
3. Is there a number, threshold, limit, or edge case the user assumed?
|
|
35
|
+
4. Does this reveal a domain-wide constraint ("always", "never")?
|
|
36
|
+
5. Is an existing entry now wrong or incomplete?
|
|
37
|
+
|
|
38
|
+
### Step 2 — Decide: add, update, or skip
|
|
39
|
+
|
|
40
|
+
Use the tables in Reference: **When to add a new entry** and **When NOT to add**. Add when user states or implies a behavior, specifies a constraint, an edge case is missing, or a bug fix reveals correct behavior never specified. Do not add for competent-developer defaults, implementation-only details, or duplicates.
|
|
41
|
+
|
|
42
|
+
### Step 3 — Record implicit expectations in the right form
|
|
43
|
+
|
|
44
|
+
- User’s words reveal unstated behavior → add requirement with `> user: "exact quote"` and `~` when implemented (see Reference example).
|
|
45
|
+
- You infer a value they didn’t give (e.g. "keep it fast") → add entry with `> inferred: reasoning` and ` ! assumed <value> — <reason unconfirmed>`. Surface the `!` in Phase 3; user confirms, corrects, or defers (see Reference example).
|
|
46
|
+
|
|
47
|
+
### Step 4 — Apply assumption discipline
|
|
48
|
+
|
|
49
|
+
Every gap you fill on the user’s behalf gets a `!` line. When surfacing `!`: **Confirm** → remove `!`; **Correct** → rewrite statement, remove `!`; **Defer** → keep `!` (it will appear in every future diff until confirmed). See Reference → Assumption discipline.
|
|
50
|
+
|
|
51
|
+
### Step 5 — Feed into the request flow
|
|
52
|
+
|
|
53
|
+
All new or changed entries are proposed in Phase 3 and written in Phase 4 of the request flow. Do not add entries without going through the flow (propose → confirm → write).
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Reference
|
|
58
|
+
|
|
59
|
+
### The principle
|
|
60
|
+
|
|
61
|
+
Every task is a chance to compile user intent into the spec. A well-maintained spec is one where a fresh agent, given only the spec and no prior context, would produce a system that matches everything the user actually expects. Never leave expectations only in code or only in conversation — compile them.
|
|
62
|
+
|
|
63
|
+
### Five questions (detail)
|
|
64
|
+
|
|
65
|
+
1. **Is there a behavior implied here that is not yet written in the spec?** If the user's request assumes something works a certain way and the spec doesn't say so, that's a missing entry.
|
|
66
|
+
2. **Would a future reader of the spec infer the same thing the user expects?** If not, update the entry — wrong statement, missing constraint, wrong scope.
|
|
67
|
+
3. **Is there a number, threshold, limit, or edge case the user assumed?** Record in the spec with a `!` line if unconfirmed, or as a confirmed statement if they said it.
|
|
68
|
+
4. **Does this reveal a domain-wide constraint?** If the user says "always", "never", or "under no circumstances", that's a `C:slug:` constraint entry, not just a requirement.
|
|
69
|
+
5. **Is an existing entry now wrong or incomplete?** The new request may reveal that an old entry was imprecise; update it in the same task.
|
|
70
|
+
|
|
71
|
+
### When to add a new entry
|
|
72
|
+
|
|
73
|
+
| Signal | Action |
|
|
74
|
+
|--------|--------|
|
|
75
|
+
| User states a behavior explicitly | Add requirement entry with `> user: "their words"` |
|
|
76
|
+
| User implies a behavior ("obviously it should...") | Add entry with `> inferred: <reasoning>` and `!` line |
|
|
77
|
+
| User specifies a constraint ("always", "never", "required") | Add `C:slug:` constraint entry |
|
|
78
|
+
| User's request would fail in an edge case not yet covered | Add entry for that edge case |
|
|
79
|
+
| Fixing a bug reveals the correct behavior was never specified | Add entry for the correct behavior |
|
|
80
|
+
| User corrects the agent's assumption | Remove `!`, update the statement to match the correction |
|
|
81
|
+
|
|
82
|
+
### When NOT to add a new entry
|
|
83
|
+
|
|
84
|
+
- Competent-developer defaults (error handling, logging patterns, standard HTTP responses) — skip.
|
|
85
|
+
- Implementation details the user never mentioned and that don't affect user-observable behavior — skip.
|
|
86
|
+
- Anything already correctly covered by an existing entry — skip; don't duplicate.
|
|
87
|
+
|
|
88
|
+
### How to record an implicit expectation — examples
|
|
89
|
+
|
|
90
|
+
**User's words reveal unstated behavior:**
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
user: "make sure the export always includes the full history"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
→ Add:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
export-full-history: Exports always include the complete history of the record.
|
|
100
|
+
> user: "make sure the export always includes the full history"
|
|
101
|
+
~ src/exports/history.py
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**You infer a value they didn't give:**
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
user: "keep it fast"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
→ "Fast" is unspecified. Add:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
export-performance: Export completes within 5 seconds for records up to 10,000 entries. [planned]
|
|
114
|
+
> inferred: user said "keep it fast" — interpreted as 5s / 10k entries
|
|
115
|
+
! assumed 5s / 10k entries — "fast" is unconfirmed
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Surface the `!` in Phase 3. The user either confirms, corrects, or defers.
|
|
119
|
+
|
|
120
|
+
### Assumption discipline
|
|
121
|
+
|
|
122
|
+
- `!` = "I decided this; the user has not confirmed it."
|
|
123
|
+
- No `!` = "The user said this, or it's an unambiguous default."
|
|
124
|
+
- When you surface a `!` to the user: **Confirm** → remove `!` (becomes user-specified). **Correct** → rewrite statement, remove `!`. **Defer** → keep `!`; do not remove it; it will appear in every future diff until the user explicitly confirms. The `!` is the record that this was not their explicit choice.
|
|
125
|
+
|
|
126
|
+
### The compounding spec
|
|
127
|
+
|
|
128
|
+
Over time, with every task handled this way, the spec converges on a complete, accurate picture of user intent. Each task adds signal. The spec becomes the memory of the system — not what the agent guessed, not what was obvious in the moment, but what the user actually wants. Never leave an expectation only in code. Never leave it only in conversation. Compile it.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Error Handling
|
|
133
|
+
|
|
134
|
+
| If this happens | Do this |
|
|
135
|
+
|-----------------|--------|
|
|
136
|
+
| You're unsure whether something is user expectation or implementation detail | Prefer capturing it with a `!` line so the user can confirm or remove. Do not leave it only in code. |
|
|
137
|
+
| User said something vague ("fast", "simple") and you chose a concrete value | Add a `!` line stating the assumed value and that the original was unconfirmed. Surface in Phase 3; do not remove `!` without user action. |
|
|
138
|
+
| You find an existing entry that's wrong but the user didn't ask to change it | Include the correction in your Phase 3 proposal ("I'm also updating X because the current spec says Y and the code/behavior is Z"). Get explicit confirmation. |
|
|
139
|
+
| You already added an entry and the user says "that's not what I meant" | Treat as correction: update the statement and provenance, remove or adjust `!`. Do not leave the wrong entry in place. |
|
|
140
|
+
| Multiple possible interpretations of the user's words | Propose one interpretation with a `!` line; in Phase 3 list the alternatives and ask which one they want. Do not implement until they choose. |
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-drift-sync
|
|
3
|
+
version: "1.0"
|
|
4
|
+
description: "Resolve drift between spec and code with the sync protocol, applying only user-confirmed fixes. Use when running prov sync or prov reconcile, after bulk refactors, large merges, or importing existing code, when the user asks to reconcile spec and code, or after autonomous code changes that may have left the spec out of date."
|
|
5
|
+
triggers:
|
|
6
|
+
- running prov sync or prov reconcile
|
|
7
|
+
- after bulk refactors, large merges, or importing existing code
|
|
8
|
+
- user asks to reconcile spec and code
|
|
9
|
+
- after autonomous code changes that may have left spec out of date
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Mission
|
|
13
|
+
|
|
14
|
+
Resolve drift between spec and code by running the sync protocol, presenting each drift item to the user with context, and applying only user-confirmed fixes so that spec and code match.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Pre-requisites
|
|
19
|
+
|
|
20
|
+
- **prov CLI** with `prov sync` and `prov reconcile` (and patch subcommands: `mark-implemented`, `remove-ref`, `update-ref`, `remove-backlink`). If prov is not available, document that drift resolution was skipped.
|
|
21
|
+
- **Spec directory** and **codebase** in the same repo (or paths known).
|
|
22
|
+
- **Read access** to spec files and code; **write access** to spec files (and optionally code for removing backlinks) after user confirms.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Instructions
|
|
27
|
+
|
|
28
|
+
### Step 1 — Run the drift report
|
|
29
|
+
|
|
30
|
+
Run `prov sync <path>` (e.g. `prov sync src/`) or `prov reconcile <path>` for read-only. Read the full output. Identify each reported item by type (silent implementation, phantom slug, dead ref). See Reference → What drift is.
|
|
31
|
+
|
|
32
|
+
### Step 2 — Present each item to the user
|
|
33
|
+
|
|
34
|
+
For each drift item: state type, slug, and location (file, line or path). State what the spec currently says vs what the code currently does. Offer the resolution options from Reference → Resolution by type. Ask: "What should I do?" Do not apply any fix until the user answers. Use the example presentation format in Reference if helpful.
|
|
35
|
+
|
|
36
|
+
### Step 3 — Apply only confirmed fixes
|
|
37
|
+
|
|
38
|
+
Use the exact commands in Reference → Patch commands. For silent implementation: `mark-implemented` or `remove-backlink`. For phantom slug: add entry via request flow or `remove-backlink`. For dead ref: `update-ref` or `remove-ref` (and consider `[planned]` or removing the entry). Only after user confirms each item.
|
|
39
|
+
|
|
40
|
+
### Step 4 — Validate and commit
|
|
41
|
+
|
|
42
|
+
Run `prov validate` (zero errors). Run `prov diff`. Commit spec (and any code changes) with a message such as `spec: reconcile src/<path>`.
|
|
43
|
+
|
|
44
|
+
### Step 5 — After autonomous code changes
|
|
45
|
+
|
|
46
|
+
When the agent made code changes without the normal request flow (e.g. bulk refactor, automated migration), run `prov sync src/` before committing and include a short drift summary in the PR description. See Reference → After autonomous code changes.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Reference
|
|
51
|
+
|
|
52
|
+
### What drift is
|
|
53
|
+
|
|
54
|
+
Drift is a gap between what the spec says and what the code does. Three types:
|
|
55
|
+
|
|
56
|
+
| Type | Description | Detected by |
|
|
57
|
+
|------|-------------|-------------|
|
|
58
|
+
| **Silent implementation** | `[planned]` entry but code already has `spec:` backlink | `prov sync` |
|
|
59
|
+
| **Phantom slug** | `spec:` in code references a slug with no spec entry | `prov sync` |
|
|
60
|
+
| **Dead ref** | `~` path in spec no longer exists as a file or directory | `prov sync` |
|
|
61
|
+
|
|
62
|
+
### Example presentation to the user
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
SILENT IMPLEMENTATION: session-expiry
|
|
66
|
+
Spec says: [planned]
|
|
67
|
+
Code has: # spec: session-expiry in src/middleware/session.py:44
|
|
68
|
+
|
|
69
|
+
Options:
|
|
70
|
+
A. Mark as implemented — remove [planned], the code ref counts
|
|
71
|
+
B. Remove the backlink — code shouldn't claim to implement this yet
|
|
72
|
+
C. Skip — leave it as-is for now
|
|
73
|
+
|
|
74
|
+
What should I do?
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Patch commands (apply only after user confirms)
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Silent implementation → mark as implemented
|
|
81
|
+
prov sync mark-implemented <slug>
|
|
82
|
+
|
|
83
|
+
# Phantom slug → remove the backlink (if the slug shouldn't exist)
|
|
84
|
+
prov sync remove-backlink <file> <line> <slug>
|
|
85
|
+
# or → add the missing spec entry via request flow (if the code is correct)
|
|
86
|
+
|
|
87
|
+
# Dead ref → remove the stale path
|
|
88
|
+
prov sync remove-ref <slug> <ref>
|
|
89
|
+
# or → update to the new path
|
|
90
|
+
prov sync update-ref <slug> <old-path> <new-path>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Resolution decisions by drift type
|
|
94
|
+
|
|
95
|
+
**Silent implementation** — Spec says `[planned]` but the code already implements it.
|
|
96
|
+
|
|
97
|
+
- **Mark implemented** (`prov sync mark-implemented <slug>`): The implementation is correct and complete. Remove `[planned]`, add `~` ref.
|
|
98
|
+
- **Remove backlink** (`prov sync remove-backlink ...`): The code should not claim to implement this yet. The spec's `[planned]` is correct.
|
|
99
|
+
|
|
100
|
+
**Phantom slug** — Code has `# spec: some-slug` but `some-slug` doesn't exist in the spec.
|
|
101
|
+
|
|
102
|
+
- **Add the spec entry**: The code is right; the spec is missing the entry. Go through request flow Phase 3 → 4. Use provenance `> code: <file:line> — phantom slug, prov sync; user confirmed spec entry` and `! statement inferred from implementation — user confirmed after sync`. See spec-entry-format for provenance source types.
|
|
103
|
+
- **Remove the backlink**: The `spec:` comment is wrong or outdated.
|
|
104
|
+
|
|
105
|
+
**Dead ref** — A `~` path in the spec no longer exists.
|
|
106
|
+
|
|
107
|
+
- **Update the ref** (`prov sync update-ref ...`): The file moved or was renamed. Update to the new path.
|
|
108
|
+
- **Remove the ref** (`prov sync remove-ref ...`): The code was deleted. The implementation is gone; the entry may need `[planned]` restored or be removed entirely.
|
|
109
|
+
|
|
110
|
+
### After autonomous code changes
|
|
111
|
+
|
|
112
|
+
When the agent has made code changes without going through the normal request flow (e.g. bulk refactor, automated migration), always run reconcile before committing:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
prov sync src/ # full drift report
|
|
116
|
+
prov validate # confirm zero errors
|
|
117
|
+
prov diff # review spec changes
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Include the drift summary in the PR description so the human reviewer can see what changed in the spec alongside the code.
|
|
121
|
+
|
|
122
|
+
### Read-only drift check
|
|
123
|
+
|
|
124
|
+
To see drift without applying any fixes:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
prov reconcile src/ # full read-only report
|
|
128
|
+
prov reconcile src/ --since HEAD # since last commit (if supported)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Output sections: PHANTOM SLUGS, SILENT IMPLEMENTATIONS, DEAD REFS, CLEAN (if none).
|
|
132
|
+
|
|
133
|
+
### Provenance for entries added from code
|
|
134
|
+
|
|
135
|
+
When adding a spec entry for a phantom slug (code has `spec:` but no entry), the entry is code-derived:
|
|
136
|
+
|
|
137
|
+
- **Provenance**: `> code: <file:line> — phantom slug, prov sync; user confirmed spec entry`
|
|
138
|
+
- **Assumption**: `! statement inferred from implementation — user confirmed after sync`
|
|
139
|
+
- Always pair `code:` provenance with `!` until the user explicitly confirms the statement reflects their intent.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Error Handling
|
|
144
|
+
|
|
145
|
+
| If this happens | Do this |
|
|
146
|
+
|-----------------|--------|
|
|
147
|
+
| **Silent implementation** — spec has `[planned]` but code has `spec:` | Present options: A. Mark implemented (update spec, add `~`). B. Remove backlink (code shouldn't claim it yet). C. Skip. Do not choose for the user. |
|
|
148
|
+
| **Phantom slug** — `spec:` in code but no spec entry | Present options: A. Add the spec entry (via request flow). B. Remove the backlink. Do not add an entry without user confirmation. |
|
|
149
|
+
| **Dead ref** — `~` path in spec does not exist | Present options: A. Update ref to new path. B. Remove ref (and possibly set entry back to `[planned]` or remove entry). Do not leave a `~` pointing at a missing file. |
|
|
150
|
+
| User says "skip" or "leave it for now" for an item | Do not apply any fix for that item. Move to the next item. You may note in the commit message that some drift was left unresolved. |
|
|
151
|
+
| `prov sync` or `prov reconcile` is not available | Do not invent patch commands. Tell the user that drift was detected but prov sync is required to fix it; list the drift items you can infer from grep/code inspection if possible. |
|
|
152
|
+
| After applying fixes, `prov validate` still reports errors | Fix the new errors (e.g. duplicate slug, missing `>`, dangling ref). Do not commit until validate passes. |
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-entry-format
|
|
3
|
+
version: "1.0"
|
|
4
|
+
description: "Apply the correct spec entry format: node types, sigils, provenance, backlinks, and commit messages. Use when writing or editing spec files, adding or updating ~ code refs or spec: backlinks, reading an unfamiliar spec entry, or checking commit or entry format."
|
|
5
|
+
triggers:
|
|
6
|
+
- writing or editing spec files
|
|
7
|
+
- adding or updating ~ code refs or spec: backlinks
|
|
8
|
+
- reading an unfamiliar spec entry
|
|
9
|
+
- checking commit or entry format
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Mission
|
|
13
|
+
|
|
14
|
+
Apply the correct spec entry format (node types, sigils, invariants, backlinks, commit messages) so the parser and grep-based retrieval work and the spec stays valid.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Pre-requisites
|
|
19
|
+
|
|
20
|
+
- **Spec directory** present: `prov/`, `spec/`, or `specs/`.
|
|
21
|
+
- **grep** (or equivalent) for slug checks and pattern search.
|
|
22
|
+
- **prov CLI** (optional): `prov check-slug`, `prov validate`. If absent, use `grep -r "^<slug>:" spec/` for slug availability.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Instructions
|
|
27
|
+
|
|
28
|
+
### Step 1 — Before writing any entry: check slug
|
|
29
|
+
|
|
30
|
+
Run `prov check-slug <proposed-slug>` or `grep -r "^<proposed-slug>:" spec/`. If the slug exists, pick a different one or edit the existing entry. Slugs: kebab-case, 2–4 words, describe **behavior** not domain (see Reference → Slug rules).
|
|
31
|
+
|
|
32
|
+
### Step 2 — Use the correct node type and structure
|
|
33
|
+
|
|
34
|
+
Use **Requirement**, **Constraint**, or **Question** format from Reference. Each has a statement line and sub-lines with ` >`, ` !`, ` @`, ` ?`, ` ~` (each on its own line, exactly 2-space indent).
|
|
35
|
+
|
|
36
|
+
### Step 3 — Enforce file invariants
|
|
37
|
+
|
|
38
|
+
Every primary entry at **column 0**. Every sub-line **exactly 2 spaces** (not 4, not tab). Sigils only on their own sub-lines; never inline in the statement. One statement line per entry. See Reference → File format invariants.
|
|
39
|
+
|
|
40
|
+
### Step 4 — Add code backlinks when implementing
|
|
41
|
+
|
|
42
|
+
In code, at the top of each function/class/block that implements a spec entry: `# spec: slug` (or `// spec: slug`). Multiple slugs: `# spec: slug-a, C:slug-b`. One comment per logical block. See Reference → Code backlinks.
|
|
43
|
+
|
|
44
|
+
### Step 5 — Use the correct commit format
|
|
45
|
+
|
|
46
|
+
See Reference → Commit format. Spec-only vs code+spec; always include the `spec: ...` line when code and spec change together.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Reference
|
|
51
|
+
|
|
52
|
+
### Reading an entry — anatomy
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
session-expiry: Sessions expire after 30 days of inactivity.
|
|
56
|
+
> inferred: user said "standard session timeout, nothing crazy" — interpreted as 30 days
|
|
57
|
+
! assumed 30 days — "nothing crazy" is unconfirmed
|
|
58
|
+
@ C:jwt-stateless
|
|
59
|
+
~ src/middleware/session.py:44
|
|
60
|
+
~ src/middleware/session.py:101
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
| Part | Meaning |
|
|
64
|
+
|------|---------|
|
|
65
|
+
| `session-expiry` | Slug — permanent, globally unique. Used in `spec:` backlinks in code. |
|
|
66
|
+
| Statement | What the system does. Current state only. |
|
|
67
|
+
| `>` | Provenance — use source prefix: user, inferred, code, regulatory, derived. See Provenance source types below. |
|
|
68
|
+
| `!` | Agent filled this in; user has not confirmed it. |
|
|
69
|
+
| `@` | This entry depends on another slug. |
|
|
70
|
+
| `~` | Code implementing this entry. One line per ref. |
|
|
71
|
+
| `[planned]` | Not yet implemented. No `~` lines. Remove when implemented. |
|
|
72
|
+
|
|
73
|
+
### Provenance source types
|
|
74
|
+
|
|
75
|
+
Every `>` line must identify where the entry came from. Use exactly one of these — do not invent new types.
|
|
76
|
+
|
|
77
|
+
| Type | Format | When used | `!` required? |
|
|
78
|
+
|------|--------|-----------|---------------|
|
|
79
|
+
| user | `> user: "exact words"` | Direct quote from user | No |
|
|
80
|
+
| inferred | `> inferred: reasoning` | Agent interpretation of user intent | Yes |
|
|
81
|
+
| code | `> code: path — context` | Discovered during sync, drift, reverse-engineering | Yes |
|
|
82
|
+
| regulatory | `> regulatory: source — citation` | Legal, compliance, platform requirement | No |
|
|
83
|
+
| derived | `> derived: slug — reasoning` | Logical consequence of another entry | No |
|
|
84
|
+
|
|
85
|
+
For Q nodes: `> blocks: slug` remains valid.
|
|
86
|
+
|
|
87
|
+
Examples:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
> user: "we'll just do Google login for now"
|
|
91
|
+
|
|
92
|
+
> inferred: user said "nothing crazy" for timeout — interpreted as 30 days
|
|
93
|
+
! assumed 30 days — not confirmed
|
|
94
|
+
|
|
95
|
+
> code: src/auth/google.py — phantom slug, prov sync 2026-03-10
|
|
96
|
+
! statement inferred from implementation — user confirmed after sync
|
|
97
|
+
|
|
98
|
+
> regulatory: GDPR Article 17 — right to erasure within 30 days
|
|
99
|
+
|
|
100
|
+
> derived: C:jwt-stateless — stateless tokens can't maintain server-side revocation list
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Node types at column 0
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
slug: requirement — user-observable behavior
|
|
107
|
+
C:slug: constraint — non-negotiable rule governing a domain
|
|
108
|
+
Q:slug: question — unresolved decision blocking implementation
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Sub-lines always 2-space indent. Never 4 or tab.
|
|
112
|
+
|
|
113
|
+
### Slug rules
|
|
114
|
+
|
|
115
|
+
- kebab-case, 2–4 words, describe **behavior** not domain.
|
|
116
|
+
- Good: `session-expiry`, `guest-access`. Bad: `auth-session` (domain prefix), `limit` (too vague).
|
|
117
|
+
|
|
118
|
+
### Requirement format
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
slug: Statement describing user-observable behavior. [planned if not yet coded]
|
|
122
|
+
> user: "exact quote" | inferred: reasoning | code: path — context | regulatory: source — citation | derived: slug — reasoning
|
|
123
|
+
! assumption (required for inferred and code; only when agent filled a gap)
|
|
124
|
+
@ dependency-slug (if this entry depends on another slug)
|
|
125
|
+
? Q:blocking-question (if blocked by an open question)
|
|
126
|
+
~ src/path/to/file.py:line (one per line, only when implemented)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Constraint format
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
C:slug: Non-negotiable rule statement.
|
|
133
|
+
> user: "exact quote" or regulatory: source — citation
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Open question format
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
Q:slug: Question that must be resolved before implementation?
|
|
140
|
+
> blocks: slug-of-the-requirement-it-blocks
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### File format invariants — never violate
|
|
144
|
+
|
|
145
|
+
1. Every primary entry starts at **column 0**. No leading spaces.
|
|
146
|
+
2. Every sub-line is indented **exactly 2 spaces**. Not 4. Not a tab.
|
|
147
|
+
3. The `~` sigil appears only on its own sub-line. Never inline in the statement.
|
|
148
|
+
4. Each entry has one statement line (the line with `slug: statement`). Multi-sentence statements on that one line are fine.
|
|
149
|
+
|
|
150
|
+
Violating these breaks the parser and grep-based retrieval.
|
|
151
|
+
|
|
152
|
+
### Complete domain file example
|
|
153
|
+
|
|
154
|
+
```markdown
|
|
155
|
+
# Auth
|
|
156
|
+
|
|
157
|
+
> OAuth-based auth and stateless JWT sessions. Two roles: admin/member.
|
|
158
|
+
|
|
159
|
+
## Constraints
|
|
160
|
+
|
|
161
|
+
C:oauth-only: OAuth only — no email/password.
|
|
162
|
+
> user: "I don't want to deal with password resets"
|
|
163
|
+
|
|
164
|
+
C:jwt-stateless: Sessions are stateless JWT — no server-side session store.
|
|
165
|
+
> user: "I don't want to manage session infrastructure"
|
|
166
|
+
|
|
167
|
+
## Requirements
|
|
168
|
+
|
|
169
|
+
google-login: Users authenticate via Google OAuth.
|
|
170
|
+
> user: "we'll just do Google login for now"
|
|
171
|
+
@ C:oauth-only
|
|
172
|
+
~ src/api/auth/google.py
|
|
173
|
+
~ src/api/auth/callback.py
|
|
174
|
+
|
|
175
|
+
session-expiry: Sessions expire after 30 days of inactivity.
|
|
176
|
+
> inferred: user said "standard session timeout, nothing crazy" — interpreted as 30 days
|
|
177
|
+
! assumed 30 days — "nothing crazy" is unconfirmed
|
|
178
|
+
@ C:jwt-stateless
|
|
179
|
+
~ src/middleware/session.py:44
|
|
180
|
+
|
|
181
|
+
admin-revoke: Admins can revoke any user session immediately. [planned]
|
|
182
|
+
> user: "need a kill switch for bad actors"
|
|
183
|
+
! assumed token blocklist approach — not stated by user
|
|
184
|
+
@ session-expiry
|
|
185
|
+
? Q:admin-revoke-scope
|
|
186
|
+
|
|
187
|
+
## Open Questions
|
|
188
|
+
|
|
189
|
+
Q:admin-revoke-scope: Does admin-revoke apply to one session or all sessions?
|
|
190
|
+
> blocks: admin-revoke
|
|
191
|
+
|
|
192
|
+
## Out of scope
|
|
193
|
+
|
|
194
|
+
MFA, SSO/SAML.
|
|
195
|
+
|
|
196
|
+
## Refs
|
|
197
|
+
|
|
198
|
+
~ src/api/auth/
|
|
199
|
+
~ src/middleware/session.py
|
|
200
|
+
~ src/models/user.py
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Code backlinks
|
|
204
|
+
|
|
205
|
+
Every function or class that implements a spec entry carries a `spec:` comment. One per logical block; multiple slugs comma-separated. Place at top of block.
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
# spec: session-expiry
|
|
209
|
+
def refresh_session(token: str) -> Session:
|
|
210
|
+
|
|
211
|
+
# spec: billing-session-sync, C:usage-cap
|
|
212
|
+
class PlanLimitMiddleware:
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// spec: admin-revoke
|
|
217
|
+
async function revokeSession(userId: string): Promise<void>;
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### What the spec never contains
|
|
221
|
+
|
|
222
|
+
Do not write: "Previously this was X", "Changed from X to Y", "Deprecated — use other-slug", "We chose JWT because...", or any description of how the system got to its current state. No entry without a `>` line. No implementation detail the user did not specify without a `!` line. The spec is always current state only.
|
|
223
|
+
|
|
224
|
+
### Commit format
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# Spec-only changes
|
|
228
|
+
spec(auth): add session-expiry, C:jwt-stateless
|
|
229
|
+
spec(auth): implement admin-revoke
|
|
230
|
+
spec(auth): close Q:admin-revoke-scope
|
|
231
|
+
spec(billing): update plan-limits statement
|
|
232
|
+
spec: reconcile src/api/
|
|
233
|
+
|
|
234
|
+
# Code + spec in same commit
|
|
235
|
+
feat(auth): implement session expiry
|
|
236
|
+
spec: implement session-expiry, add ! assumption for 30-day value
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Grep quick reference
|
|
240
|
+
|
|
241
|
+
Replace `spec/` with `prov/` or `specs/` if that is your spec root.
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
# Orient
|
|
245
|
+
grep -rh "^>" spec/*.md spec/*/*.md 2>/dev/null
|
|
246
|
+
grep -r "^Q:" spec/
|
|
247
|
+
grep -r "\[planned\]" spec/
|
|
248
|
+
grep -r "^ !" spec/
|
|
249
|
+
grep -r "^C:" spec/
|
|
250
|
+
|
|
251
|
+
# What governs this path?
|
|
252
|
+
grep -r "~src/path/to/file" spec/
|
|
253
|
+
grep -r "~src/path/" spec/
|
|
254
|
+
|
|
255
|
+
# Find by slug
|
|
256
|
+
grep -r "^session-expiry:" spec/
|
|
257
|
+
grep -A 25 "^session-expiry:" spec/
|
|
258
|
+
|
|
259
|
+
# Dependents and implementers
|
|
260
|
+
grep -r "^ @ session-expiry" spec/
|
|
261
|
+
grep -rn "spec: session-expiry" src/
|
|
262
|
+
|
|
263
|
+
# Keyword search
|
|
264
|
+
grep -rEi "session|auth|timeout" spec/
|
|
265
|
+
|
|
266
|
+
# Slug availability (before writing)
|
|
267
|
+
grep -r "^my-new-slug:" spec/
|
|
268
|
+
|
|
269
|
+
# Duplicate check
|
|
270
|
+
grep -rhE "^[a-z][a-z0-9-]*:|^C:|^Q:" spec/ | cut -d: -f1,2 | sort | uniq -d
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### prov CLI — quick reference
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
prov orient # session start
|
|
277
|
+
prov scope <path> # what governs this file/dir
|
|
278
|
+
prov context <slug> # full entry + deps
|
|
279
|
+
prov impact <slug> # blast radius
|
|
280
|
+
prov find <keywords> # search entries
|
|
281
|
+
prov domain <name> # full domain
|
|
282
|
+
prov check-slug <slug> # slug availability
|
|
283
|
+
prov validate # before every commit
|
|
284
|
+
prov diff [ref] # semantic change manifest
|
|
285
|
+
prov reconcile <path> # drift detection (read-only)
|
|
286
|
+
prov sync [path] # interactive drift resolution
|
|
287
|
+
prov rebuild # regenerate optional .spec/ cache
|
|
288
|
+
prov init # scaffold CONTEXT.md
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Error Handling
|
|
294
|
+
|
|
295
|
+
| If this happens | Do this |
|
|
296
|
+
|-----------------|--------|
|
|
297
|
+
| `prov validate` reports "ghost-scope" or "no > line" | Add a ` > ` line with appropriate source prefix (user, inferred, code, regulatory, derived). Do not commit without it. |
|
|
298
|
+
| `prov validate` reports "dead-ref" | Remove the `~` line or update the path to the real file. Do not leave a `~` pointing to a missing path. |
|
|
299
|
+
| `prov validate` reports "phantom-slug" | Either add the missing spec entry for that slug or remove the `spec: slug` backlink from code. Do not leave a backlink with no entry. |
|
|
300
|
+
| You accidentally used 4 spaces or tab for sub-lines | Change to exactly 2 spaces. Parser and grep rely on 2-space indent. |
|
|
301
|
+
| You put `~` or `@` inline in the statement | Move them to separate sub-lines with 2-space indent. One ref per line. |
|
|
302
|
+
| Slug already exists elsewhere | Choose a different slug or update the existing entry; do not create a duplicate. Use `prov check-slug` or grep before writing. |
|