owfadev 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.owfa/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.1
1
+ 0.4.2
@@ -1,7 +1,7 @@
1
1
  # Action discipline: path zones × action tiers
2
2
 
3
- > The semantic shape of permissions: this table does not rely on code for "enforcement", but deterministic structural operations are entrusted to scripts (`.owfa/scripts/owfa_kernel.py`: compliance / dependencies / injection / registry / copy sync; `.owfa/scripts/pipeline.py`: index / tags rebuild, hot / log rolling, post-write self-attestation), while semantic judgment is entrusted to the LLM; the agent consults this table before acting, and check audits afterwards from script output and git traces.
4
- > Four execution principles: deterministic structural operations go through scripts, semantic judgment through the LLM; rules spell out in plain text "how to do" rather than "what it is"; if one read suffices, there is no second scan (call frugality); write commands must close with `pipeline.py verify` self-attestation (the minimal attester form: the LLM executes, the script attests).
3
+ > The semantic shape of permissions: this table does not rely on code for "enforcement", but deterministic structural operations are entrusted to scripts (`.owfa/scripts/owfa_kernel.py`: compliance / dependencies / injection / registry / copy sync; the suite-provided pipeline, `.owfa/plugins/domains/personal/pipeline.py` (deprecated host copy `.owfa/scripts/pipeline.py` until 0.5.0): index / tags rebuild, hot / log rolling, post-write self-attestation), while semantic judgment is entrusted to the LLM; the agent consults this table before acting, and check audits afterwards from script output and git traces.
4
+ > Four execution principles: deterministic structural operations go through scripts, semantic judgment through the LLM; rules spell out in plain text "how to do" rather than "what it is"; if one read suffices, there is no second scan (call frugality); write commands must close with the pipeline's `verify` self-attestation (the minimal attester form: the LLM executes, the script attests; the pipeline is suite machinery — with the personal suite since 0.1.1).
5
5
 
6
6
  ## Path zones
7
7
 
@@ -17,7 +17,7 @@
17
17
 
18
18
  | Tier | Typical actions | How executed |
19
19
  |---|---|---|
20
- | Mechanical-auto | index / tags / registry rebuild, injection-region rebuild, hot window eviction, log archival routing, hash recalculation, query log lines, command copy sync, post-write self-attestation | Execute directly (whatever scripts can do goes through scripts: `owfa_kernel.py` and `pipeline.py`), no asking |
20
+ | Mechanical-auto | index / tags / registry rebuild, injection-region rebuild, hot window eviction, log archival routing, hash recalculation, query log lines, command copy sync, post-write self-attestation | Execute directly (whatever scripts can do goes through scripts: `owfa_kernel.py` (framework) and the suite pipeline), no asking |
21
21
  | Mechanical-confirm | tag merges (batch edits to plugin fields), reserved-field migration, tmp over-age cleanup (present list, delete after confirmation) | Present the list, execute after confirmation |
22
22
  | Semantic-report | note-merge suggestions, near-duplicate alerts, staleness judgments on proxy descriptions | Report the differences; the human decides |
23
23
  | Always-human | deletion, history rewriting, changes to existing `vault/` files, rewriting note bodies | Commands never execute these; ghost-writing on explicit user instruction must leave a log trace |
@@ -39,4 +39,4 @@ The criterion: touching "plugin-owned fields or regenerable pages" → mechanica
39
39
  - **hot**: ≤25 entries, <5 days, ≤200 characters per entry. Write hot entries via `pipeline.py hot <type> "<one-liner>"`—out-of-window entries are evicted and over-long entries truncated automatically before writing
40
40
  - **Index / registry**: on deviation from reality → rebuild directly inside check (`pipeline.py index` / `tags`; `owfa_kernel.py all`), no asking
41
41
  - **Vocabulary**: before writing tags, map / save first reads `wiki/tags.md` (the derived zone is the vocabulary), preferring to reuse existing words; near-duplicate merging is a mechanical-confirm item
42
- - **Parameter ownership**: mechanical parameters such as rolling windows defer to the `pipeline.py` source (the script source is the rule list), while plugin PLUGIN.md files keep the semantic explanations—commands and docs do not re-copy the numbers
42
+ - **Parameter ownership**: mechanical parameters such as rolling windows defer to the pipeline source (suite package root) (the script source is the rule list), while plugin PLUGIN.md files keep the semantic explanations—commands and docs do not re-copy the numbers
@@ -1,6 +1,12 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
- """Derived-layer post-write pipeline: index / tags / hot / log / verify.
3
+ """DEPRECATED HOST COPY — retires in 0.5.0. Since suite 0.1.1 the pipeline ships with
4
+ the personal suite at the package root (instance path:
5
+ .owfa/plugins/domains/personal/pipeline.py); the kernel never calls it. This
6
+ framework-tree copy is a one-version compatibility shim for reverse-order upgrades
7
+ (framework before suite). Do not edit here — source of truth: owfadev/owfa-personal.
8
+
9
+ Derived-layer post-write pipeline: index / tags / hot / log / verify.
4
10
 
5
11
  Positioning (.owfa/protocol/actions.md execution principles): deterministic structural
6
12
  operations go to this script; semantic judgment goes to the LLM. Rebuild and rolling
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "owfadev",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "OWFA — One Workspace For All (agents). Install, initialize and upgrade the owfa agent workspace framework.",
5
5
  "keywords": [
6
6
  "owfa",
@@ -1,13 +1,13 @@
1
1
  schema_version: 1
2
2
  id: personal
3
3
  kind: suite
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  compat: ">= 0.4"
6
6
  members: [calendar, cron, device, domain, hot, index, instance-git, language, link, log, mapping, notes, sessions, structure, tag, tmp, todo, trust, user-profile, vault, wiki]
7
7
  depends: [framework]
8
8
  skeleton: [vault/, wiki/notes/, wiki/sessions/, wiki/vault/]
9
9
  uninstall:
10
- anchors: [wiki/profile.md, wiki/language.md, wiki/calendar.md, wiki/todo.md, wiki/cron/]
10
+ anchors: [wiki/profile.md, wiki/language.md, wiki/structure.md, wiki/calendar.md, wiki/todo.md, wiki/cron/]
11
11
  retains: [vault/, wiki/]
12
12
  credentials: []
13
13
  bridges: []
@@ -32,5 +32,6 @@ A derivation-destination bridge governing schedules: domain plugins one-way deri
32
32
  ## Changelog
33
33
 
34
34
  - 0.5 2026-11-09: inject line rewritten to routing-pointer density (issue #49 phase 1, relieves the #48 budget): path + read/write trigger + the one easy-to-break invariant + pointer here; the dropped detail already lives in this file / the manifest
35
- - 0.4 (2026-10-06) inject line: sections lost to the kernel comment-strip clip restored (quoted values are now protected), tightened for budget headroom — issue #12 post-migration nit- 0.3 (2026-10-06) inject line compressed to pointer density (issue #12 layer discipline) — procedural detail lives in usage / PLUGIN.md / skills- 0.2 2026-10-02: global-domain batch two — established the on-demand bridge as the derivation destination; domain-plugin self-descriptions retained with a pointer
35
+ - 0.4 (2026-10-06) inject line: sections lost to the kernel comment-strip clip restored (quoted values are now protected), tightened for budget headroom — issue #12 post-migration nit
36
+ - 0.3 (2026-10-06) inject line compressed to pointer density (issue #12 layer discipline) — procedural detail lives in usage / PLUGIN.md / skills- 0.2 2026-10-02: global-domain batch two — established the on-demand bridge as the derivation destination; domain-plugin self-descriptions retained with a pointer
36
37
  - 0.1 2026-09-19: established — month-page two-section scheme, the open source model, the freezing regime; lark-calendar as the first source adapter
@@ -20,7 +20,7 @@ Read: registry (`.owfa/protocol/registry.yaml`, field and value-set anchor), tag
20
20
  2. Read the target asset in vault/
21
21
  3. Assemble the proxy-page draft per the write-side contracts in the injection region (mapping mirror and registration fields, trust generated, tag labeling); **present the mapping preview** (path / hash / description / tags) and wait for user confirmation
22
22
  4. After confirmation, write the proxy page
23
- 5. **Post-write pipeline** (deterministic, mechanical and automatic, no prompting): execute each plugin's write calls in injection-region order, then finish with `python .owfa/scripts/pipeline.py verify` (post-write self-verification; on failure, go back and fix); then commit per the commit discipline (`映射: <asset name>`, see the vocabulary in `.owfa/protocol/actions.md`)
23
+ 5. **Post-write pipeline** (deterministic, mechanical and automatic, no prompting): execute each plugin's write calls in injection-region order, then finish with `python .owfa/plugins/domains/personal/pipeline.py verify` (post-write self-verification; on failure, go back and fix); then commit per the commit discipline (`映射: <asset name>`, see the vocabulary in `.owfa/protocol/actions.md`)
24
24
  6. Report: path / hash / description / tags
25
25
 
26
26
  ## Prohibitions
@@ -59,14 +59,14 @@ Output language takes the default key of the language declaration page `wiki/lan
59
59
  <!-- /usage:tag -->
60
60
 
61
61
  <!-- usage:index -->
62
- - Post-write rebuild (mechanical, automatic): `python .owfa/scripts/pipeline.py index` (index — overflow-offloading scheme, including deletion of obsolete old indexes after merge-back) and the same script's `tags` (tag reverse index); LLMs never hand-write indexes
62
+ - Post-write rebuild (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py index` (index — overflow-offloading scheme, including deletion of obsolete old indexes after merge-back) and the same script's `tags` (tag reverse index); LLMs never hand-write indexes
63
63
  <!-- /usage:index -->
64
64
 
65
65
  <!-- usage:hot -->
66
- - Writing entries (mechanical, automatic): `python .owfa/scripts/pipeline.py hot <type> "<wikilink + one-sentence essence>"` (type value set same as log, see the log block of the AGENTS injection region); window eviction and truncation are performed by the script
66
+ - Writing entries (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py hot <type> "<wikilink + one-sentence essence>"` (type value set same as log, see the log block of the AGENTS injection region); window eviction and truncation are performed by the script
67
67
  <!-- /usage:hot -->
68
68
 
69
69
  <!-- usage:log -->
70
- - Writing lines (mechanical, automatic): `python .owfa/scripts/pipeline.py log <type> "<one sentence>" [--domain <domain>]` (type value set in the log block of the AGENTS injection region; domain tag = domain-plugin name such as bb/lark/vault, mandatory for in-domain transactions, omitted for framework and native transactions); rolling window and archiving are performed by the script
70
+ - Writing lines (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py log <type> "<one sentence>" [--domain <domain>]` (type value set in the log block of the AGENTS injection region; domain tag = domain-plugin name such as bb/lark/vault, mandatory for in-domain transactions, omitted for framework and native transactions); rolling window and archiving are performed by the script
71
71
  <!-- /usage:log -->
72
72
  <!-- cmd-inject:end -->
@@ -20,7 +20,7 @@ Read: registry (`.owfa/protocol/registry.yaml`, field and value-set anchor), tru
20
20
  2. **Judge signals** (criteria in the user-profile usage block below): if this session's and recent observations do not qualify, report and exit — never force a write
21
21
  3. Assemble the update: incremental assertions (new value replaces old + body trace) or construction / consolidation (whole-page rewrite) — construction and consolidation **present a profile preview** (assertions / evidence / layers) and wait for user confirmation
22
22
  4. Write the page (layered placement and stale_after renewal per the usage block below)
23
- 5. **Post-write pipeline** (deterministic, mechanical and automatic, no prompting): execute each plugin's write calls in injection-region order, then finish with `python .owfa/scripts/pipeline.py verify` (post-write self-verification; on failure, go back and fix); then commit per the commit discipline (`画像: <one line>`, see the vocabulary in `.owfa/protocol/actions.md`)
23
+ 5. **Post-write pipeline** (deterministic, mechanical and automatic, no prompting): execute each plugin's write calls in injection-region order, then finish with `python .owfa/plugins/domains/personal/pipeline.py verify` (post-write self-verification; on failure, go back and fix); then commit per the commit discipline (`画像: <one line>`, see the vocabulary in `.owfa/protocol/actions.md`)
24
24
  6. Report: what was updated / the evidence chain / which layer it landed in
25
25
 
26
26
  ## Prohibitions
@@ -62,14 +62,14 @@ Output language takes the default key of the language declaration page `wiki/lan
62
62
  <!-- /usage:trust -->
63
63
 
64
64
  <!-- usage:index -->
65
- - Post-write rebuild (mechanical, automatic): `python .owfa/scripts/pipeline.py index` (index — overflow-offloading scheme, including deletion of obsolete old indexes after merge-back) and the same script's `tags` (tag reverse index); LLMs never hand-write indexes
65
+ - Post-write rebuild (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py index` (index — overflow-offloading scheme, including deletion of obsolete old indexes after merge-back) and the same script's `tags` (tag reverse index); LLMs never hand-write indexes
66
66
  <!-- /usage:index -->
67
67
 
68
68
  <!-- usage:hot -->
69
- - Writing entries (mechanical, automatic): `python .owfa/scripts/pipeline.py hot <type> "<wikilink + one-sentence essence>"` (type value set same as log, see the log block of the AGENTS injection region); window eviction and truncation are performed by the script
69
+ - Writing entries (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py hot <type> "<wikilink + one-sentence essence>"` (type value set same as log, see the log block of the AGENTS injection region); window eviction and truncation are performed by the script
70
70
  <!-- /usage:hot -->
71
71
 
72
72
  <!-- usage:log -->
73
- - Writing lines (mechanical, automatic): `python .owfa/scripts/pipeline.py log <type> "<one sentence>" [--domain <domain>]` (type value set in the log block of the AGENTS injection region; domain tag = domain-plugin name such as bb/lark/vault, mandatory for in-domain transactions, omitted for framework and native transactions); rolling window and archiving are performed by the script
73
+ - Writing lines (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py log <type> "<one sentence>" [--domain <domain>]` (type value set in the log block of the AGENTS injection region; domain tag = domain-plugin name such as bb/lark/vault, mandatory for in-domain transactions, omitted for framework and native transactions); rolling window and archiving are performed by the script
74
74
  <!-- /usage:log -->
75
75
  <!-- cmd-inject:end -->
@@ -33,7 +33,7 @@ type / status value sets defer to the registry (a one-time read anchor; do not r
33
33
  4. Rewrite in declarative present tense: write knowledge, not dialogue
34
34
  5. Create the page per the write-side contracts in the injection region (notes / sessions destinations and shapes, trust generated, tag labeling); the session type goes to the long-sessions section
35
35
  6. Write wiki pages mentioned in the conversation into related with wikilinks
36
- 7. **Post-write pipeline** (deterministic, mechanical, automatic): execute each plugin's write calls in injection-region order, then finish with `python .owfa/scripts/pipeline.py verify` (post-write self-verification; on failure, go back and fix); then commit per the commit discipline (`保存: <page title>`, see `.owfa/protocol/actions.md`)
36
+ 7. **Post-write pipeline** (deterministic, mechanical, automatic): execute each plugin's write calls in injection-region order, then finish with `python .owfa/plugins/domains/personal/pipeline.py verify` (post-write self-verification; on failure, go back and fix); then commit per the commit discipline (`保存: <page title>`, see `.owfa/protocol/actions.md`)
37
37
  8. Report: `Saved as [[title]] in wiki/notes/` (session type: `... in wiki/sessions/`)
38
38
 
39
39
  ## Long Sessions (session backbone)
@@ -62,7 +62,7 @@ Declarative present tense; output language takes the default key of the language
62
62
 
63
63
  <!-- usage:sessions -->
64
64
  - Landing spot `wiki/sessions/YYYY-MM-DD-<topic>.md` (default naming), type: session, participants required (actor list)
65
- - Backbone page five-section shape: Core Conclusions / Decisions & Rationale / Non-obvious Insights / Open Questions / Related Pages (full-shape sample in the Example section of `.owfa/plugins/sessions/PLUGIN.md`)
65
+ - Backbone page five-section shape: Core Conclusions / Decisions & Rationale / Non-obvious Insights / Open Questions / Related Pages (full-shape sample in the Example section of `.owfa/plugins/domains/personal/sessions/PLUGIN.md`)
66
66
  - Standalone high-value topics promoted to `wiki/notes/` pages, the backbone page keeping a wikilink; dedupe before promotion
67
67
  <!-- /usage:sessions -->
68
68
 
@@ -81,14 +81,14 @@ Declarative present tense; output language takes the default key of the language
81
81
  <!-- /usage:trust -->
82
82
 
83
83
  <!-- usage:index -->
84
- - Post-write rebuild (mechanical, automatic): `python .owfa/scripts/pipeline.py index` (index — overflow-offloading scheme, including deletion of obsolete old indexes after merge-back) and the same script's `tags` (tag reverse index); LLMs never hand-write indexes
84
+ - Post-write rebuild (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py index` (index — overflow-offloading scheme, including deletion of obsolete old indexes after merge-back) and the same script's `tags` (tag reverse index); LLMs never hand-write indexes
85
85
  <!-- /usage:index -->
86
86
 
87
87
  <!-- usage:hot -->
88
- - Writing entries (mechanical, automatic): `python .owfa/scripts/pipeline.py hot <type> "<wikilink + one-sentence essence>"` (type value set same as log, see the log block of the AGENTS injection region); window eviction and truncation are performed by the script
88
+ - Writing entries (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py hot <type> "<wikilink + one-sentence essence>"` (type value set same as log, see the log block of the AGENTS injection region); window eviction and truncation are performed by the script
89
89
  <!-- /usage:hot -->
90
90
 
91
91
  <!-- usage:log -->
92
- - Writing lines (mechanical, automatic): `python .owfa/scripts/pipeline.py log <type> "<one sentence>" [--domain <domain>]` (type value set in the log block of the AGENTS injection region; domain tag = domain-plugin name such as bb/lark/vault, mandatory for in-domain transactions, omitted for framework and native transactions); rolling window and archiving are performed by the script
92
+ - Writing lines (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py log <type> "<one sentence>" [--domain <domain>]` (type value set in the log block of the AGENTS injection region; domain tag = domain-plugin name such as bb/lark/vault, mandatory for in-domain transactions, omitted for framework and native transactions); rolling window and archiving are performed by the script
93
93
  <!-- /usage:log -->
94
94
  <!-- cmd-inject:end -->
@@ -35,5 +35,6 @@
35
35
  ## Changelog
36
36
 
37
37
  - 0.5 2026-11-09: inject line rewritten to routing-pointer density (issue #49 phase 1, relieves the #48 budget): path + read/write trigger + the one easy-to-break invariant + pointer here; the dropped detail already lives in this file / the manifest
38
- - 0.4 (2026-10-06) inject line: sections lost to the kernel comment-strip clip restored (quoted values are now protected), tightened for budget headroom — issue #12 post-migration nit- 0.3 (2026-10-06) inject line compressed to pointer density (issue #12 layer discipline) — procedural detail lives in usage / PLUGIN.md / skills- 0.2 2026-10-04: added the tool-environment summary section — the body's `## Tool Environment` records presence-level info on connectors/runtimes/channels, a cross-device lookup registry, the AGENTS shell pointing to the pages; presence-level granularity, (un)install syncing, no full inventory
38
+ - 0.4 (2026-10-06) inject line: sections lost to the kernel comment-strip clip restored (quoted values are now protected), tightened for budget headroom — issue #12 post-migration nit
39
+ - 0.3 (2026-10-06) inject line compressed to pointer density (issue #12 layer discipline) — procedural detail lives in usage / PLUGIN.md / skills- 0.2 2026-10-04: added the tool-environment summary section — the body's `## Tool Environment` records presence-level info on connectors/runtimes/channels, a cross-device lookup registry, the AGENTS shell pointing to the pages; presence-level granularity, (un)install syncing, no full inventory
39
40
  - 0.1 2026-10-04: established — reusing the notes territory (type: entity suggested), the device block mapping minimal key set, the attached-audit expiry scan (30-day window), expiry entering todo via delegation and confirmation; zero commands; depends wiki
@@ -28,6 +28,7 @@ hot.max_entry_chars: 200 # parameters calibrated against the original reposito
28
28
 
29
29
  ## Changelog
30
30
 
31
+ - 0.11 2026-11-15: pipeline call path relocated to the suite package root (suite 0.1.1)
31
32
  - 0.10 2026-09-23: added the wiki dependency edge — inner-side plugins attach to wiki, aligning with the domain 0.1 declaration; omitted from the 2026-09-22 domain-ization batch
32
33
  - 0.9 2026-09-13: usage's type parameter gained its value-set source — same as log, pointing to the log block of the AGENTS injection region
33
34
  - 0.8 2026-09-13: injection source moved to the manifest — removed Checks, Usage, Inject, Attachments sections, md returned to pure documentation
@@ -1,15 +1,15 @@
1
1
  id: hot
2
2
  schema_version: 1
3
- version: 0.10
3
+ version: 0.11
4
4
  depends:
5
5
  - wiki
6
- updated: 2026-10-06
6
+ updated: 2026-11-15
7
7
  attachment:
8
8
  - "wiki/hot.md — single-file hot cache"
9
9
  fields: {}
10
10
  inject: "Hot cache `wiki/hot.md`: recent-change digest (≤25 entries, <5 days, ≤200 chars per entry); agents read this page first on entering the repository; evict out-of-window entries before writing"
11
11
  usage:
12
- - Writing entries (mechanical, automatic): `python .owfa/scripts/pipeline.py hot <type> "<wikilink + one-sentence essence>"` (type value set same as log, see the log block of the AGENTS injection region); window eviction and truncation are performed by the script
12
+ - Writing entries (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py hot <type> "<wikilink + one-sentence essence>"` (type value set same as log, see the log block of the AGENTS injection region); window eviction and truncation are performed by the script
13
13
  checks:
14
14
  - Window out of bounds (>25 entries / >5 days / >200 chars per entry) → run `pipeline.py hot <type> "<backfill>"` once, or wait for the next write to converge naturally then re-check
15
15
  - Contradiction with log (log has records while hot shows no trace) → warning
@@ -25,6 +25,7 @@
25
25
 
26
26
  ## Changelog
27
27
 
28
+ - 0.15 2026-11-15: pipeline call path relocated to the suite package root (`.owfa/plugins/domains/personal/pipeline.py`) — derived-layer machinery travels with the suite (suite 0.1.1)
28
29
  - 0.14 2026-11-09: inject line rewritten to routing-pointer density (issue #49 phase 1, relieves the #48 budget): path + read/write trigger + the one easy-to-break invariant + pointer here; the dropped detail already lives in this file / the manifest
29
30
  - 0.13 (2026-10-06) inject line compressed to pointer density (issue #12 layer discipline) — procedural detail lives in usage / PLUGIN.md / skills- 0.12 2026-09-23: added the wiki dependency edge — inner-side plugins attach to wiki, aligning with the domain 0.1 declaration; omitted from the 2026-09-22 domain-ization batch
30
31
  - 0.11 2026-09-19: concept-page detection excluded wiki/tmp/ — the temporary zone stays out of indexes and tags, in step with the tmp plugin's establishment
@@ -1,10 +1,10 @@
1
1
  id: index
2
2
  schema_version: 1
3
- version: 0.14
3
+ version: 0.15
4
4
  depends:
5
5
  - tag
6
6
  - wiki
7
- updated: 2026-11-09
7
+ updated: 2026-11-15
8
8
  attachment:
9
9
  - "wiki/index.md — root index (always present; carries format_version; directly lists reachable pages)"
10
10
  - "Per-directory index.md — born of the overflow-offloading scheme (split out when a list overflows the window, disappearing on rebuild once merged back into the parent)"
@@ -12,7 +12,7 @@ attachment:
12
12
  fields: {}
13
13
  inject: "Index `wiki/index.md` (+ subtree index.md on overflow): derived, never hand-edited — rebuild via `pipeline.py index`; lists every reachable page by full path; the overflow cure is subdirectories; details PLUGIN.md"
14
14
  usage:
15
- - Post-write rebuild (mechanical, automatic): `python .owfa/scripts/pipeline.py index` (index — overflow-offloading scheme, including deletion of obsolete old indexes after merge-back) and the same script's `tags` (tag reverse index); LLMs never hand-write indexes
15
+ - Post-write rebuild (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py index` (index — overflow-offloading scheme, including deletion of obsolete old indexes after merge-back) and the same script's `tags` (tag reverse index); LLMs never hand-write indexes
16
16
  checks:
17
17
  - Deviation between indexes and the actual page set (including merged-back indexes pending deletion) → fixed by running `pipeline.py index` to rebuild (idempotent; no diff means consistent); same for tags (`pipeline.py tags`)
18
18
  - Traces of hand editing → warning
@@ -42,6 +42,7 @@ log.max_chars: 14000 # window character cap, approximate
42
42
 
43
43
  ## Changelog
44
44
 
45
+ - 0.17 2026-11-15: pipeline call path relocated (suite 0.1.1); `usage_routes: [owfa-query]` added — the log projection in owfa-query's usage block is now manifest-backed
45
46
  - 0.16 2026-11-09: inject line rewritten to routing-pointer density (issue #49 phase 1, relieves the #48 budget): path + read/write trigger + the one easy-to-break invariant + pointer here; the dropped detail already lives in this file / the manifest
46
47
  - 0.15 2026-10-02: global-domain batch one — established the mandatory bridge, i.e. the recording bridge; domain bases must depend on it, kernel verifies completeness; entries gained the omissible `[domain]` tag; pipeline log gained the `--domain` parameter
47
48
  - 0.13 2026-09-23: added the wiki dependency edge — inner-side plugins attach to wiki, aligning with the domain 0.1 declaration; omitted from the 2026-09-22 domain-ization batch
@@ -1,18 +1,20 @@
1
1
  id: log
2
2
  schema_version: 1
3
- version: 0.16
3
+ version: 0.17
4
4
  bridge: 必依
5
5
  depends:
6
6
  - wiki
7
- updated: 2026-11-09
7
+ updated: 2026-11-15
8
8
  attachment:
9
9
  - "wiki/log.md — single-file operation journal (rolling window)"
10
10
  - "wiki/archive/YYYY-MM/log.md — archive spillover (immutable zone, grouped by entry month)"
11
11
  - "scripts/check.py — attached audit (entry date contract)"
12
12
  fields: {}
13
+ usage_routes:
14
+ - owfa-query
13
15
  inject: "Run log `wiki/log.md`: prepend, never rewrite; entry = date + type (map/save/query/check/plugin/todo/profile/other) + optional [domain] + one sentence, written via `pipeline.py log`; >100 entries auto-archived; details PLUGIN.md"
14
16
  usage:
15
- - Writing lines (mechanical, automatic): `python .owfa/scripts/pipeline.py log <type> "<one sentence>" [--domain <domain>]` (type value set in the log block of the AGENTS injection region; domain tag = domain-plugin name such as bb/lark/vault, mandatory for in-domain transactions, omitted for framework and native transactions); rolling window and archiving are performed by the script
17
+ - Writing lines (mechanical, automatic): `python .owfa/plugins/domains/personal/pipeline.py log <type> "<one sentence>" [--domain <domain>]` (type value set in the log block of the AGENTS injection region; domain tag = domain-plugin name such as bb/lark/vault, mandatory for in-domain transactions, omitted for framework and native transactions); rolling window and archiving are performed by the script
16
18
  checks:
17
19
  - Mechanical items (attached-audit script `scripts/check.py`, executed on audit discovery): undated entries (starting with `- ` yet not matching the date format, main file and archive checked alike) → error
18
20
  - Semantic items (check command): historical entries modified (verifiable via git) → error; capacity over the limit → re-check after mechanical archiving
@@ -0,0 +1,441 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Derived-layer post-write pipeline: index / tags / hot / log / verify.
4
+
5
+ Lives at the personal-suite package root since 0.1.1 (protocol machinery travels with
6
+ the suite; the kernel never calls it). Instance path: .owfa/plugins/domains/personal/pipeline.py.
7
+ The framework tree keeps a deprecated host copy until 0.5.0.
8
+
9
+ Positioning (.owfa/protocol/actions.md execution principles): deterministic structural
10
+ operations go to this script; semantic judgment goes to the LLM. Rebuild and rolling
11
+ rules and window parameters are governed by this file's source (the script source is
12
+ the rule list); PLUGIN.md keeps the semantic explanation; commands uniformly end by
13
+ invoking this pipeline instead of hand-writing derived pages themselves. verify is
14
+ post-write self-attestation (the minimal attester form): the LLM executes, the script
15
+ certifies.
16
+
17
+ Usage:
18
+ python .owfa/plugins/domains/personal/pipeline.py index # canonical suite location (host shim: .owfa/scripts/pipeline.py, deprecated)
19
+ python .owfa/scripts/pipeline.py index # deprecated host shim, retires in 0.5.0 (overflow-offloading scheme, idempotent; includes deleting surplus indexes after merging back)
20
+ python .owfa/scripts/pipeline.py tags # rebuild wiki/tags.md (idempotent)
21
+ python .owfa/scripts/pipeline.py hot <type> <one-liner> # evict out-of-window entries + prepend a hot-cache entry
22
+ python .owfa/scripts/pipeline.py log <type> <one-liner> [--domain domain] # capacity archive + prepend a log line (domain tag optional — domainless transactions)
23
+ python .owfa/scripts/pipeline.py verify # post-write self-attestation: attached audits + derived-area drift check
24
+
25
+ Type enumeration: map / save / query / check / plugin / todo / profile / other (the log plugin).
26
+ Concept-page determination (what enters the index): all .md under wiki/, excluding —
27
+ reserved names (index.md, log.md), wiki-root derived pages (hot.md, tags.md), the
28
+ archive/ subtree (immutable region, never rewritten by this script), and the tmp/
29
+ subtree (temporary zone: invisible to the derived layer, no retention promise, see the
30
+ tmp plugin). Index overflow-offloading scheme: a single index list holds at most
31
+ INDEX_MAX_ENTRIES entries (page entries + directory entries); the root index always
32
+ exists; on overflow, split off the subdirectories with the most pages (ties by name)
33
+ into their own indexes until it fits; pure-function rebuild (same structure, same result).
34
+ """
35
+ import datetime
36
+ import os
37
+ import re
38
+ import subprocess
39
+ import sys
40
+
41
+ if hasattr(sys.stdout, "reconfigure"):
42
+ sys.stdout.reconfigure(encoding="utf-8")
43
+ sys.stderr.reconfigure(encoding="utf-8")
44
+
45
+ # Location-adaptive bootstrap. Two legal hosts:
46
+ # suite install: <root>/.owfa/plugins/domains/personal/pipeline.py (canonical since 0.1.1)
47
+ # framework host shim: <root>/.owfa/scripts/pipeline.py (deprecated, retires in 0.5.0)
48
+ _here = os.path.dirname(os.path.abspath(__file__))
49
+ if os.path.basename(_here) == "scripts":
50
+ ROOT = os.path.dirname(os.path.dirname(_here)) # <root>/.owfa/scripts
51
+ else:
52
+ ROOT = os.path.dirname(os.path.dirname(os.path.dirname(_here))) # .../personal -> domains -> plugins -> .owfa -> root is one more up
53
+ ROOT = os.path.dirname(ROOT)
54
+ sys.path.insert(0, os.path.join(ROOT, ".owfa", "scripts")) # wikilib is a framework-level shared library
55
+ sys.path.insert(0, _here)
56
+ import wikilib
57
+ WIKI = os.path.join(ROOT, "wiki")
58
+ FORMAT_VERSION = "0.2"
59
+ DESC_MAX = 80
60
+ ROOT_RESERVED = {"hot.md", "tags.md"} # wiki-root derived pages (log.md/index.md are reserved names, excluded uniformly)
61
+
62
+ # rolling-window parameters (mechanical authoritative source for the hot / log plugins; PLUGIN.md keeps the semantic explanation)
63
+ HOT_MAX_ENTRIES = 25
64
+ HOT_MAX_DAYS = 5
65
+ HOT_MAX_CHARS = 200
66
+ LOG_MAX_ENTRIES = 100
67
+ INDEX_MAX_ENTRIES = 25 # single index-list window (page entries + directory entries; overflow-offloading split basis)
68
+ TYPE_ORDER = ["map", "save", "query", "check", "plugin", "todo", "profile", "other"]
69
+ HOT_HEADER = ("# 热缓存\n\n> 最近变更摘要;≤25 条且 <5 日,窗外即删;可整体再生。"
70
+ "规则见 `.owfa/plugins/domains/personal/hot/`,写走 `pipeline.py hot`。\n")
71
+ LOG_HEADER = ("# 运行日志\n\n> 置顶追加、只增不删;条目 = `- YYYY-MM-DD <类型> [<域>]:一句话`(域标可缺省——无域事务,log 桥)。"
72
+ "规则见 `.owfa/plugins/domains/personal/log/`,写走 `pipeline.py log`。\n")
73
+ DATE_RE = re.compile(r"^- (\d{4}-\d{2}-\d{2}) ")
74
+
75
+
76
+ def _today():
77
+ return datetime.date.today().isoformat()
78
+
79
+
80
+ # ---------- concept pages and index / tags ----------
81
+
82
+ def _cut(text):
83
+ return text if len(text) <= DESC_MAX else text[: DESC_MAX - 1] + "…"
84
+
85
+
86
+ def _desc(fm, body):
87
+ d = fm.get("description")
88
+ if d:
89
+ return _cut(str(d))
90
+ for line in body.splitlines():
91
+ t = line.strip()
92
+ if t and not t.startswith(("#", ">", "|", "```")):
93
+ return _cut(t)
94
+ return "(无描述)"
95
+
96
+
97
+ def concept_pages():
98
+ """[(page full name = path minus .md, containing dir, frontmatter, description)], sorted by full name."""
99
+ out = []
100
+ for rel, fm, body in wikilib.walk_pages(ROOT):
101
+ d, _, fn = rel.rpartition("/")
102
+ if fn in ("index.md", "log.md"):
103
+ continue # reserved names: not concept pages
104
+ if d == "" and fn in ROOT_RESERVED:
105
+ continue
106
+ if rel.startswith("archive/") or d.startswith("archive/") or d == "archive":
107
+ continue
108
+ if rel.startswith("tmp/") or d.startswith("tmp/") or d == "tmp":
109
+ continue # temporary zone: invisible to the derived layer
110
+ out.append((rel[:-3], d, fm, _desc(fm, body)))
111
+ return sorted(out)
112
+
113
+
114
+ def all_dirs(pages):
115
+ """The set of directories under wiki/ that should get an index (including empty ones; excluding the archive/ subtree)."""
116
+ dirs = {""}
117
+ for _, d, _, _ in pages:
118
+ parts = d.split("/") if d else []
119
+ for i in range(len(parts) + 1):
120
+ dirs.add("/".join(parts[:i]))
121
+ for dirpath, subdirs, _files in os.walk(WIKI):
122
+ if "archive" in subdirs:
123
+ subdirs.remove("archive") # do not descend into the immutable region
124
+ if "tmp" in subdirs:
125
+ subdirs.remove("tmp") # no index for the temporary zone
126
+ rel = os.path.relpath(dirpath, WIKI).replace(os.sep, "/")
127
+ dirs.add("" if rel == "." else rel)
128
+ return dirs
129
+
130
+
131
+ def subdirs_of(d, dirs):
132
+ """Direct subdirectory names of d (sorted)."""
133
+ prefix = d + "/" if d else ""
134
+ depth = d.count("/") + 1 if d else 0
135
+ return sorted(x[len(prefix):] for x in dirs
136
+ if x != d and x.startswith(prefix) and x.count("/") == depth)
137
+
138
+
139
+ def _count_subtree(full, pages):
140
+ return sum(1 for name, d, _, _ in pages if d == full or d.startswith(full + "/"))
141
+
142
+
143
+ def plan_index_dirs(pages, dirs):
144
+ """Overflow-offloading plan: returns the set of directories that should get an index.md (the root always present).
145
+
146
+ A directory's list = its own concept pages + pages of un-split subtrees (transparent
147
+ inlining) + directory entry lines; on overflow, split off the subdirectories with the
148
+ most pages (ties by name) into their own indexes until it fits. A split saves at least
149
+ S-1 lines, so a subdirectory with S<2 is never split; an empty subtree (S=0) costs
150
+ one inline line (the visibility line). Pure function: same structure guarantees the
151
+ same result, no historical state.
152
+ """
153
+ own = {}
154
+ for _, d, _, _ in pages:
155
+ own[d] = own.get(d, 0) + 1
156
+
157
+ planned = set()
158
+
159
+ def plan(d):
160
+ planned.add(d)
161
+ kids = subdirs_of(d, dirs)
162
+ sizes = {c: _count_subtree((d + "/" + c) if d else c, pages) for c in kids}
163
+ total = own.get(d, 0) + sum(s if s > 0 else 1 for s in sizes.values())
164
+ if total <= INDEX_MAX_ENTRIES:
165
+ return
166
+ for c in sorted((k for k in kids if sizes[k] >= 2),
167
+ key=lambda c: (-sizes[c], c)):
168
+ if total <= INDEX_MAX_ENTRIES:
169
+ break
170
+ plan((d + "/" + c) if d else c)
171
+ total -= sizes[c] - 1
172
+
173
+ plan("")
174
+ return planned
175
+
176
+
177
+ def visible_pages(d, pages, planned):
178
+ """Pages listed directly in d's index: this directory's pages + all descendant pages whose path crosses no split directory (transparent inlining)."""
179
+ pre = d + "/" if d else ""
180
+ out = []
181
+ for name, dd, fm, desc in pages:
182
+ if dd == d:
183
+ out.append((name, fm, desc))
184
+ elif dd.startswith(pre):
185
+ parts = dd[len(pre):].split("/")
186
+ if all((pre + "/".join(parts[:i])) not in planned for i in range(1, len(parts) + 1)):
187
+ out.append((name, fm, desc))
188
+ return out
189
+
190
+
191
+ def render_index(d, pages, dirs, planned):
192
+ """Full text of directory d's index.md (overflow-offloading scheme: reachable pages listed directly; split subdirectories as entry lines)."""
193
+ is_root = d == ""
194
+ lines = []
195
+ if is_root:
196
+ lines += ["---", f"format_version: {FORMAT_VERSION}", "---", ""]
197
+ lines.append("# 索引" if is_root else f"# {d.rsplit('/', 1)[-1]} 索引")
198
+ lines.append("")
199
+ tip = ("溢出减负:本页直列可达页面;清单超窗时子目录自立索引(入口行带页数),下钻读之。"
200
+ if is_root else "本目录索引:直列未切子树页面,已切子目录见入口行。")
201
+ lines.append(f"> {tip}只聚合、永不手编,由 index 插件经 `pipeline.py index` 重建。")
202
+ lines.append("")
203
+ entries = []
204
+ for s in subdirs_of(d, dirs):
205
+ full = (d + "/" + s) if d else s
206
+ n = _count_subtree(full, pages)
207
+ if full in planned:
208
+ entries.append(f"- [[{full}/index|{s}/]]({n} 页)")
209
+ elif n == 0:
210
+ entries.append(f"- {s}/(0 页)") # empty-subtree visibility line: no index to link, excluded from the broken-link graph
211
+ if entries:
212
+ lines += ["## 子目录", ""] + entries + [""]
213
+ groups = {}
214
+ for name, fm, desc in visible_pages(d, pages, planned):
215
+ groups.setdefault(str(fm.get("type") or "未分类"), []).append((name, desc))
216
+ for t in sorted(groups):
217
+ lines.append(f"## {t}")
218
+ lines.append("")
219
+ for name, desc in sorted(groups[t]):
220
+ lines.append(f"- [[{name}]] —— {desc}")
221
+ lines.append("")
222
+ if not entries and not groups:
223
+ lines.append("(暂无页面)")
224
+ lines.append("")
225
+ return "\n".join(lines).rstrip() + "\n"
226
+
227
+
228
+ def render_tags(pages):
229
+ tag_map = {}
230
+ for name, d, fm, _ in pages:
231
+ tags = fm.get("tags")
232
+ if tags is None:
233
+ continue
234
+ if not isinstance(tags, list):
235
+ tags = [tags]
236
+ for t in tags:
237
+ tag_map.setdefault(str(t), []).append(name)
238
+ lines = ["# tag 索引", "",
239
+ "> tag → 页面反向索引;只聚合、永不手编,由 index 插件经 `pipeline.py tags` 重建。", ""]
240
+ if not tag_map:
241
+ lines.append("(暂无)")
242
+ lines.append("")
243
+ for t in sorted(tag_map):
244
+ lines.append(f"## {t}")
245
+ lines.append("")
246
+ for name in sorted(tag_map[t]):
247
+ lines.append(f"- [[{name}]]")
248
+ lines.append("")
249
+ return "\n".join(lines).rstrip() + "\n"
250
+
251
+
252
+ def index_targets():
253
+ pages = concept_pages()
254
+ dirs = all_dirs(pages)
255
+ planned = plan_index_dirs(pages, dirs)
256
+ targets = {(d + "/" if d else "") + "index.md": render_index(d, pages, dirs, planned)
257
+ for d in planned}
258
+ return planned, targets
259
+
260
+
261
+ def write_changed(path, content):
262
+ if os.path.exists(path) and open(path, encoding="utf-8").read() == content:
263
+ return False
264
+ os.makedirs(os.path.dirname(path), exist_ok=True)
265
+ open(path, "w", encoding="utf-8", newline="\n").write(content)
266
+ return True
267
+
268
+
269
+ def do_index(check_only=False):
270
+ _, targets = index_targets()
271
+ drift, changed = [], 0
272
+ for rel, content in sorted(targets.items()):
273
+ path = os.path.join(WIKI, rel)
274
+ cur = open(path, encoding="utf-8").read() if os.path.exists(path) else None
275
+ if cur == content:
276
+ continue
277
+ if check_only:
278
+ drift.append(rel)
279
+ elif write_changed(path, content):
280
+ changed += 1
281
+ print(f"[index] rebuilt wiki/{rel}")
282
+ # unplanned index.md files (old indexes after offloading merges back): delete / report drift; archive/ and tmp/ subtrees untouched
283
+ for dirpath, subdirs, files in os.walk(WIKI):
284
+ if "archive" in subdirs:
285
+ subdirs.remove("archive") # do not descend into the immutable region
286
+ if "tmp" in subdirs:
287
+ subdirs.remove("tmp") # the temporary zone is outside this pipeline's jurisdiction
288
+ if "index.md" not in files:
289
+ continue
290
+ rel = os.path.relpath(os.path.join(dirpath, "index.md"), WIKI).replace(os.sep, "/")
291
+ if rel not in targets:
292
+ if check_only:
293
+ drift.append(rel)
294
+ else:
295
+ os.remove(os.path.join(WIKI, rel))
296
+ changed += 1
297
+ print(f"[index] removed wiki/{rel} (merged back into parent)")
298
+ if not check_only:
299
+ print(f"[index] done, {changed} file(s) changed (idempotent)")
300
+ return drift
301
+
302
+
303
+ def do_tags(check_only=False):
304
+ path = os.path.join(WIKI, "tags.md")
305
+ content = render_tags(concept_pages())
306
+ cur = open(path, encoding="utf-8").read() if os.path.exists(path) else None
307
+ if cur == content:
308
+ if not check_only:
309
+ print("[tags] unchanged")
310
+ return []
311
+ if check_only:
312
+ return ["tags.md"]
313
+ write_changed(path, content)
314
+ print("[tags] rebuilt wiki/tags.md")
315
+ return []
316
+
317
+
318
+ # ---------- hot / log rolling ----------
319
+
320
+ def do_hot(kind, text):
321
+ if kind not in TYPE_ORDER:
322
+ print(f"[hot] type must be one of {'/'.join(TYPE_ORDER)} (got {kind})")
323
+ return False
324
+ entry = f"- {_today()} {text}"[:HOT_MAX_CHARS]
325
+ # collect existing entries (with section membership), mechanically evict out-of-window ones
326
+ sections = {t: [] for t in TYPE_ORDER}
327
+ hot_path = os.path.join(WIKI, "hot.md")
328
+ if os.path.exists(hot_path):
329
+ cur = None
330
+ for raw in open(hot_path, encoding="utf-8").read().splitlines():
331
+ m = re.match(r"^##\s*Recent (\S+)", raw)
332
+ if m and m.group(1) in TYPE_ORDER:
333
+ cur = m.group(1)
334
+ continue
335
+ dm = DATE_RE.match(raw)
336
+ if dm and cur:
337
+ if (datetime.date.today() - datetime.date.fromisoformat(dm.group(1))).days < HOT_MAX_DAYS:
338
+ sections[cur].append(raw[:HOT_MAX_CHARS])
339
+ sections[kind].insert(0, entry) # prepend
340
+ flat = [e for t in TYPE_ORDER for e in sections[t]]
341
+ if len(flat) > HOT_MAX_ENTRIES: # overall overflow: keep the 25 most recent by date uniformly (stable sort, same-day keeps section order)
342
+ keep = set(sorted(flat, key=lambda e: e[2:12], reverse=True)[:HOT_MAX_ENTRIES])
343
+ for t in TYPE_ORDER:
344
+ sections[t] = [e for e in sections[t] if e in keep]
345
+ body = [HOT_HEADER.rstrip()]
346
+ any_entry = False
347
+ for t in TYPE_ORDER:
348
+ if not sections[t]:
349
+ continue
350
+ any_entry = True
351
+ body += ["", f"## Recent {t}", ""] + sections[t]
352
+ if not any_entry:
353
+ body += ["", "(暂无)"]
354
+ write_changed(hot_path, "\n".join(body) + "\n")
355
+ print(f"[hot] written ({kind}), {min(len(flat), HOT_MAX_ENTRIES)} entries")
356
+ return True
357
+
358
+
359
+ def _split_domain(args):
360
+ """Extract --domain <domain> / --domain=<domain> from the argument list (the log bridge's domain tag); the remaining args are returned in order."""
361
+ dom, rest, i = None, [], 0
362
+ while i < len(args):
363
+ if args[i] == "--domain" and i + 1 < len(args):
364
+ dom = args[i + 1]
365
+ i += 2
366
+ continue
367
+ if args[i].startswith("--domain="):
368
+ dom = args[i].split("=", 1)[1]
369
+ i += 1
370
+ continue
371
+ rest.append(args[i])
372
+ i += 1
373
+ return dom, rest
374
+
375
+
376
+ def do_log(kind, text, domain=None):
377
+ if kind not in TYPE_ORDER:
378
+ print(f"[log] type must be one of {'/'.join(TYPE_ORDER)} (got {kind})")
379
+ return False
380
+ log_path = os.path.join(WIKI, "log.md")
381
+ entries = []
382
+ if os.path.exists(log_path):
383
+ for raw in open(log_path, encoding="utf-8").read().splitlines():
384
+ if DATE_RE.match(raw):
385
+ entries.append(raw)
386
+ tag = f" [{domain}]" if domain else ""
387
+ entries.insert(0, f"- {_today()} {kind}{tag}:{text}") # prepend; existing entries are never rewritten
388
+ overflow = entries[LOG_MAX_ENTRIES:]
389
+ if overflow: # window overflow: the oldest stretch is grouped by entry month into archive/<month>/log.md (position move only)
390
+ for month in sorted({e[2:9] for e in overflow}):
391
+ moved = [e for e in overflow if e[2:9] == month]
392
+ adir = os.path.join(WIKI, "archive", month)
393
+ apath = os.path.join(adir, "log.md")
394
+ old = open(apath, encoding="utf-8").read() if os.path.exists(apath) else f"# 归档 {month}\n"
395
+ write_changed(apath, old.rstrip() + "\n" + "\n".join(moved) + "\n")
396
+ print(f"[log] archived {len(moved)} entries to wiki/archive/{month}/log.md")
397
+ write_changed(log_path, LOG_HEADER + "\n" + "\n".join(entries[:LOG_MAX_ENTRIES]) + "\n")
398
+ print(f"[log] written ({kind}), main file {min(len(entries), LOG_MAX_ENTRIES)} entries")
399
+ return True
400
+
401
+
402
+ # ---------- post-write self-attestation ----------
403
+
404
+ def do_verify():
405
+ ok = True
406
+ r = subprocess.run(
407
+ [sys.executable, os.path.join(ROOT, ".owfa", "scripts", "owfa_kernel.py"), "audit"])
408
+ if r.returncode != 0:
409
+ ok = False
410
+ print("[verify] plugin audit has errors")
411
+ drift = do_index(check_only=True) + do_tags(check_only=True)
412
+ if drift:
413
+ ok = False
414
+ print("[verify] derived drift: " + ", ".join("wiki/" + d for d in drift) + " (run pipeline.py index / tags to fix)")
415
+ else:
416
+ print("[verify] derived area consistent")
417
+ print("[verify] " + ("passed" if ok else "failed"))
418
+ return 0 if ok else 1
419
+
420
+
421
+ def main():
422
+ cmd = sys.argv[1] if len(sys.argv) > 1 else ""
423
+ if cmd == "index":
424
+ do_index()
425
+ return 0
426
+ if cmd == "tags":
427
+ do_tags()
428
+ return 0
429
+ if cmd == "hot":
430
+ return 0 if do_hot(sys.argv[2], " ".join(sys.argv[3:])) else 1
431
+ if cmd == "log":
432
+ dom, rest = _split_domain(sys.argv[3:])
433
+ return 0 if do_log(sys.argv[2], " ".join(rest), domain=dom) else 1
434
+ if cmd == "verify":
435
+ return do_verify()
436
+ print(__doc__)
437
+ return 2
438
+
439
+
440
+ if __name__ == "__main__":
441
+ sys.exit(main())
@@ -52,6 +52,7 @@ The performance budget for volumetric fog on low-end machines?
52
52
 
53
53
  ## Changelog
54
54
 
55
+ - 0.11 2026-11-15: manifest path fix — `.owfa/plugins/sessions/` → `.owfa/plugins/domains/personal/sessions/` (stale pre-split deployment path)
55
56
  - 0.10 2026-11-09: inject line rewritten to routing-pointer density (issue #49 phase 1, relieves the #48 budget): path + read/write trigger + the one easy-to-break invariant + pointer here; the dropped detail already lives in this file / the manifest
56
57
  - 0.9 2026-09-23: added the wiki dependency edge — inner plugins attach to wiki, aligning with the domain 0.1 declaration; missed in the 2026-09-22 domainization batch
57
58
  - 0.8 2026-09-13: made the usage sample pointer explicit — added the `.owfa/plugins/sessions/PLUGIN.md` path, zero priors
@@ -1,9 +1,9 @@
1
1
  id: sessions
2
2
  schema_version: 1
3
- version: 0.10
3
+ version: 0.11
4
4
  depends:
5
5
  - wiki
6
- updated: 2026-11-09
6
+ updated: 2026-11-15
7
7
  attachment:
8
8
  - "wiki/sessions/ — native sessions zone, session-type backbone pages"
9
9
  fields:
@@ -13,7 +13,7 @@ commands:
13
13
  inject: "Native sessions `wiki/sessions/`: session backbone pages (`type: session`, `participants` required, named YYYY-MM-DD-<topic>); high-value topics promoted to `wiki/notes/` with a back-link; commands append, never modify"
14
14
  usage:
15
15
  - Landing spot `wiki/sessions/YYYY-MM-DD-<topic>.md` (default naming), type: session, participants required (actor list)
16
- - Backbone page five-section shape: Core Conclusions / Decisions & Rationale / Non-obvious Insights / Open Questions / Related Pages (full-shape sample in the Example section of `.owfa/plugins/sessions/PLUGIN.md`)
16
+ - Backbone page five-section shape: Core Conclusions / Decisions & Rationale / Non-obvious Insights / Open Questions / Related Pages (full-shape sample in the Example section of `.owfa/plugins/domains/personal/sessions/PLUGIN.md`)
17
17
  - Standalone high-value topics promoted to `wiki/notes/` pages, the backbone page keeping a wikilink; dedupe before promotion
18
18
  checks:
19
19
  - Mechanical (covered by audit): session-type pages outside `wiki/sessions/` (or the reverse) → warning; participants missing or entries violating the actor convention → warning
@@ -24,4 +24,5 @@
24
24
  ## Changelog
25
25
 
26
26
  - 0.4 2026-11-09: inject line rewritten to routing-pointer density (issue #49 phase 1, relieves the #48 budget): path + read/write trigger + the one easy-to-break invariant + pointer here; the dropped detail already lives in this file / the manifest
27
- - 0.3 (2026-10-06) inject line: code formatting restored on the territory path (issue #12 post-migration nit)- 0.2 (2026-10-06) inject line compressed to pointer density (issue #12 layer discipline) — procedural detail lives in usage / PLUGIN.md / skills- 0.1 2026-09-19: established — path-as-territory, invisible to the derived layer, stale_after cleanup prompts, delete upon promotion
27
+ - 0.3 (2026-10-06) inject line: code formatting restored on the territory path (issue #12 post-migration nit)
28
+ - 0.2 (2026-10-06) inject line compressed to pointer density (issue #12 layer discipline) — procedural detail lives in usage / PLUGIN.md / skills- 0.1 2026-09-19: established — path-as-territory, invisible to the derived layer, stale_after cleanup prompts, delete upon promotion
@@ -35,7 +35,8 @@ The cognition bridge: the global profile's extension point toward domain-level c
35
35
 
36
36
  - 0.8 2026-11-12: contract-had-no-enforcement fix — mechanical checks (wrong-territory error / page-absent info) landed as the attached-audit script scripts/check.py, closing the gap between the declared checks and execution
37
37
  - 0.7 2026-11-09: inject line rewritten to routing-pointer density (issue #49 phase 1, relieves the #48 budget): path + read/write trigger + the one easy-to-break invariant + pointer here; the dropped detail already lives in this file / the manifest
38
- - 0.6 (2026-10-06) inject line: sections lost to the kernel comment-strip clip restored (quoted values are now protected), tightened for budget headroom — issue #12 post-migration nit- 0.5 (2026-10-06) inject line compressed to pointer density (issue #12 layer discipline) — procedural detail lives in usage / PLUGIN.md / skills- 0.4 2026-10-02: global-domain batch three — established the cognition bridge, on-demand: the profile body `## Domain Cognition` registration section, aggregate-don't-copy, read-first discipline; bb-track user.md the first registration; the mapping edge removed — under the bridge law it reached domain via the vault chain, causing a global plugin to be misjudged, caught by an actual kernel test; the 'hanging edges are harmless' premise failed
38
+ - 0.6 (2026-10-06) inject line: sections lost to the kernel comment-strip clip restored (quoted values are now protected), tightened for budget headroom — issue #12 post-migration nit
39
+ - 0.5 (2026-10-06) inject line compressed to pointer density (issue #12 layer discipline) — procedural detail lives in usage / PLUGIN.md / skills- 0.4 2026-10-02: global-domain batch three — established the cognition bridge, on-demand: the profile body `## Domain Cognition` registration section, aggregate-don't-copy, read-first discipline; bb-track user.md the first registration; the mapping edge removed — under the bridge law it reached domain via the vault chain, causing a global plugin to be misjudged, caught by an actual kernel test; the 'hanging edges are harmless' premise failed
39
40
  - 0.3 2026-09-29: profile command established — the write side shed its parasitism on the map and save dual entry points, both commands' consumes entries removed; the evidence domain opened to any page inside wiki, dissolving the cross-domain ownership suspension; first creation self-builds on trigger, absorbing the profile part of the pending initialization items; tags explicitly not applied; depends kept, ruling: reference-level edges retained, not cut
40
41
  - 0.2 2026-09-14: usage added the profile distillation methodology — signal criteria, layered placement, assertions concrete and verifiable; the executable part of the distillation entered the write-side contract, closing the SASU-L disclosure loop: an agent running map or save knows how to distill, without relying on model priors; the full text remains in `docs/research-user-profile.md`
41
42
  - 0.1 2026-09-13: established — `wiki/profile.md` convergence-style cognition profile, type: profile entered the registry value set; depends were wiki, trust, mapping, sessions; dual signal channels hung on save and map, consumes inserted after trust and before derivation; three checks — the assertion evidence gate as warning, wrong territory as error, page absence as info-level