Compare commits

..
Author SHA1 Message Date
m a925d787dc GEN2-027: prepare controlled production canary
CI / test (push) Failing after 26s
2026-08-29 12:01:37 +03:00
m 43556e1603 GEN2-026: route household context through scoped Gen2 projection
CI / test (push) Failing after 28s
2026-08-29 12:00:04 +03:00
m dd00dabf32 GEN2-025: normalize multimodal ingress provenance
CI / test (push) Failing after 27s
2026-08-29 11:58:34 +03:00
m 33365ce7ee GEN2-024: establish principal realms and source trust
CI / test (push) Failing after 26s
2026-08-29 11:57:19 +03:00
m 5017a854ee GEN2-023: make conversational configuration intent explicit
CI / test (push) Failing after 29s
2026-08-29 11:55:38 +03:00
m 839b35f310 GEN2 M4 remediation: durable recovery and governed evolution
CI / test (push) Failing after 26s
2026-08-29 11:47:05 +03:00
m 96687140ce GEN2-022: govern self evolution through development gates
CI / test (push) Failing after 27s
2026-08-29 11:31:45 +03:00
m b282038949 GEN2-021: add independent supervisor lifeboat
CI / test (push) Failing after 27s
2026-08-29 11:30:49 +03:00
m 4de506a2af GEN2-020: separate execution receipts from world outcomes
CI / test (push) Failing after 26s
2026-08-29 11:30:05 +03:00
m 36272b9036 GEN2-019: add advisory consequence assessment
CI / test (push) Failing after 29s
2026-08-29 11:28:52 +03:00
m a779568622 GEN2-018: add bounded perspectives over Work Graph
CI / test (push) Failing after 27s
2026-08-29 11:28:05 +03:00
m 243a11490b GEN2-017: add durable long-running investigations
CI / test (push) Failing after 26s
2026-08-29 11:27:21 +03:00
m 26207d93ef GEN2-016: add intelligence strategy and benchmark evidence
CI / test (push) Failing after 26s
2026-08-29 11:16:07 +03:00
m 42871f2e47 GEN2-015: add evidence-backed SELF ledger
CI / test (push) Failing after 28s
2026-08-29 11:13:38 +03:00
m 6ea1d4b729 GEN2-014: add reflex lifecycle and escalation
CI / test (push) Failing after 28s
2026-08-29 11:12:42 +03:00
m c6d1ebf36f GEN2-013: add versioned Skill V2 contracts
CI / test (push) Failing after 27s
2026-08-29 11:11:50 +03:00
m 25d8d6d219 GEN2-012: add typed scoped configuration
CI / test (push) Failing after 33s
2026-08-29 11:09:33 +03:00
m 6cbef9af41 GEN2-012: add scoped configuration bootstrap boundary
CI / test (push) Failing after 34s
2026-08-29 11:08:53 +03:00
m 2fe9802e5a GEN2-011: cut PersonalMemory to compatibility fallback
CI / test (push) Failing after 37s
2026-08-29 02:41:23 +03:00
m 0882df3ad2 GEN2-010: add bounded Context Compiler V2 trace
CI / test (push) Successful in 53s
2026-08-29 02:39:58 +03:00
m 0acbe53fad GEN2-009: add rebuildable retrieval projections
CI / test (push) Successful in 50s
2026-08-29 02:38:49 +03:00
m e634bb946a GEN2-008: promote experience and episode projections
CI / test (push) Successful in 55s
2026-08-29 02:37:28 +03:00
m c7ad996cae GEN2-007: add task-relative freshness assessment
CI / test (push) Successful in 52s
2026-08-29 02:35:54 +03:00
m a065382512 GEN2-006: normalize epistemic propositions and assessments
CI / test (push) Successful in 51s
2026-08-29 02:33:09 +03:00
m 8a8e571905 GEN2-005: govern identity resolution and version bindings
CI / test (push) Failing after 38s
2026-08-29 02:20:02 +03:00
m 301dbdcfb2 GEN2-004: add ContextScope and FocusStack V2
CI / test (push) Successful in 50s
2026-08-29 02:17:36 +03:00
m 8037e66998 GEN2-003: add typed World referent foundation
CI / test (push) Successful in 50s
2026-08-29 02:11:36 +03:00
m 29815c49b8 GEN2-002: add shared semantic primitives
CI / test (push) Successful in 52s
2026-08-29 02:08:20 +03:00
m c14ad7fd0b GEN2-001: accept owner registry and dependency rules
CI / test (push) Successful in 49s
2026-08-29 02:05:35 +03:00
m 939a5152e1 ARCH-GEN2-000: adopt Gen2 architecture governance
CI / test (push) Successful in 48s
2026-08-29 01:53:27 +03:00
m 4e54ace76b Route local place searches to relevant evidence
CI / test (pull_request) Successful in 1m19s
CI / test (push) Successful in 47s
2026-08-26 10:40:15 +03:00
m f329224d12 Merge pull request 'Keep nearest flight reply focused' (#405) from codex/household-text-cognition-path into main
CI / test (push) Successful in 1m21s
Reviewed-on: #405
2026-08-26 07:33:36 +00:00
m bb76171af4 Merge remote-tracking branch 'origin/main' into codex/household-text-cognition-path
CI / test (push) Successful in 1m20s
CI / test (pull_request) Successful in 1m23s
2026-08-26 10:30:15 +03:00
m 213f06661d Keep nearest flight reply focused
CI / test (push) Failing after 59s
CI / test (pull_request) Failing after 58s
2026-08-26 10:27:54 +03:00
m d350b9a565 Merge pull request 'Allow reply-only cognition for text directives' (#404) from codex/household-text-cognition-path into main
CI / test (push) Successful in 1m24s
Reviewed-on: #404
2026-08-26 07:21:07 +00:00
m f862c3ac13 Allow reply-only cognition for text directives
CI / test (push) Successful in 1m22s
CI / test (pull_request) Successful in 1m17s
2026-08-26 10:17:51 +03:00
m 5e18eb6082 Merge pull request 'Route safe text directives through cognition' (#403) from codex/household-text-directives into main
CI / test (push) Successful in 1m21s
Reviewed-on: #403
2026-08-26 07:12:00 +00:00
m ec86c983e3 Route safe text directives through cognition
CI / test (push) Successful in 1m20s
CI / test (pull_request) Successful in 1m16s
2026-08-26 10:08:42 +03:00
m ea854d5278 Merge pull request 'Allow review of backed research answers' (#402) from codex/household-research-review into main
CI / test (push) Successful in 1m17s
Reviewed-on: #402
2026-08-26 07:01:37 +00:00
m bbecadcec2 Allow review of backed research answers
CI / test (push) Successful in 1m19s
CI / test (pull_request) Successful in 1m22s
2026-08-26 09:58:20 +03:00
m 1c89b30512 Merge pull request 'Reject distance sources without measured evidence' (#401) from codex/household-distance-evidence into main
CI / test (push) Successful in 1m18s
Reviewed-on: #401
2026-08-26 06:50:59 +00:00
m 75a8533939 Reject distance sources without measured evidence
CI / test (push) Successful in 1m18s
CI / test (pull_request) Successful in 1m18s
2026-08-26 09:47:49 +03:00
m 515a98c470 Merge pull request 'Preserve distance context before search normalization' (#400) from codex/household-distance-context into main
CI / test (push) Successful in 1m32s
Reviewed-on: #400
2026-08-26 06:38:01 +00:00
m d3ad1fd5bb Preserve distance context before search normalization
CI / test (push) Successful in 1m23s
CI / test (pull_request) Successful in 1m20s
2026-08-26 09:34:43 +03:00
m e1802aef12 Merge pull request 'Answer directly without repeating the question' (#399) from codex/household-direct-answer into main
CI / test (push) Successful in 1m34s
Reviewed-on: #399
2026-08-26 06:23:34 +00:00
m 35fc2438dc Answer directly without repeating the question
CI / test (push) Successful in 1m25s
CI / test (pull_request) Successful in 1m21s
2026-08-26 09:19:28 +03:00
m 70335a78e2 Merge pull request 'Fallback to local interpretation when provider fails' (#398) from codex/household-answer-quality into main
CI / test (push) Successful in 1m33s
Reviewed-on: #398
2026-08-26 06:05:14 +00:00
m 41067a0b16 Merge branch 'main' into codex/household-answer-quality
CI / test (push) Successful in 1m18s
CI / test (pull_request) Successful in 1m18s
2026-08-26 06:00:13 +00:00
m fba05d5ed4 Fallback to local interpretation when provider fails
CI / test (push) Failing after 56s
CI / test (pull_request) Failing after 56s
2026-08-26 08:59:49 +03:00
m 6e14ba1727 Merge pull request 'Review stable knowledge replies for conversational quality' (#397) from codex/household-answer-quality into main
CI / test (push) Successful in 2m0s
Reviewed-on: #397
2026-08-26 05:53:37 +00:00
m 9c6e2097b1 Review stable knowledge replies for conversational quality
CI / test (push) Successful in 1m20s
CI / test (pull_request) Successful in 1m27s
2026-08-26 08:48:01 +03:00
m 96559f6ab8 Merge pull request 'Preserve completed household answers in web chat' (#396) from codex/household-core-reply into main
CI / test (push) Successful in 1m25s
Reviewed-on: #396
2026-08-26 04:58:04 +00:00
m 46b89577eb Preserve completed household answers in web chat
CI / test (push) Successful in 1m20s
CI / test (pull_request) Successful in 1m21s
2026-08-26 05:21:53 +03:00
m a6ddbfaaf2 Merge pull request 'Handle household typos through semantic cognition' (#395) from codex/household-typo-cognition into main
CI / test (push) Successful in 1m29s
Reviewed-on: #395
2026-08-26 02:17:46 +00:00
m 362a1bd993 Handle household typos through semantic cognition
CI / test (push) Successful in 1m48s
CI / test (pull_request) Successful in 1m15s
2026-08-26 04:59:40 +03:00
m 735222de0d Merge pull request 'Route household knowledge and travel evidence through cognition' (#394) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m34s
Reviewed-on: #394
2026-08-26 01:51:16 +00:00
m 4e3d153557 Route household knowledge through cognition
CI / test (push) Successful in 1m50s
CI / test (pull_request) Successful in 1m16s
2026-08-26 04:31:18 +03:00
m f316f7ec3f Exclude dates from concrete research identifiers
CI / test (push) Successful in 1m21s
2026-08-26 04:20:15 +03:00
m da5d06895b Require destination evidence for ticket results
CI / test (push) Successful in 1m17s
2026-08-26 04:17:12 +03:00
m 4d1a579132 Merge pull request 'Keep source names out of identifier clarification' (#393) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m23s
Reviewed-on: #393
2026-08-26 01:12:36 +00:00
m 43836af511 Keep source names out of identifier clarification
CI / test (push) Successful in 1m15s
CI / test (pull_request) Successful in 1m37s
2026-08-26 03:34:00 +03:00
m 32457f7142 Merge pull request 'Explain missing concrete research identifiers' (#392) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m30s
Reviewed-on: #392
2026-08-26 00:31:26 +00:00
m 204eee489c Explain missing concrete research identifiers
CI / test (push) Successful in 1m15s
CI / test (pull_request) Successful in 1m16s
2026-08-26 03:20:17 +03:00
m 5cd8665aba Merge pull request 'Reject generic pages for concrete research identifiers' (#391) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m30s
Reviewed-on: #391
2026-08-26 00:17:03 +00:00
m 04018cbd07 Reject generic pages for concrete research identifiers
CI / test (push) Successful in 1m25s
CI / test (pull_request) Successful in 1m18s
2026-08-26 02:11:51 +03:00
m 23a1eeae56 Merge pull request 'Allow research source recovery to complete' (#390) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m12s
Reviewed-on: #390
2026-08-25 21:25:26 +00:00
m 369588ada7 Clean search imperatives before research
CI / test (push) Successful in 1m25s
CI / test (pull_request) Failing after 55s
2026-08-26 00:24:45 +03:00
m e323689fd4 Merge pull request 'Allow research source recovery to complete' (#390) from codex/household-travel-query-fix into main
Reviewed-on: #390
2026-08-25 21:19:35 +00:00
m af042dc69f Keep internet status replies concise
CI / test (push) Successful in 1m26s
CI / test (pull_request) Failing after 53s
2026-08-26 00:19:15 +03:00
m 60c1c31bd9 Merge pull request 'Allow research source recovery to complete' (#390) from codex/household-travel-query-fix into main
Reviewed-on: #390
2026-08-25 21:14:40 +00:00
m ff3f14fc77 Request time difference measurements explicitly
CI / test (push) Failing after 59s
CI / test (pull_request) Failing after 56s
2026-08-26 00:14:20 +03:00
m 36f991d8d0 Merge pull request 'Allow research source recovery to complete' (#390) from codex/household-travel-query-fix into main
Reviewed-on: #390
2026-08-25 21:11:50 +00:00
m 54a3996c17 Keep comparison entities in one request
CI / test (push) Failing after 59s
CI / test (pull_request) Failing after 52s
2026-08-26 00:11:30 +03:00
m a769f33d16 Merge pull request 'Allow research source recovery to complete' (#390) from codex/household-travel-query-fix into main
Reviewed-on: #390
2026-08-25 21:08:39 +00:00
m 056ff1b795 Research current time differences generically
CI / test (push) Failing after 1m0s
CI / test (pull_request) Failing after 57s
2026-08-26 00:08:19 +03:00
m 7b2debb60e Merge pull request 'Allow research source recovery to complete' (#390) from codex/household-travel-query-fix into main
Reviewed-on: #390
2026-08-25 21:02:12 +00:00
m 6dfb3fc26c Validate displayed flight research excerpts
CI / test (push) Failing after 1m0s
CI / test (pull_request) Failing after 57s
2026-08-26 00:01:51 +03:00
m e0a093eaf3 Merge pull request 'Allow research source recovery to complete' (#390) from codex/household-travel-query-fix into main
Reviewed-on: #390
2026-08-25 20:58:11 +00:00
m 24916aa8f7 Require route evidence in displayed snippets
CI / test (push) Successful in 1m38s
CI / test (pull_request) Failing after 55s
2026-08-25 23:57:50 +03:00
m d7afd5be34 Merge pull request 'Allow research source recovery to complete' (#390) from codex/household-travel-query-fix into main
Reviewed-on: #390
2026-08-25 20:47:18 +00:00
m e104ce790d Require full route evidence for nearest flights
CI / test (push) Successful in 1m29s
CI / test (pull_request) Failing after 56s
2026-08-25 23:46:52 +03:00
m d7484cf757 Merge pull request 'Allow research source recovery to complete' (#390) from codex/household-travel-query-fix into main
Reviewed-on: #390
2026-08-25 20:43:03 +00:00
m a57e8ea71b Allow research source recovery to complete
CI / test (push) Failing after 56s
CI / test (pull_request) Failing after 1m4s
2026-08-25 23:42:33 +03:00
m 9dffde63b8 Merge pull request 'Form nearest flight searches from route context' (#389) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m16s
Reviewed-on: #389
2026-08-25 20:39:42 +00:00
m 4e5bb9abc9 Form nearest flight searches from route context
CI / test (push) Successful in 1m28s
CI / test (pull_request) Failing after 57s
2026-08-25 23:39:08 +03:00
m 3435de8013 Merge pull request 'Preserve honest research outcomes' (#388) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m13s
Reviewed-on: #388
2026-08-25 20:34:09 +00:00
m 76c2824887 Preserve attempted research outcomes
CI / test (push) Successful in 1m30s
CI / test (pull_request) Failing after 56s
2026-08-25 23:33:30 +03:00
m fc00a57942 Merge pull request 'Observe chat context route decisions' (#387) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m15s
Reviewed-on: #387
2026-08-25 20:30:19 +00:00
m 1b21888e8b Observe chat context route decisions
CI / test (push) Successful in 1m27s
CI / test (pull_request) Failing after 1m1s
2026-08-25 23:29:39 +03:00
m 012f5efafe Merge pull request 'Compile personal facts for contextual assistance' (#386) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m12s
Reviewed-on: #386
2026-08-25 19:51:47 +00:00
m eb842e24ff Compile personal facts for contextual assistance
CI / test (push) Successful in 1m15s
CI / test (pull_request) Failing after 50s
2026-08-25 22:50:37 +03:00
m 13bbcdf747 Preserve specialized research routes
CI / test (push) Successful in 1m19s
2026-08-25 22:46:20 +03:00
m c00b9b1549 Merge pull request 'Route plane requests through verified research' (#385) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m15s
Reviewed-on: #385
2026-08-25 19:42:26 +00:00
m 2d88d488f4 Route plane requests through verified research
CI / test (push) Successful in 1m34s
CI / test (pull_request) Failing after 58s
2026-08-25 22:42:03 +03:00
m 72c9cfc893 Merge pull request 'Validate flight research by route meaning' (#384) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m22s
Reviewed-on: #384
2026-08-25 19:35:41 +00:00
m 0b619bdc08 Validate flight research by route meaning
CI / test (push) Successful in 1m28s
CI / test (pull_request) Failing after 58s
2026-08-25 22:35:21 +03:00
m db23e984da Merge pull request 'Forward large generated images to chat' (#383) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m14s
Reviewed-on: #383
2026-08-25 19:31:17 +00:00
m f0c8f39986 Forward large generated images to chat
CI / test (push) Successful in 1m28s
CI / test (pull_request) Failing after 53s
2026-08-25 22:30:50 +03:00
m 5d8ec1995a Merge pull request 'Honor requested image quality' (#382) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m30s
Reviewed-on: #382
2026-08-25 19:14:21 +00:00
m 75d707e960 Honor requested image quality
CI / test (push) Successful in 1m22s
CI / test (pull_request) Successful in 1m25s
2026-08-25 22:12:44 +03:00
m 89b053b7bf Merge pull request 'Require assistant target for renaming' (#381) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m16s
Reviewed-on: #381
2026-08-25 18:32:39 +00:00
m e90aded6d3 Require assistant target for renaming
CI / test (push) Successful in 1m25s
CI / test (pull_request) Failing after 54s
2026-08-25 21:32:20 +03:00
m 8456ecd237 Merge pull request 'Continue ticket search with date follow-up' (#380) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m13s
Reviewed-on: #380
2026-08-25 18:21:30 +00:00
m b89fdef1d9 Merge remote-tracking branch 'origin/main' into codex/household-travel-query-fix
CI / test (push) Failing after 57s
CI / test (pull_request) Failing after 55s
2026-08-25 21:21:12 +03:00
m 6f3d576602 Continue ticket search with date follow-up
CI / test (push) Failing after 50s
CI / test (pull_request) Failing after 1m9s
2026-08-25 21:20:36 +03:00
m b026ec151e Merge pull request 'Preserve explicit memory confirmations' (#379) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m25s
Reviewed-on: #379
2026-08-25 18:16:05 +00:00
m 5d4c3877b1 Preserve explicit memory confirmations
CI / test (push) Successful in 1m14s
CI / test (pull_request) Successful in 1m26s
2026-08-25 21:13:26 +03:00
m 113c5ab965 Merge pull request 'Apply learned source aliases to research' (#378) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m14s
Reviewed-on: #378
2026-08-25 18:02:29 +00:00
m bce7993a6a Apply learned source aliases to research
CI / test (push) Successful in 1m30s
CI / test (pull_request) Failing after 52s
2026-08-25 21:02:07 +03:00
m 3bbf416c20 Merge pull request 'Explain missing research evidence' (#377) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m14s
Reviewed-on: #377
2026-08-25 17:56:42 +00:00
m b62b3b0dc3 Explain missing research evidence
CI / test (push) Failing after 59s
CI / test (pull_request) Failing after 1m2s
2026-08-25 20:56:21 +03:00
m 7e72474b0a Merge pull request 'Summarize verified internet connectivity' (#376) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m33s
Reviewed-on: #376
2026-08-25 17:53:22 +00:00
m b05081328e Recognize network connection wording
CI / test (push) Failing after 1m1s
CI / test (pull_request) Failing after 50s
2026-08-25 20:53:00 +03:00
m 0e7d1a7a50 Summarize verified internet connectivity
CI / test (push) Failing after 58s
2026-08-25 20:52:41 +03:00
m 2aaa73bb2a Merge pull request 'Describe local Domovoy capabilities' (#375) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m13s
Reviewed-on: #375
2026-08-25 17:50:03 +00:00
m 9000d90d72 Describe local Domovoy capabilities
CI / test (push) Successful in 1m29s
CI / test (pull_request) Failing after 1m0s
2026-08-25 20:49:39 +03:00
m 4afcfd3846 Merge pull request 'Recognize self capability questions' (#374) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m19s
Reviewed-on: #374
2026-08-25 16:54:32 +00:00
m 6ba8265686 Recognize self capability questions
CI / test (push) Failing after 58s
CI / test (pull_request) Failing after 54s
2026-08-25 19:54:06 +03:00
m 21583528c0 Merge pull request 'Explain current cognitive response route' (#373) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m18s
Reviewed-on: #373
2026-08-25 16:51:27 +00:00
m b1bb48f5b5 Explain current cognitive response route
CI / test (push) Successful in 1m40s
CI / test (pull_request) Failing after 54s
2026-08-25 19:51:03 +03:00
m 88f5f6e8f8 Merge pull request 'Recognize named model inventory requests' (#372) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m16s
Reviewed-on: #372
2026-08-25 16:48:12 +00:00
m 5439db2cc3 Recognize named model inventory requests
CI / test (push) Successful in 1m14s
CI / test (pull_request) Failing after 54s
2026-08-25 19:47:25 +03:00
m 208cb18ee0 Merge pull request 'Preserve latest travel context' (#371) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m32s
Reviewed-on: #371
2026-08-25 16:43:43 +00:00
m 5d19becdaf Preserve latest travel context
CI / test (push) Successful in 1m10s
CI / test (pull_request) Successful in 1m14s
2026-08-25 19:36:49 +03:00
m 4cd3ecdf15 Merge pull request 'Normalize contextual travel research' (#370) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m13s
Reviewed-on: #370
2026-08-25 16:29:58 +00:00
m 8e26f529f7 Merge remote-tracking branch 'origin/codex/household-travel-query-fix' into codex/household-travel-query-fix
CI / test (push) Failing after 1m3s
CI / test (pull_request) Failing after 54s
2026-08-25 19:28:11 +03:00
m 3cc636d6b7 Normalize contextual travel research 2026-08-25 19:27:59 +03:00
m 14dc439c82 Merge pull request 'Improve semantic travel research queries' (#369) from codex/household-travel-query-fix into main
CI / test (push) Successful in 1m14s
Reviewed-on: #369
2026-08-25 16:26:24 +00:00
m 21887988b2 Merge branch 'main' into codex/household-travel-query-fix
CI / test (push) Failing after 57s
CI / test (pull_request) Failing after 54s
2026-08-25 16:25:54 +00:00
m 232a57eed4 Improve semantic travel research queries
CI / test (push) Failing after 53s
CI / test (pull_request) Failing after 54s
2026-08-25 19:25:00 +03:00
m d1fd70e436 Merge pull request 'Preserve location context for travel follow-ups' (#368) from codex/household-travel-context-fix into main
CI / test (push) Successful in 1m30s
Reviewed-on: #368
2026-08-25 16:22:04 +00:00
m 1d73162df1 Merge remote-tracking branch 'origin/main' into codex/household-travel-context-fix
CI / test (push) Successful in 1m14s
CI / test (pull_request) Successful in 1m24s
2026-08-25 19:17:59 +03:00
m 7788cf4b44 Preserve location context for travel follow-ups
CI / test (push) Failing after 58s
CI / test (pull_request) Failing after 50s
2026-08-25 19:17:34 +03:00
m d9dcddbdbb Merge pull request 'Preserve direct time difference replies' (#367) from codex/household-time-reply-priority into main
CI / test (push) Successful in 2m3s
Reviewed-on: #367
2026-08-25 16:11:36 +00:00
m 5fb616310d Merge remote-tracking branch 'origin/main' into codex/household-time-reply-priority
CI / test (push) Successful in 1m18s
CI / test (pull_request) Successful in 1m24s
2026-08-25 19:08:15 +03:00
m 5a9cf7a22d Preserve direct time difference replies
CI / test (push) Failing after 51s
CI / test (pull_request) Failing after 48s
2026-08-25 19:06:51 +03:00
m d649f79ca4 Merge pull request 'Preserve remembered preference identity' (#366) from codex/household-checklist-live-preference-fix into main
CI / test (push) Successful in 1m58s
Reviewed-on: #366
2026-08-25 16:00:08 +00:00
172 changed files with 21048 additions and 183 deletions
+13
View File
@@ -72,3 +72,16 @@ State:
- assumptions;
- findings not changed;
- gaps or limitations.
## Domovoy Gen2 execution governance
When the active task is a Gen2 packet, read the canonical documents before editing:
- `docs/DOMOVOY_CONSTITUTION.md`
- `architecture/GEN2_TARGET_ARCHITECTURE.md`
- `architecture/GEN2_CANONICAL_DATA_MODEL.md`
- `development/GEN2_MIGRATION_MAP.md`
- `development/GEN2_MASTER_PLAN.md`
- `development/GEN2_EXECUTION_CONTRACT.md`
The active task packet and `development/GEN2_TASK_INDEX.md` define execution order. `PRE-GEN2-000` freezes the V1 baseline; `ARCH-GEN2-000` accepts Gen2 governance; later `GEN2-*` packets must not be started automatically. Gen2 architecture and ownership changes are permitted only within the active packet's declared scope and authority. Default validation is FAST; MILESTONE or FULL is required only when the selected packet explicitly says so.
+18
View File
@@ -0,0 +1,18 @@
package multimodal
import (
"crypto/sha256"
"encoding/hex"
"git.cin.su/m/Assistant/contracts/artifact"
"git.cin.su/m/Assistant/contracts/capability"
"git.cin.su/m/Assistant/contracts/interaction"
)
func NormalizeIngress(id string, modality interaction.IngressModality, sourceRef, deviceRef, locationRef, principalID, contentType string, data []byte, response capability.MultimodalResponse, at int64) (interaction.IngressEnvelope, artifact.MediaArtifact) {
hash := sha256.Sum256(data)
artifactValue := artifact.MediaArtifact{ID: artifact.ArtifactID("artifact:media:" + hex.EncodeToString(hash[:8])), ContentType: contentType, SizeBytes: int64(len(data)), ContentDigest: hex.EncodeToString(hash[:]), SourceRef: sourceRef, RecordedAtUnixMillis: at}
if len(data) == 0 {
return interaction.IngressEnvelope{ID: id, Modality: modality, SourceRef: sourceRef, DeviceRef: deviceRef, LocationRef: locationRef, PrincipalID: principalID, Degraded: true, RecordedAtUnixMillis: at}, artifact.MediaArtifact{}
}
return interaction.IngressEnvelope{ID: id, Modality: modality, SourceRef: sourceRef, DeviceRef: deviceRef, LocationRef: locationRef, PrincipalID: principalID, ArtifactRef: string(artifactValue.ID), ObservationRef: response.EvidenceRef, ProviderRef: response.Provider, ModelRef: response.Model, ModelVersion: response.ModelVersion, ConfidenceMillis: response.ConfidenceMillis, RecordedAtUnixMillis: at}, artifactValue
}
+22
View File
@@ -0,0 +1,22 @@
package multimodal_test
import (
"git.cin.su/m/Assistant/adapters/multimodal"
"git.cin.su/m/Assistant/contracts/capability"
"git.cin.su/m/Assistant/contracts/interaction"
"testing"
)
func TestIngressNormalizesMediaArtifactAndObservationProvenance(t *testing.T) {
e, a := multimodal.NormalizeIngress("ingress-1", interaction.IngressImage, "camera:street", "device:cam", "world:street", "principal", "image/png", []byte("image"), capability.MultimodalResponse{Provider: "local", Model: "vision", ModelVersion: "1", EvidenceRef: "observation-1", ConfidenceMillis: 800}, 1)
if !e.Valid() || !a.Valid() || e.ArtifactRef == "" || e.ObservationRef != "observation-1" || e.DeviceRef == "" || e.LocationRef == "" {
t.Fatalf("envelope=%+v artifact=%+v", e, a)
}
}
func TestUnavailableIngressDegradesWithoutFabricatingObservation(t *testing.T) {
e, a := multimodal.NormalizeIngress("ingress-1", interaction.IngressAudio, "mic", "device:mic", "", "principal", "audio/wav", nil, capability.MultimodalResponse{}, 1)
if !e.Degraded || e.ObservationRef != "" || a.Valid() {
t.Fatalf("envelope=%+v artifact=%+v", e, a)
}
}
+33
View File
@@ -2,6 +2,7 @@ package postgres
import (
"context"
"encoding/json"
"strings"
"git.cin.su/m/Assistant/contracts/identity"
@@ -18,6 +19,38 @@ func OpenSituation(ctx context.Context, config ContinuityConfig) (*SituationRepo
}
return &SituationRepository{pool: pool}, nil
}
func (r *SituationRepository) SaveContextScope(ctx context.Context, scope situation.ContextScope) error {
if err := scope.Validate(); err != nil {
return err
}
bindings, err := json.Marshal(scope.Bindings)
if err != nil {
return err
}
_, err = r.pool.Exec(ctx, `INSERT INTO situation.context_scopes(context_scope_id,principal_id,revision,bindings,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5) ON CONFLICT(context_scope_id) DO UPDATE SET revision=EXCLUDED.revision, bindings=EXCLUDED.bindings, recorded_at_unix_millis=EXCLUDED.recorded_at_unix_millis`, scope.ID, scope.PrincipalID, scope.Revision, bindings, scope.RecordedAt)
return err
}
func (r *SituationRepository) SaveFocusFrame(ctx context.Context, frame situation.FocusFrame) error {
if err := frame.Validate(); err != nil {
return err
}
ref, err := json.Marshal(frame.ContextScopeRef)
if err != nil {
return err
}
_, err = r.pool.Exec(ctx, `INSERT INTO situation.focus_frames(focus_frame_id,principal_id,actor_id,revision,authority_scope_ref,context_scope_ref,goal_ref,task_ref,source_utterance_ref,provenance,confidence_millis,state,parent_frame_ref,activated_at_unix_millis,suspended_at_unix_millis,expired_at_unix_millis,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17) ON CONFLICT(focus_frame_id) DO UPDATE SET revision=EXCLUDED.revision, context_scope_ref=EXCLUDED.context_scope_ref, state=EXCLUDED.state, suspended_at_unix_millis=EXCLUDED.suspended_at_unix_millis, expired_at_unix_millis=EXCLUDED.expired_at_unix_millis, recorded_at_unix_millis=EXCLUDED.recorded_at_unix_millis`, frame.ID, frame.PrincipalID, frame.ActorID, frame.Revision, frame.AuthorityScopeRef, ref, frame.GoalRef, frame.TaskRef, frame.SourceUtteranceRef, frame.Provenance, frame.ConfidenceMillis, frame.State, frame.ParentFrameRef, frame.ActivatedAt, frame.SuspendedAt, frame.ExpiredAt, frame.RecordedAt)
return err
}
func (r *SituationRepository) AppendFocusTransition(ctx context.Context, transition situation.FocusTransition) error {
if err := transition.Validate(); err != nil {
return err
}
_, err := r.pool.Exec(ctx, `INSERT INTO situation.focus_transitions(transition_id,focus_frame_id,from_revision,to_revision,operation,cause_ref,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7)`, transition.TransitionID, transition.FrameID, transition.FromRevision, transition.ToRevision, transition.Operation, transition.CauseRef, transition.RecordedAt)
return err
}
func (r *SituationRepository) Close() { r.pool.Close() }
func (r *SituationRepository) Save(ctx context.Context, binding situation.FocusBinding) error {
_, err := r.pool.Exec(ctx, `INSERT INTO situation.focus_bindings (focus_binding_id, actor_id, session_id, workspace_id, project_id, goal_id, scope_id, active) VALUES ($1,$2,$3,$4,$5,$6,$7,$8) ON CONFLICT (focus_binding_id) DO UPDATE SET active=EXCLUDED.active`, binding.ID, binding.ActorID, binding.SessionID, binding.Workspace, binding.ProjectID, binding.GoalID, binding.ScopeID, binding.Active)
+115
View File
@@ -25,6 +25,121 @@ var (
ErrDevelopmentCandidateConflict = errors.New("development candidate conflict")
)
func (r *WorkRepository) SaveInvestigation(ctx context.Context, value work.Investigation, expectedRevision int64) error {
if !value.Valid() || expectedRevision < 0 {
return errors.New("invalid investigation revision")
}
attempts := make([]string, 0, len(value.AttemptRefs))
for _, item := range value.AttemptRefs {
attempts = append(attempts, string(item))
}
hypotheses := make([]string, 0, len(value.HypothesisRefs))
for _, item := range value.HypothesisRefs {
hypotheses = append(hypotheses, string(item))
}
findings := make([]string, 0, len(value.FindingRefs))
for _, item := range value.FindingRefs {
findings = append(findings, string(item))
}
blockers := append([]string(nil), value.Blockers...)
checkpoints := make([]string, 0, len(value.CheckpointRefs))
for _, item := range value.CheckpointRefs {
checkpoints = append(checkpoints, string(item))
}
if expectedRevision == 0 {
result, err := r.pool.Exec(ctx, `INSERT INTO work.long_running_work(investigation_id,objective,hypothesis_refs,attempt_refs,finding_refs,blockers,checkpoint_refs,next_step,state,revision,time_budget_millis,cost_budget_micros,max_attempts,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) ON CONFLICT(investigation_id) DO NOTHING`, value.ID, value.Objective, hypotheses, attempts, findings, blockers, checkpoints, value.NextStep, value.State, value.Revision, value.TimeBudgetMillis, value.CostBudgetMicros, value.MaxAttempts, value.RecordedAtUnixMillis)
if err != nil {
return err
}
if result.RowsAffected() != 1 {
return errors.New("investigation already exists")
}
return nil
}
result, err := r.pool.Exec(ctx, `UPDATE work.long_running_work SET objective=$2,hypothesis_refs=$3,attempt_refs=$4,finding_refs=$5,blockers=$6,checkpoint_refs=$7,next_step=$8,state=$9,revision=$10,time_budget_millis=$11,cost_budget_micros=$12,max_attempts=$13,recorded_at_unix_millis=$14 WHERE investigation_id=$1 AND revision=$15`, value.ID, value.Objective, hypotheses, attempts, findings, blockers, checkpoints, value.NextStep, value.State, value.Revision, value.TimeBudgetMillis, value.CostBudgetMicros, value.MaxAttempts, value.RecordedAtUnixMillis, expectedRevision)
if err != nil {
return err
}
if result.RowsAffected() != 1 {
return errors.New("investigation revision conflict")
}
return nil
}
func (r *WorkRepository) LoadInvestigation(ctx context.Context, id work.LongRunningWorkID) (work.Investigation, error) {
var value work.Investigation
var hypotheses, attempts, findings, blockers, checkpoints []string
err := r.pool.QueryRow(ctx, `SELECT investigation_id,objective,hypothesis_refs,attempt_refs,finding_refs,blockers,checkpoint_refs,next_step,state,revision,time_budget_millis,cost_budget_micros,max_attempts,recorded_at_unix_millis FROM work.long_running_work WHERE investigation_id=$1`, id).Scan(&value.ID, &value.Objective, &hypotheses, &attempts, &findings, &blockers, &checkpoints, &value.NextStep, &value.State, &value.Revision, &value.TimeBudgetMillis, &value.CostBudgetMicros, &value.MaxAttempts, &value.RecordedAtUnixMillis)
if err != nil {
return work.Investigation{}, fmt.Errorf("load investigation: %w", err)
}
for _, item := range hypotheses {
value.HypothesisRefs = append(value.HypothesisRefs, work.EvidenceRef(item))
}
for _, item := range attempts {
value.AttemptRefs = append(value.AttemptRefs, work.AgentRunID(item))
}
for _, item := range findings {
value.FindingRefs = append(value.FindingRefs, work.EvidenceRef(item))
}
value.Blockers = append(value.Blockers, blockers...)
for _, item := range checkpoints {
value.CheckpointRefs = append(value.CheckpointRefs, work.AgentCheckpointID(item))
}
return value, nil
}
// SaveInvestigationCheckpoint atomically records the checkpoint and marks its
// attempts verified. The unique key makes retries idempotent.
func (r *WorkRepository) SaveInvestigationCheckpoint(ctx context.Context, checkpoint work.InvestigationCheckpoint) error {
if !checkpoint.Valid() {
return errors.New("invalid investigation checkpoint")
}
tx, err := r.pool.Begin(ctx)
if err != nil {
return err
}
defer tx.Rollback(ctx)
if _, err = tx.Exec(ctx, `INSERT INTO work.investigation_checkpoints(checkpoint_id,investigation_id,completed_attempt_refs,completed_finding_refs,next_step,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6) ON CONFLICT(checkpoint_id) DO NOTHING`, checkpoint.ID, checkpoint.InvestigationID, stringIDs(checkpoint.CompletedAttemptRefs), stringEvidence(checkpoint.CompletedFindingRefs), checkpoint.NextStep, checkpoint.RecordedAtUnixMillis); err != nil {
return err
}
for _, attempt := range checkpoint.CompletedAttemptRefs {
if _, err = tx.Exec(ctx, `INSERT INTO work.investigation_attempts(investigation_id,attempt_ref,verified_at_unix_millis) VALUES($1,$2,$3) ON CONFLICT(investigation_id,attempt_ref) DO NOTHING`, checkpoint.InvestigationID, attempt, checkpoint.RecordedAtUnixMillis); err != nil {
return err
}
}
return tx.Commit(ctx)
}
func (r *WorkRepository) UnverifiedInvestigationAttempts(ctx context.Context, id work.LongRunningWorkID, candidates []work.AgentRunID) ([]work.AgentRunID, error) {
result := make([]work.AgentRunID, 0, len(candidates))
for _, candidate := range candidates {
var exists bool
if err := r.pool.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM work.investigation_attempts WHERE investigation_id=$1 AND attempt_ref=$2)`, id, candidate).Scan(&exists); err != nil {
return nil, err
}
if !exists {
result = append(result, candidate)
}
}
return result, nil
}
func stringIDs(values []work.AgentRunID) []string {
result := make([]string, 0, len(values))
for _, value := range values {
result = append(result, string(value))
}
return result
}
func stringEvidence(values []work.EvidenceRef) []string {
result := make([]string, 0, len(values))
for _, value := range values {
result = append(result, string(value))
}
return result
}
func OpenWork(ctx context.Context, config ContinuityConfig) (*WorkRepository, error) {
pool, err := openPool(ctx, config)
if err != nil {
+108
View File
@@ -0,0 +1,108 @@
package postgres
import (
"context"
"encoding/json"
"fmt"
"git.cin.su/m/Assistant/contracts/world"
worlddomain "git.cin.su/m/Assistant/modules/world/domain"
"github.com/jackc/pgx/v5/pgxpool"
)
type WorldRepository struct{ pool *pgxpool.Pool }
func OpenWorld(ctx context.Context, config ContinuityConfig) (*WorldRepository, error) {
pool, err := openPool(ctx, config)
if err != nil {
return nil, err
}
return &WorldRepository{pool: pool}, nil
}
func (r *WorldRepository) Close() { r.pool.Close() }
func (r *WorldRepository) SaveKindDefinition(ctx context.Context, value world.WorldObjectKindDefinition) error {
if err := worlddomain.ValidateKindDefinition(value); err != nil {
return err
}
var parentOwner, parentKind, parentID string
var parentRevision *uint64
if value.ParentKindRef != nil {
parentOwner, parentKind, parentID = value.ParentKindRef.OwnerNamespace, value.ParentKindRef.SemanticKind, string(value.ParentKindRef.StableID)
if value.ParentKindRef.Revision != nil {
revision := uint64(*value.ParentKindRef.Revision)
parentRevision = &revision
}
}
_, err := r.pool.Exec(ctx, `INSERT INTO world.kind_definitions(kind_definition_id,kind_key,revision,display_name,parent_owner_namespace,parent_semantic_kind,parent_stable_id,parent_revision,lifecycle,definition_digest,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11) ON CONFLICT(kind_definition_id) DO NOTHING`, value.ID, value.KindKey, value.Revision, value.DisplayName, parentOwner, parentKind, parentID, parentRevision, value.Lifecycle, value.DefinitionDigest, value.RecordedAt)
return err
}
func (r *WorldRepository) SaveObject(ctx context.Context, value world.WorldObject) error {
if err := worlddomain.ValidateObject(value); err != nil {
return err
}
_, err := r.pool.Exec(ctx, `INSERT INTO world.objects(world_object_id,principal_id,kind_owner_namespace,kind_semantic_kind,kind_stable_id,kind_revision,lifecycle,created_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7,$8) ON CONFLICT(world_object_id) DO NOTHING`, value.ID, value.PrincipalID, value.KindDefinitionRef.OwnerNamespace, value.KindDefinitionRef.SemanticKind, value.KindDefinitionRef.StableID, value.KindRevision, value.Lifecycle, value.CreatedAt)
return err
}
func (r *WorldRepository) SaveAlias(ctx context.Context, value world.WorldAlias) error {
if err := worlddomain.ValidateAlias(value); err != nil {
return err
}
_, err := r.pool.Exec(ctx, `INSERT INTO world.aliases(world_alias_id,principal_id,world_object_id,alias,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5) ON CONFLICT(world_alias_id) DO NOTHING`, value.ID, value.PrincipalID, value.ObjectID, value.Alias, value.RecordedAt)
return err
}
func (r *WorldRepository) SaveFacetDefinition(ctx context.Context, value world.FacetDefinition) error {
if err := worlddomain.ValidateFacetDefinition(value); err != nil {
return err
}
payload, err := json.Marshal(value.ValueType)
if err != nil {
return fmt.Errorf("encode facet value type: %w", err)
}
_, err = r.pool.Exec(ctx, `INSERT INTO world.facet_definitions(facet_definition_id,kind_key,revision,facet_key,value_type,definition_digest,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7) ON CONFLICT(facet_definition_id) DO NOTHING`, value.ID, value.KindKey, value.Revision, value.FacetKey, payload, value.DefinitionDigest, value.RecordedAt)
return err
}
func (r *WorldRepository) SaveRelationDefinition(ctx context.Context, value world.RelationDefinition) error {
if err := worlddomain.ValidateRelationDefinition(value); err != nil {
return err
}
_, err := r.pool.Exec(ctx, `INSERT INTO world.relation_definitions(relation_definition_id,kind_key,revision,relation_key,target_kind_key,definition_digest,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5,$6,$7) ON CONFLICT(relation_definition_id) DO NOTHING`, value.ID, value.KindKey, value.Revision, value.RelationKey, value.TargetKindKey, value.DefinitionDigest, value.RecordedAt)
return err
}
func (r *WorldRepository) SaveResolution(ctx context.Context, value world.IdentityResolutionDecisionRecord) error {
if err := worlddomain.ValidateResolution(value); err != nil {
return err
}
candidates, err := json.Marshal(value.Candidates)
if err != nil {
return fmt.Errorf("encode resolution candidates: %w", err)
}
evidence, err := json.Marshal(value.Evidence)
if err != nil {
return fmt.Errorf("encode resolution evidence: %w", err)
}
_, err = r.pool.Exec(ctx, `INSERT INTO world.identity_resolution_decisions(resolution_decision_id,principal_id,candidates,decision,evidence,confidence_millis,decided_at_unix_millis,revision) VALUES($1,$2,$3,$4,$5,$6,$7,$8) ON CONFLICT(resolution_decision_id) DO NOTHING`, value.ID, value.PrincipalID, candidates, value.Decision, evidence, value.ConfidenceMillis, value.DecidedAt, value.Revision)
return err
}
func (r *WorldRepository) SaveLineage(ctx context.Context, value world.WorldLineage) error {
if err := worlddomain.ValidateLineage(value); err != nil {
return err
}
sources, err := json.Marshal(value.SourceRefs)
if err != nil {
return fmt.Errorf("encode lineage sources: %w", err)
}
successors, err := json.Marshal(value.SuccessorRefs)
if err != nil {
return fmt.Errorf("encode lineage successors: %w", err)
}
_, err = r.pool.Exec(ctx, `INSERT INTO world.lineage(lineage_id,operation,source_refs,successor_refs,recorded_at_unix_millis) VALUES($1,$2,$3,$4,$5) ON CONFLICT(lineage_id) DO NOTHING`, value.ID, value.Operation, sources, successors, value.RecordedAt)
return err
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,45 @@
# ADR-0020 — Architecture Generation 2 governance adoption
**Status:** Accepted by `ARCH-GEN2-000`
**Date:** 2026-08-29
**Scope:** Architecture and governance only; no runtime or schema migration.
## Decision
Assistant adopts the documents under `docs/DOMOVOY_CONSTITUTION.md`,
`architecture/GEN2_TARGET_ARCHITECTURE.md`,
`architecture/GEN2_CANONICAL_DATA_MODEL.md`,
`development/GEN2_MIGRATION_MAP.md`,
`development/GEN2_MASTER_PLAN.md`, and the execution contract as the
canonical Architecture Generation 2 governance basis.
The existing V1 implementation remains the rollback and compatibility
baseline. This decision authorizes subsequent, separately accepted Gen2
packets to introduce the World, Configuration, and SELF bounded owners and
Gen2 migrations, subject to explicit ownership, schema, contract, and
rollback decisions in those packets. It does not create those owners or
change canonical runtime state in this task.
## Authority and execution order
The Gen2 constitution and accepted architecture decisions govern the Gen2
program. The target architecture, canonical data model, migration map,
master plan, execution contract, task index, and individual task packet are
interpreted in that order. A lower-level packet cannot silently weaken a
higher-level invariant or reorder the task index.
Every Gen2 task starts from `gen2-integration`, uses the active task pointer,
and passes the declared FAST/MILESTONE/FULL gate before merge. `ARCH-GEN2-000`
is the architecture adoption root accepted against the PRE baseline;
`GEN2-001` and later tasks are not accepted by this decision and require
separate execution.
## Invariants preserved
- No new canonical owner, cross-module dependency, privilege, database role,
third-party dependency, runtime writer, event, or migration is introduced.
- Existing Authority → Commit → Executor boundaries remain mandatory.
- Memory remains a rebuildable retrieval fabric, World is not a generic truth
owner, and SELF is not a monolithic orchestrator.
- The `domovoy-pre-gen2` baseline tag remains immutable and is the rollback
point until a later migration task explicitly establishes another one.
+53 -1
View File
@@ -1,7 +1,7 @@
{
"registry_version": 1,
"semantic_generation": 1,
"architecture_generation": 1,
"architecture_generation": 2,
"modules": {
"identity": {
"id": "mod.identity",
@@ -179,6 +179,30 @@
"database_schema": "interaction",
"boundary_class": "remote_capable",
"may_depend_on": ["contracts.identity", "contracts.situation", "contracts.epistemics", "contracts.cognitive", "platform.ids", "platform.events"]
},
"world": {
"id": "mod.world",
"owns": ["WorldObject", "WorldObjectKindDefinition", "WorldAlias", "FacetDefinition", "RelationDefinition", "IdentityResolutionCandidate", "IdentityResolutionDecision", "WorldLineage"],
"database_schema": "world",
"boundary_class": "remote_capable",
"may_depend_on": ["contracts.identity", "platform.ids", "platform.events"],
"forbidden": ["adapters.models", "adapters.temporal", "claims", "beliefs", "observations"]
},
"configuration": {
"id": "mod.configuration",
"owns": ["SettingDefinition", "SettingAssignment", "ConfigurationRevision", "ConfigurationChangeProvenance"],
"database_schema": "configuration",
"boundary_class": "remote_capable",
"may_depend_on": ["contracts.identity", "contracts.authority", "platform.ids", "platform.events", "platform.secrets"],
"forbidden": ["secret_values", "arbitrary_key_value_without_definition"]
},
"self": {
"id": "mod.self",
"owns": ["CompetenceAssessment", "WeaknessPattern", "DependencyAssessment", "LearningLedgerEntry", "ImprovementNeed", "SelfVersionView", "SelfEvaluationInterpretation"],
"database_schema": "self",
"boundary_class": "remote_capable",
"may_depend_on": ["contracts.capability", "contracts.epistemics", "contracts.artifact", "platform.ids", "platform.events"],
"forbidden": ["adapters.models", "tasks", "authority_grants", "code_release_switching"]
}
},
"platform": {
@@ -244,6 +268,26 @@
"cross_owner_write": "forbidden",
"cross_owner_application_join": "forbidden"
},
"runtime_topology_v2": {
"core_runtime": {
"modules": ["identity", "situation", "work", "epistemics", "capability", "artifact", "interaction", "world", "configuration", "self"]
},
"continuity_runtime": {"modules": ["continuity"]},
"commit_runtime": {"modules": ["authority", "commit"]},
"cognitive_workers": {"modules": [], "role": "replaceable reasoning/context workers; no canonical ownership"},
"supervisor_runtime": {"modules": [], "role": "release health, switch, rollback and recovery; not a semantic owner"}
},
"storage_topology_v2": {
"postgres_cluster": "assistant_primary",
"schemas": {
"identity": "identity_role", "authority": "authority_role", "situation": "situation_role", "work": "work_role",
"epistemics": "epistemics_role", "continuity": "continuity_role", "capability": "capability_role", "commit": "commit_role",
"artifact": "artifact_role", "interaction": "interaction_role", "world": "world_role", "configuration": "configuration_role", "self": "self_role"
},
"cross_owner_fk": "forbidden_by_default",
"cross_owner_write": "forbidden",
"cross_owner_application_join": "forbidden"
},
"invariants": [
{
"id": "INV-AUTH-001",
@@ -309,6 +353,14 @@
".gitea/workflows/ci.yml",
"cmd/devctl/**",
"dev/ACTIVE_TASK.json",
"docs/DOMOVOY_CONSTITUTION.md",
"docs/DOMOVOY_GEN2_GAP_MAP.md",
"architecture/GEN2_TARGET_ARCHITECTURE.md",
"architecture/GEN2_CANONICAL_DATA_MODEL.md",
"development/GEN2_MIGRATION_MAP.md",
"development/GEN2_MASTER_PLAN.md",
"development/GEN2_EXECUTION_CONTRACT.md",
"development/GEN2_TASK_INDEX.md",
"security/**"
],
"default_feature_task_authority": {
+67 -1
View File
@@ -1,6 +1,6 @@
registry_version: 1
semantic_generation: 1
architecture_generation: 1
architecture_generation: 2
modules:
identity:
@@ -75,6 +75,30 @@ modules:
boundary_class: remote_capable
may_depend_on: [contracts.identity, contracts.situation, contracts.epistemics, contracts.cognitive, platform.ids, platform.events]
world:
id: mod.world
owns: [WorldObject, WorldObjectKindDefinition, WorldAlias, FacetDefinition, RelationDefinition, IdentityResolutionCandidate, IdentityResolutionDecision, WorldLineage]
database_schema: world
boundary_class: remote_capable
may_depend_on: [contracts.identity, platform.ids, platform.events]
forbidden: [adapters.models, adapters.temporal, claims, beliefs, observations]
configuration:
id: mod.configuration
owns: [SettingDefinition, SettingAssignment, ConfigurationRevision, ConfigurationChangeProvenance]
database_schema: configuration
boundary_class: remote_capable
may_depend_on: [contracts.identity, contracts.authority, platform.ids, platform.events, platform.secrets]
forbidden: [secret_values, arbitrary_key_value_without_definition]
self:
id: mod.self
owns: [CompetenceAssessment, WeaknessPattern, DependencyAssessment, LearningLedgerEntry, ImprovementNeed, SelfVersionView, SelfEvaluationInterpretation]
database_schema: self
boundary_class: remote_capable
may_depend_on: [contracts.capability, contracts.epistemics, contracts.artifact, platform.ids, platform.events]
forbidden: [adapters.models, tasks, authority_grants, code_release_switching]
platform:
allowed_packages:
- platform.ids
@@ -98,6 +122,20 @@ runtime_topology_v1:
modules: []
role: "replaceable cognition/context compilation workers; no canonical ownership"
runtime_topology_v2:
core_runtime:
modules: [identity, situation, work, epistemics, capability, artifact, interaction, world, configuration, self]
continuity_runtime:
modules: [continuity]
commit_runtime:
modules: [authority, commit]
cognitive_workers:
modules: []
role: "replaceable reasoning/context workers; no canonical ownership"
supervisor_runtime:
modules: []
role: "release health, switch, rollback and recovery; not a semantic owner"
storage_topology_v1:
postgres_cluster: assistant_primary
schemas:
@@ -115,6 +153,26 @@ storage_topology_v1:
cross_owner_write: forbidden
cross_owner_application_join: forbidden
storage_topology_v2:
postgres_cluster: assistant_primary
schemas:
identity: identity_role
authority: authority_role
situation: situation_role
work: work_role
epistemics: epistemics_role
continuity: continuity_role
capability: capability_role
commit: commit_role
artifact: artifact_role
interaction: interaction_role
world: world_role
configuration: configuration_role
self: self_role
cross_owner_fk: forbidden_by_default
cross_owner_write: forbidden
cross_owner_application_join: forbidden
invariants:
- id: INV-AUTH-001
property: "No external mutation without current valid authority and target/revision checks"
@@ -149,6 +207,14 @@ protected_paths:
- .gitea/workflows/ci.yml
- cmd/devctl/**
- dev/ACTIVE_TASK.json
- docs/DOMOVOY_CONSTITUTION.md
- docs/DOMOVOY_GEN2_GAP_MAP.md
- architecture/GEN2_TARGET_ARCHITECTURE.md
- architecture/GEN2_CANONICAL_DATA_MODEL.md
- development/GEN2_MIGRATION_MAP.md
- development/GEN2_MASTER_PLAN.md
- development/GEN2_EXECUTION_CONTRACT.md
- development/GEN2_TASK_INDEX.md
- security/**
default_feature_task_authority:
+8 -2
View File
@@ -67,12 +67,18 @@ func (g cognitiveGateway) interpretationHandler(w http.ResponseWriter, r *http.R
}
g.observe(r.Context(), selected, response, started)
if response.FinishReason != cognitive.FinishCompleted {
writeInterpretationResponse(w, cognitive.GatewayInterpretationResponse{Version: request.Version, RequestID: request.RequestID, FinishReason: response.FinishReason, Usage: response.Usage})
// A selected provider can become unavailable after discovery. Semantic
// routing must still retain the deterministic interpretation and use the
// local lifeboat rather than turn an ordinary conversation into a
// degraded reply solely because one provider failed.
writeInterpretationResponse(w, g.interpretWithBuiltin(r.Context(), request, maxOutputBytes))
return
}
candidate, ok := parseInterpretationCandidate(response.AdvisoryText)
if !ok {
writeInterpretationResponse(w, cognitive.GatewayInterpretationResponse{Version: request.Version, RequestID: request.RequestID, FinishReason: cognitive.FinishInvalidStructuredOutput, Usage: response.Usage})
// Structured interpretation is a transport contract. A malformed model
// answer is not a reason to discard the available local fallback.
writeInterpretationResponse(w, g.interpretWithBuiltin(r.Context(), request, maxOutputBytes))
return
}
writeInterpretationResponse(w, cognitive.GatewayInterpretationResponse{Version: request.Version, RequestID: request.RequestID, Candidate: candidate, FinishReason: cognitive.FinishCompleted, Usage: response.Usage})
@@ -1,9 +1,15 @@
package main
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"git.cin.su/m/Assistant/contracts/capability"
"git.cin.su/m/Assistant/contracts/cognitive"
)
@@ -24,3 +30,32 @@ func TestBuiltinInterpretationTimeoutRetainsDeterministicCandidate(t *testing.T)
t.Fatalf("candidate did not retain deterministic meaning: %+v", response.Candidate)
}
}
func TestInterpretationProviderFailureUsesLocalLifeboat(t *testing.T) {
selected := gatewaySelection()
selected.Binding.DataPolicy = capability.DataPolicyLocalOnly
primary := &stubAdvisoryProvider{response: cognitive.AdvisoryResponse{FinishReason: cognitive.FinishProviderUnavailable}}
lifeboat := &stubAdvisoryProvider{response: cognitive.AdvisoryResponse{AdvisoryText: `{"primary_speech_act":"QUESTION","secondary_speech_act":"","confidence_millis":900,"applicability":"APPLICABLE","requested_outcome":"","needs_cognition":true,"clarification":"NOT_REQUIRED","selection_reason":"local lifeboat","capability_hints":["COGNITIVE_REASONING"]}`, FinishReason: cognitive.FinishCompleted}}
gateway := cognitiveGateway{
resolver: &registryStub{selected: selected},
providers: map[capability.ProviderKind][]providerRegistration{
selected.Provider.Kind: {{ProviderInstanceID: selected.Provider.ID, Kind: selected.Provider.Kind, Provider: primary}},
},
builtinLocal: &providerRegistration{Provider: lifeboat},
now: time.Now,
}
request := cognitive.GatewayInterpretationRequest{Version: cognitive.CreatorAdvisoryV1, RequestID: "request-1", ActorID: "actor-1", PrincipalID: "principal-1", ScopeID: "scope-1", Message: "сколько фигур в шахматах?", Locale: "ru", MaxOutputBytes: 4096, DataPolicy: capability.DataPolicyLocalOnly, DeterministicSpeechAct: "QUESTION", DeterministicConfidence: 800, DeterministicApplicability: cognitive.InterpretationApplicable}
payload, _ := json.Marshal(request)
recorder := httptest.NewRecorder()
gateway.interpretationHandler(recorder, httptest.NewRequest(http.MethodPost, "/v1/interpretations", bytes.NewReader(payload)))
if recorder.Code != http.StatusOK || !primary.called || !lifeboat.called {
t.Fatalf("status=%d primary=%t lifeboat=%t body=%s", recorder.Code, primary.called, lifeboat.called, recorder.Body.String())
}
var response cognitive.GatewayInterpretationResponse
if err := json.Unmarshal(recorder.Body.Bytes(), &response); err != nil {
t.Fatal(err)
}
if response.FinishReason != cognitive.FinishCompleted || response.Candidate.SelectionReason != "local lifeboat" {
t.Fatalf("response=%+v", response)
}
}
+37 -1
View File
@@ -2,6 +2,7 @@ package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
@@ -38,7 +39,8 @@ func (g multimodalGateway) handler(operation capability.MultimodalOperation) htt
http.Error(w, "local image generation capability unavailable", http.StatusBadGateway)
return
}
image, err := g.imageGenerator.Generate(r.Context(), g.imageModel, r.FormValue("prompt"), r.FormValue("size"))
prompt := r.FormValue("prompt")
image, err := g.imageGenerator.Generate(r.Context(), g.imageModel, prompt, imageRequestSize(prompt, r.FormValue("size")))
if err != nil || strings.TrimSpace(image.DataBase64) == "" {
logMultimodalFailure(operation, err)
http.Error(w, "local image generation capability unavailable", http.StatusBadGateway)
@@ -96,6 +98,40 @@ func (g multimodalGateway) handler(operation capability.MultimodalOperation) htt
}
}
// imageRequestSize is a transport-level normalization for the local image
// capability. An explicit, valid size always wins. When the caller only
// expresses a conventional output-quality target, the capability translates it
// to a supported provider size without exposing provider workflow details to
// the interaction core. This policy is deliberately local and replaceable
// with the image capability implementation.
func imageRequestSize(prompt, requested string) string {
if isImageSize(requested) {
return strings.TrimSpace(requested)
}
words := strings.Fields(strings.ToLower(prompt))
for index, word := range words {
switch word {
case "4k", "uhd":
return "2048x2048"
case "hd":
return "1024x1024"
case "ultra":
if index+1 < len(words) && words[index+1] == "hd" {
return "2048x2048"
}
}
}
return ""
}
func isImageSize(value string) bool {
var width, height int
if _, err := fmt.Sscanf(strings.TrimSpace(value), "%dx%d", &width, &height); err != nil {
return false
}
return width >= 256 && height >= 256 && width <= 2048 && height <= 2048
}
func logMultimodalFailure(operation capability.MultimodalOperation, err error) {
// Keep provider details in server diagnostics; never return them to chat.
log.Printf("multimodal operation %s failed: %v", operation, err)
+21
View File
@@ -47,6 +47,27 @@ func TestMultimodalImageGenerationFailsClosedWhenSkillIsUnbound(t *testing.T) {
}
}
func TestImageRequestSizeUsesExplicitSizeOrQualityTarget(t *testing.T) {
for _, test := range []struct {
name string
prompt string
requested string
want string
}{
{name: "explicit", prompt: "нарисуй птицу", requested: "768x512", want: "768x512"},
{name: "hd", prompt: "нарисуй птицу в HD", want: "1024x1024"},
{name: "uhd", prompt: "draw a bird in UHD", want: "2048x2048"},
{name: "ordinary", prompt: "нарисуй птицу", want: ""},
{name: "invalid explicit", prompt: "нарисуй птицу", requested: "100x100", want: ""},
} {
t.Run(test.name, func(t *testing.T) {
if got := imageRequestSize(test.prompt, test.requested); got != test.want {
t.Fatalf("imageRequestSize(%q, %q) = %q, want %q", test.prompt, test.requested, got, test.want)
}
})
}
}
func TestMultimodalVideoUnderstandingFailsClosedWhenSkillIsUnbound(t *testing.T) {
server := multimodalGateway{now: time.Now}
request := multipartRequest(t, "/v1/multimodal/video-understand", "clip.mp4", []byte("video"))
+8
View File
@@ -72,3 +72,11 @@ func hasChatRoute(routes []chatRoute, kind chatRouteKind) bool {
}
return false
}
// specializedRouteBypassesGeneralInterpretation keeps a concrete capability
// route stable. General cognition may still be used later to assess evidence,
// but it must not replace an executable research or media route with a vague
// conversational clarification before the capability is attempted.
func specializedRouteBypassesGeneralInterpretation(routes []chatRoute) bool {
return hasChatRoute(routes, chatRouteMedia) || hasChatRoute(routes, chatRouteResearch)
}
@@ -39,3 +39,15 @@ func TestBuildChatRoutePlanAlwaysKeepsLocalConversationRoute(t *testing.T) {
t.Fatalf("unexpected local route: %+v", planned)
}
}
func TestSpecializedRouteBypassesGeneralInterpretation(t *testing.T) {
if !specializedRouteBypassesGeneralInterpretation([]chatRoute{{Kind: chatRouteResearch}}) {
t.Fatal("research route must execute before general cognition")
}
if !specializedRouteBypassesGeneralInterpretation([]chatRoute{{Kind: chatRouteMedia}}) {
t.Fatal("media route must execute before general cognition")
}
if specializedRouteBypassesGeneralInterpretation([]chatRoute{{Kind: chatRouteConversation}}) {
t.Fatal("conversation-only route must retain general cognition")
}
}
+55 -3
View File
@@ -31,19 +31,23 @@ type cognitiveInterpretationClient struct {
// ReviewResponse asks the cognitive gateway to turn a locally assembled draft
// into a natural answer. The draft remains the safe fallback when cognition is
// unavailable; the model does not mutate canonical state or execute actions.
func (c cognitiveInterpretationClient) ReviewResponse(ctx context.Context, session identity.CreatorSession, userMessage, draft string, meaning cognitive.TaskMeaning) (string, error) {
func (c cognitiveInterpretationClient) ReviewResponse(ctx context.Context, session identity.CreatorSession, userMessage, draft, personalMemory string, meaning cognitive.TaskMeaning) (string, error) {
requestID, err := ids.New()
if err != nil {
return "", err
}
prompt := "Ты редактор ответа Домового. Проверь черновик по смыслу и подготовь естественный ответ человеку. Учитывай весь запрос, включая недостающие параметры для конкретного результата. Если данных не хватает, задай один короткий полезный уточняющий вопрос, например откуда и куда ехать. Не выдавай поисковые сниппеты как выполненное действие и не показывай служебные URL поисковой выдачи. Сохрани проверяемые факты, названия источников, прямые ссылки и ограничения. Не выдумывай факты и не утверждай невыполненные действия. Верни только готовый ответ без разбора проверки, служебных слов и упоминания моделей. Если черновик уже адекватен, верни его без лишних добавлений.\n\nСообщение пользователя:\n" + userMessage + "\n\nЧерновик ответа:\n" + draft
prompt := "Ты редактор финального ответа Домового. Проверь черновик по смыслу и подготовь естественный ответ человеку. Учитывай весь запрос, включая недостающие параметры для конкретного результата. Если данных не хватает, задай один короткий полезный уточняющий вопрос, например откуда и куда ехать. Не выдавай поисковые сниппеты как выполненное действие и не показывай служебные URL поисковой выдачи. Сохрани проверяемые факты, названия источников, прямые ссылки и ограничения. Не выдумывай факты и не утверждай невыполненные действия. Сначала внутренне проверь, что ответ начинается с содержания, решающего вопрос. Не повторяй вопрос пользователя в качестве заголовка или вступления, если это не нужно для смысла. Представление, имя помощника, приветствие или предложение дополнительной помощи допустимы только если пользователь сам спросил об этом; иначе убери их. Верни только готовый ответ без разбора проверки, служебных слов и упоминания моделей. Если черновик уже адекватен, верни его без лишних добавлений.\n\nСообщение пользователя:\n" + userMessage + "\n\nЧерновик ответа:\n" + draft
context := []cognitive.ContextExcerpt{}
if strings.TrimSpace(personalMemory) != "" {
context = append(context, cognitive.ContextExcerpt{ID: "personal-memory", SourceKind: "derived-personal-memory", SourceID: "interaction:human-utterances", Revision: 1, Sensitivity: cognitive.SensitivityPrivateAllowed, Text: personalMemory})
}
target := *c.baseURL
target.Path = "/v1/advisories"
payload, err := json.Marshal(cognitive.GatewayAdvisoryRequest{
Version: cognitive.CreatorAdvisoryV1, RequestID: cognitive.RequestID(requestID),
ActorID: session.ActorID, PrincipalID: session.PrincipalID,
ScopeID: authority.ScopeID("domovoy-global-scope"), Message: prompt,
Locale: "ru", MaxOutputBytes: 2048, DataPolicy: capability.DataPolicyLocalOnly,
Context: context, Locale: "ru", MaxOutputBytes: 2048, DataPolicy: capability.DataPolicyLocalOnly,
Meaning: cognitive.TaskMeaning{
SpeechAct: "RESPONSE_REVIEW",
CapabilityHints: meaning.CapabilityHints,
@@ -78,6 +82,54 @@ func (c cognitiveInterpretationClient) ReviewResponse(ctx context.Context, sessi
return strings.TrimSpace(result.AdvisoryText), nil
}
// AnswerStableKnowledge asks the local cognitive route for a short answer to a
// non-current question only after evidence retrieval did not produce a usable
// result. The model decides whether its knowledge is stable enough; it must
// explicitly decline changing or source-dependent facts instead of guessing.
func (c cognitiveInterpretationClient) AnswerStableKnowledge(ctx context.Context, session identity.CreatorSession, userMessage, personalMemory string, meaning cognitive.TaskMeaning) (string, error) {
requestID, err := ids.New()
if err != nil {
return "", err
}
prompt := "Ты отвечаешь как Домовой на обычное сообщение пользователя. Сначала пойми цель: на вопрос дай короткий естественный ответ по устойчивому общеизвестному знанию, а безопасную просьбу создать текстовый или структурный результат выполни прямо в ответе. Начинай сразу с содержания и не представляйся, если пользователь не спросил об имени. Не называй модель или внутреннюю систему. Если истинность ответа зависит от текущего наблюдения, внешнего источника или инструмента, верни ровно NEEDS_VERIFIED_RESEARCH. Не придумывай факты и не утверждай выполнение внешнего действия.\n\nСообщение пользователя:\n" + userMessage
context := []cognitive.ContextExcerpt{}
if strings.TrimSpace(personalMemory) != "" {
context = append(context, cognitive.ContextExcerpt{ID: "personal-memory", SourceKind: "derived-personal-memory", SourceID: "interaction:human-utterances", Revision: 1, Sensitivity: cognitive.SensitivityPrivateAllowed, Text: personalMemory})
}
target := *c.baseURL
target.Path = "/v1/advisories"
payload, err := json.Marshal(cognitive.GatewayAdvisoryRequest{
Version: cognitive.CreatorAdvisoryV1, RequestID: cognitive.RequestID(requestID),
ActorID: session.ActorID, PrincipalID: session.PrincipalID, ScopeID: authority.ScopeID("domovoy-global-scope"),
Message: prompt, Context: context, Locale: "ru", MaxOutputBytes: 1024, DataPolicy: capability.DataPolicyLocalOnly,
Meaning: cognitive.TaskMeaning{SpeechAct: "STABLE_KNOWLEDGE_ANSWER", CapabilityHints: meaning.CapabilityHints, RequestedOutcome: meaning.RequestedOutcome, InformationRequestKind: meaning.InformationRequestKind, ConfidenceMillis: meaning.ConfidenceMillis},
})
if err != nil {
return "", err
}
request, err := http.NewRequestWithContext(ctx, http.MethodPost, target.String(), bytes.NewReader(payload))
if err != nil {
return "", err
}
request.Header.Set("Content-Type", "application/json")
response, err := c.client.Do(request)
if err != nil {
return "", err
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return "", fmt.Errorf("cognitive stable knowledge status %d", response.StatusCode)
}
var result cognitive.GatewayAdvisoryResponse
if err := json.NewDecoder(response.Body).Decode(&result); err != nil {
return "", err
}
if result.FinishReason != cognitive.FinishCompleted || strings.TrimSpace(result.AdvisoryText) == "" {
return "", fmt.Errorf("cognitive stable knowledge incomplete: %s", result.FinishReason)
}
return strings.TrimSpace(result.AdvisoryText), nil
}
func newCognitiveInterpretationClient(rawURL string, client *http.Client) (cognitiveInterpretationClient, error) {
base, err := url.Parse(rawURL)
if err != nil || base.Scheme == "" || base.Host == "" {
@@ -25,6 +25,12 @@ func TestReviewResponseUsesCognitiveGatewayAndReturnsOnlyDraftAnswer(t *testing.
if request.Message == "" || request.Meaning.SpeechAct == "" {
t.Fatalf("review request did not carry semantic context: %+v", request)
}
if !strings.Contains(request.Message, "ответ начинается с содержания") || !strings.Contains(request.Message, "Не повторяй вопрос пользователя") || !strings.Contains(request.Message, "только если пользователь сам спросил") {
t.Fatalf("review request lacks the conversational quality contract: %q", request.Message)
}
if len(request.Context) != 1 || !strings.Contains(request.Context[0].Text, "красный цвет") {
t.Fatalf("review request did not carry compact personal memory: %+v", request.Context)
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(cognitive.GatewayAdvisoryResponse{Version: cognitive.CreatorAdvisoryV1, RequestID: request.RequestID, AdvisoryText: "Меня зовут Дед. Я Домовой.", FinishReason: cognitive.FinishCompleted})
}))
@@ -33,7 +39,7 @@ func TestReviewResponseUsesCognitiveGatewayAndReturnsOnlyDraftAnswer(t *testing.
if err != nil {
t.Fatal(err)
}
reviewed, err := client.ReviewResponse(context.Background(), identity.CreatorSession{ActorID: "actor", PrincipalID: "principal"}, "кто ты?", "Я — Домовой.", cognitive.TaskMeaning{SpeechAct: "QUESTION"})
reviewed, err := client.ReviewResponse(context.Background(), identity.CreatorSession{ActorID: "actor", PrincipalID: "principal"}, "кто ты?", "Я — Домовой.", "Предпочтение пользователя (его сообщение): красный цвет", cognitive.TaskMeaning{SpeechAct: "QUESTION"})
if err != nil {
t.Fatal(err)
}
@@ -42,6 +48,28 @@ func TestReviewResponseUsesCognitiveGatewayAndReturnsOnlyDraftAnswer(t *testing.
}
}
func TestAnswerStableKnowledgeUsesLocalOnlyCognitiveRoute(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var request cognitive.GatewayAdvisoryRequest
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
t.Fatalf("decode stable knowledge request: %v", err)
}
if request.DataPolicy != capability.DataPolicyLocalOnly || request.Meaning.SpeechAct != "STABLE_KNOWLEDGE_ANSWER" {
t.Fatalf("unexpected stable knowledge request: %+v", request)
}
_ = json.NewEncoder(w).Encode(cognitive.GatewayAdvisoryResponse{Version: cognitive.CreatorAdvisoryV1, RequestID: request.RequestID, AdvisoryText: "Санкт-Петербург — город в России.", FinishReason: cognitive.FinishCompleted})
}))
defer server.Close()
client, err := newCognitiveInterpretationClient(server.URL, server.Client())
if err != nil {
t.Fatal(err)
}
answer, err := client.AnswerStableKnowledge(context.Background(), identity.CreatorSession{ActorID: "actor", PrincipalID: "principal"}, "Питер — это где?", "", cognitive.TaskMeaning{SpeechAct: "QUESTION"})
if err != nil || answer != "Санкт-Петербург — город в России." {
t.Fatalf("answer=%q err=%v", answer, err)
}
}
func TestGenerateImageUsesDedicatedCognitiveMediaRoute(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost || r.URL.Path != "/v1/multimodal/generate-image" {
@@ -0,0 +1,27 @@
package main
import (
"testing"
"git.cin.su/m/Assistant/contracts/interaction"
)
func TestSpecializedInformationReplyIsNotOverwrittenByResearch(t *testing.T) {
for _, kind := range []interaction.InformationRequestKind{
interaction.InformationRequestMemoryInventory,
interaction.InformationRequestCapabilityInventory,
interaction.InformationRequestCognitiveModelInventory,
interaction.InformationRequestCognitiveChannelStatus,
interaction.InformationRequestCognitiveRecovery,
} {
if shouldRunGeneralResearch(kind) {
t.Fatalf("specialized information request %q must bypass general research", kind)
}
}
if !shouldRunGeneralResearch(interaction.InformationRequestTimeDifference) {
t.Fatal("time difference must use the current-data research route")
}
if !shouldRunGeneralResearch("") {
t.Fatal("ordinary research requests must still use general research")
}
}
+359 -36
View File
@@ -120,7 +120,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
researchClient, err := newResearchRuntimeClient(envOr("RESEARCH_RUNTIME_URL", "http://research-runtime:8087"), &http.Client{Timeout: 12 * time.Second})
researchClient, err := newResearchRuntimeClient(envOr("RESEARCH_RUNTIME_URL", "http://research-runtime:8087"), &http.Client{Timeout: 20 * time.Second})
if err != nil {
log.Fatal(err)
}
@@ -511,6 +511,7 @@ func main() {
}
var effectiveTaskMessage = interactiondomain.StripAssistantVocative(utterance.Content)
creativeUserRequest := interactiondomain.IsCreativeRequest(utterance.Content)
locationReply := interactiondomain.LocationContextReply(utterance.Content)
continuationMessage := ""
travelContinuation := false
var previousTask *interaction.HumanUtterance
@@ -532,7 +533,8 @@ func main() {
log.Printf("interaction principal history loaded: %d utterances", len(recentUserHistory))
}
conversationHistory = append(conversationHistory, recentUserHistory...)
if !creativeUserRequest {
gen2Context := interactiondomain.BuildScopedGen2Context(conversationHistory, string(session.PrincipalID))
if !creativeUserRequest && locationReply == "" {
if continuation := interactiondomain.ContinueLocalSearch(effectiveTaskMessage, conversationHistory); continuation != "" {
continuationMessage = continuation
effectiveTaskMessage = continuation
@@ -540,6 +542,10 @@ func main() {
continuationMessage = continuation
travelContinuation = true
effectiveTaskMessage = continuation
} else if continuation := interactiondomain.ContinueTravelDate(effectiveTaskMessage, conversationHistory); continuation != "" {
continuationMessage = continuation
travelContinuation = true
effectiveTaskMessage = continuation
}
}
if request.ConversationID != "" && interactiondomain.IsRetryRequest(utterance.Content) {
@@ -566,7 +572,11 @@ func main() {
continuedSemantic, continuedErr := interactiondomain.InterpretUtterance(continuedUtterance, projects, previousFocus, now)
if continuedErr == nil {
continuedSemantic.Interpretation.Source = "CONVERSATION_CONTINUATION"
continuedSemantic.Interpretation.SelectionReason = "location follow-up completed the previous local-search task"
if travelContinuation {
continuedSemantic.Interpretation.SelectionReason = "travel follow-up completed the previous travel task"
} else {
continuedSemantic.Interpretation.SelectionReason = "location follow-up completed the previous local-search task"
}
semantic = continuedSemantic
}
}
@@ -599,8 +609,11 @@ func main() {
}
}
}
locationReply := interactiondomain.LocationContextReply(utterance.Content)
if locationReply != "" {
continuationMessage = ""
travelContinuation = false
effectiveTaskMessage = interactiondomain.StripAssistantVocative(utterance.Content)
previousTask = nil
semantic.Reply = locationReply
semantic.NeedsCognition = false
semantic.Interpretation.NeedsCognition = false
@@ -616,6 +629,7 @@ func main() {
assistantName = latestAssistantName(conversationHistory)
}
identityReply := ""
memoryInstructionReply := ""
log.Printf("interaction identity context: name=%q history=%d", assistantName, len(conversationHistory))
if interactiondomain.IsIdentityInquiry(utterance.Content) && assistantName != "" {
identityReply = "Меня зовут " + assistantName + ". Я Домовой, ваш помощник."
@@ -625,6 +639,14 @@ func main() {
semantic.Interpretation.Applicability = interaction.SemanticApplicable
semantic.Interpretation.Clarification = interaction.ClarificationNotRequired
}
if identityReply == "" && interactiondomain.IsExplicitMemoryInstruction(utterance.Content) {
memoryInstructionReply = "Запомнил."
semantic.Reply = memoryInstructionReply
semantic.NeedsCognition = false
semantic.CapabilityHints = nil
semantic.Interpretation.Applicability = interaction.SemanticApplicable
semantic.Interpretation.Clarification = interaction.ClarificationNotRequired
}
deterministicSpeechAct := semantic.Interpretation.SpeechAct
deterministicReply := semantic.Reply
routePlan := buildChatRoutePlan(semantic)
@@ -632,14 +654,14 @@ func main() {
cognitiveAvailable := true
semanticInterpretationRequested := shouldRequestSemanticInterpretation(semantic)
semanticReflexAudit := shouldAuditDeterministicReflex(semantic, string(utterance.ID), now)
// A selected specialized media route already has an executable semantic
// outcome. Do not block it on the general cognitive channel: image
// generation must reach its own adapter even when cognition is degraded.
if hasChatRoute(routePlan, chatRouteMedia) {
// A selected specialized route already has an executable semantic outcome.
// Do not block it on the general cognitive channel: research and image
// generation must reach their own adapters even when cognition is degraded.
if specializedRouteBypassesGeneralInterpretation(routePlan) {
semanticInterpretationRequested = false
semanticReflexAudit = false
}
if identityReply != "" {
if identityReply != "" || memoryInstructionReply != "" {
semanticReflexAudit = false
}
if semanticInterpretationRequested || semanticReflexAudit {
@@ -748,8 +770,8 @@ func main() {
case interaction.InformationRequestMemoryInventory:
planningReply = humanMemoryInventory(conversationHistory, assistantName)
needsCognition = false
case interaction.InformationRequestTimeDifference:
planningReply = humanTimeDifferenceReply(effectiveTaskMessage)
case interaction.InformationRequestResearchFailureExplanation:
planningReply = "Я не выдаю предположение как факт, если не получил согласованных проверяемых данных. Могу повторить поиск, уточнить запрос или проверить другой источник."
needsCognition = false
case interaction.InformationRequestCapabilityInventory:
kinds, err := capabilityRepository.AvailableCapabilityKinds(r.Context(), session.PrincipalID)
@@ -759,17 +781,27 @@ func main() {
planningReply = "Я умею общаться, сохранять контекст, искать проверяемую информацию и работать с подключёнными моделями. Дополнительные действия подключаются отдельно."
}
needsCognition = false
case interaction.InformationRequestLocalCapabilityInventory:
planningReply = "Без внешних моделей я могу поддерживать разговор, хранить контекст, вести цели и напоминания, а также честно сообщать состояние подключённых возможностей."
needsCognition = false
case interaction.InformationRequestCognitiveModelInventory:
candidates, inventoryErr := capabilityRepository.LoadCognitiveCandidates(r.Context(), capability.CapabilityID("creator-advisory"), session.PrincipalID)
planningReply = humanCognitiveModelInventory(candidates, inventoryErr)
needsCognition = false
case interaction.InformationRequestCognitiveCurrentModel:
health, healthErr := capabilityRepository.LoadHealth(r.Context(), capability.CapabilityID("cognitive-proposal"))
planningReply = humanCurrentCognitiveModelReply(health, healthErr)
needsCognition = false
case interaction.InformationRequestCognitiveChannelStatus, interaction.InformationRequestCognitiveRecovery:
health, healthErr := capabilityRepository.LoadHealth(r.Context(), capability.CapabilityID("cognitive-proposal"))
planningReply = humanCognitiveChannelReply(semantic.InformationRequestKind, semantic.Interpretation.SpeechAct, health, healthErr)
needsCognition = false
}
researchBacked := false
if hasChatRoute(routePlan, chatRouteResearch) && semantic.Interpretation.Clarification != interaction.ClarificationRequired {
researchAttempted := false
stableKnowledgeReply := false
if hasChatRoute(routePlan, chatRouteResearch) && semantic.Interpretation.Clarification != interaction.ClarificationRequired && shouldRunGeneralResearch(semantic.InformationRequestKind) {
researchAttempted = true
if planID, idErr := ids.New(); idErr == nil {
parts := interactiondomain.IndependentRequestParts(effectiveTaskMessage)
replies := make([]string, 0, len(parts))
@@ -778,14 +810,35 @@ func main() {
replies = append(replies, "По запросу «"+part+"»: "+clarification)
continue
}
searchQuery := interactiondomain.TravelSearchQuery(part, now)
researchCtx, cancelResearch := context.WithTimeout(r.Context(), 8*time.Second)
learnedLexicon := interactiondomain.TaskLexiconFromHistory(conversationHistory)
// Preserve the original utterance for semantic route compilation
// before removing a search imperative. Distance and route skills
// need the user's relation words (for example "до") to bind a
// remembered current location to the requested destination.
searchQuery := interactiondomain.TravelResearchQuery(part, conversationHistory, now)
searchQuery = interactiondomain.SearchQueryWithLexicon(searchQuery, learnedLexicon)
searchQuery = interactiondomain.TimeDifferenceResearchQuery(searchQuery)
// The research capability may try its configured source and a
// source-recovery fallback. Its caller must leave enough budget for
// both attempts and evidence evaluation.
researchCtx, cancelResearch := context.WithTimeout(r.Context(), 18*time.Second)
result, researchErr := researchClient.SearchWeb(researchCtx, epistemics.WebSearchRequest{
Plan: epistemics.ResearchPlan{ID: epistemics.ResearchPlanID(fmt.Sprintf("plan:%s:%d", planID, index)), Question: searchQuery, SourceClasses: []string{"web-search"}, FreshnessPolicy: "current"},
PropositionKey: fmt.Sprintf("question:%s:%d", utterance.ID, index), Query: searchQuery,
})
reply, backed := renderResearchReply(searchQuery, result, researchErr)
if !backed && cognitiveAvailable {
answerCtx, cancelAnswer := context.WithTimeout(r.Context(), 12*time.Second)
answer, answerErr := cognitiveClient.AnswerStableKnowledge(answerCtx, session, part, gen2Context.Text, cognitive.TaskMeaning{
SpeechAct: string(semantic.Interpretation.SpeechAct), CapabilityHints: toCapabilityKinds(semantic.CapabilityHints), RequestedOutcome: semantic.Interpretation.RequestedOutcome, InformationRequestKind: semantic.InformationRequestKind, ConfidenceMillis: semantic.Interpretation.ConfidenceMillis,
})
cancelAnswer()
if answerErr == nil && stableKnowledgeAnswer(answer) {
reply, backed = answer, true
stableKnowledgeReply = true
}
}
cancelResearch()
reply, backed := renderResearchReply(part, result, researchErr)
if backed {
researchBacked = true
}
@@ -813,6 +866,19 @@ func main() {
needsCognition = false
}
}
canGenerateTextReply := shouldGenerateNonMutatingTextDirective(semantic, routePlan, helpPath, creativeRequest) && planningReply == deterministicReply
if (planningReply == "" && needsCognition && semantic.Interpretation.SpeechAct == interaction.SpeechActQuestion || canGenerateTextReply) && !hasChatRoute(routePlan, chatRouteResearch) && !creativeRequest {
answerCtx, cancelAnswer := context.WithTimeout(r.Context(), 12*time.Second)
answer, answerErr := cognitiveClient.AnswerStableKnowledge(answerCtx, session, effectiveTaskMessage, gen2Context.Text, cognitive.TaskMeaning{
SpeechAct: string(semantic.Interpretation.SpeechAct), CapabilityHints: toCapabilityKinds(semantic.CapabilityHints), RequestedOutcome: semantic.Interpretation.RequestedOutcome, InformationRequestKind: semantic.InformationRequestKind, ConfidenceMillis: semantic.Interpretation.ConfidenceMillis,
})
cancelAnswer()
if answerErr == nil && stableKnowledgeAnswer(answer) {
planningReply = answer
stableKnowledgeReply = true
needsCognition = false
}
}
if planningReply == "" && needsCognition && cognitiveAttempted && !cognitiveAvailable {
planningReply = humanCognitiveDegradedReply(utterance.Content)
needsCognition = false
@@ -920,9 +986,13 @@ func main() {
planningReply = identityReply
needsCognition = false
}
if memoryInstructionReply != "" {
planningReply = memoryInstructionReply
needsCognition = false
}
if strings.TrimSpace(planningReply) != "" {
reviewContext, cancelReview := context.WithTimeout(r.Context(), 12*time.Second)
reviewedReply, reviewErr := cognitiveClient.ReviewResponse(reviewContext, session, utterance.Content, planningReply, cognitive.TaskMeaning{
reviewedReply, reviewErr := cognitiveClient.ReviewResponse(reviewContext, session, utterance.Content, planningReply, gen2Context.Text, cognitive.TaskMeaning{
SpeechAct: string(semantic.Interpretation.SpeechAct),
CapabilityHints: toCapabilityKinds(semantic.CapabilityHints),
RequestedOutcome: semantic.Interpretation.RequestedOutcome,
@@ -930,10 +1000,16 @@ func main() {
ConfidenceMillis: semantic.Interpretation.ConfidenceMillis,
})
cancelReview()
stableSemanticReply := mediaAttempted || identityReply != "" || creativeReply != "" || (creativeFallbackReply != "" && !cognitiveAvailable) || semantic.InformationRequestKind != "" || locationReply != "" || deterministicSpeechAct == interaction.SpeechActConversational || deterministicSpeechAct == interaction.SpeechActConfirmation || deterministicSpeechAct == interaction.SpeechActRejection
// A source-backed research result is owned by the research capability,
// but its wording is not canonical state. Let the cognitive editor turn
// it into a useful human answer while reviewPreservesResearchEvidence
// still requires the source evidence to remain present. Information
// requests without research (identity, channel state and so on) remain
// stable semantic replies and cannot be rewritten here.
stableSemanticReply := mediaAttempted || identityReply != "" || memoryInstructionReply != "" || creativeReply != "" || (creativeFallbackReply != "" && !cognitiveAvailable) || (semantic.InformationRequestKind != "" && !(researchAttempted && researchBacked)) || locationReply != "" || deterministicSpeechAct == interaction.SpeechActConversational || deterministicSpeechAct == interaction.SpeechActConfirmation || deterministicSpeechAct == interaction.SpeechActRejection
if reviewErr != nil {
log.Printf("cognitive response review unavailable: %v", reviewErr)
} else if !stableSemanticReply && (!researchBacked || reviewPreservesResearchEvidence(reviewedReply, planningReply)) {
} else if reviewMayReplacePlanningReply(stableSemanticReply, stableKnowledgeReply, researchAttempted, researchBacked, reviewedReply, planningReply) {
planningReply = reviewedReply
} else if reviewedReply != planningReply {
log.Printf("cognitive response review proposed stable semantic rewrite; preserving semantic reply")
@@ -955,6 +1031,11 @@ func main() {
needsCognition = false
planningReply = identityReply
}
if memoryInstructionReply != "" {
semantic.Reply = memoryInstructionReply
needsCognition = false
planningReply = memoryInstructionReply
}
if creativeReply != "" {
semantic.Reply = creativeReply
needsCognition = false
@@ -1589,6 +1670,10 @@ func main() {
}
}
func shouldRunGeneralResearch(kind interaction.InformationRequestKind) bool {
return kind == "" || kind == interaction.InformationRequestTimeDifference
}
func creatorSessionHandler(bootstrapToken, creatorUsername, creatorPassword string, sessionKey []byte, now func() time.Time) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
authenticated := identitydomain.BootstrapMatches(bootstrapToken, bearerToken(r))
@@ -1709,35 +1794,54 @@ func renderResearchReply(query string, result epistemics.ResearchResult, researc
return "Сейчас не удалось получить данные из подключённого источника. Попробую снова через доступный маршрут.", false
}
lines := make([]string, 0, 2)
for index, finding := range result.Findings {
for _, finding := range result.Findings {
if finding.State != epistemics.FindingSupported || strings.TrimSpace(finding.Excerpt.Text) == "" || strings.TrimSpace(finding.Source.Locator) == "" {
continue
}
if !researchFindingMatchesIntent(query, finding) {
continue
}
excerpt := humanResearchExcerpt(query, finding.Excerpt.Text)
limit := 180
if index > 0 {
if len(lines) > 0 {
limit = 100
}
if len([]rune(excerpt)) > limit {
excerpt = string([]rune(excerpt)[:limit]) + "…"
}
lines = append(lines, excerpt+"\nИсточник: "+researchSourceLabel(finding))
// A nearest-flight request needs one route-relevant schedule result.
// Appending weaker matches makes unrelated category pages look like
// alternatives even after the relevance check has accepted the route.
if nearestFlightQuery(query) {
break
}
if len(lines) == 2 {
break
}
}
if len(lines) == 0 {
if identifiers := requestedResearchIdentifiers(query); len(identifiers) > 0 {
return "Не нашёл проверяемых данных о «" + strings.Join(identifiers, "», «") + "». Возможно, название написано иначе; пришлите ссылку или уточните написание, и я проверю.", false
}
return "Проверяемых данных пока не найдено. Могу повторить поиск или уточнить, что именно проверить.", false
}
if isInternetStatusQuery(query) {
return "Интернет работает: Домовой получил ответ от внешнего источника.", true
}
if nearestFlightQuery(query) && !containsFlightTimeEvidence(strings.Join(lines, " ")) {
return "Нашёл расписание по маршруту, но точное время ближайшего вылета в доступных фрагментах не указано. Откройте источник и выберите ближайший рейс:\n\n" + strings.Join(lines, "\n\n"), true
}
reply := "Нашёл проверяемые данные:\n\n" + strings.Join(lines, "\n\n")
lowerQuery := strings.ToLower(query)
if (strings.Contains(lowerQuery, "цен") || strings.Contains(lowerQuery, "стоим")) && !containsPriceEvidence(reply) {
reply = "Актуальная цена в найденных фрагментах не указана, поэтому не буду придумывать сумму. Вот страницы, где её можно проверить:\n" + reply
if trainScheduleQuery(query) && !containsScheduleTimeEvidence(strings.Join(lines, " ")) {
return "Нашёл страницу расписания по маршруту, но в доступных фрагментах нет точного времени отправления:\n\n" + strings.Join(lines, "\n\n"), true
}
return reply, true
return "Нашёл проверяемые данные:\n\n" + strings.Join(lines, "\n\n"), true
}
func isInternetStatusQuery(query string) bool {
lower := strings.ToLower(query)
return (strings.Contains(lower, "интернет") || strings.Contains(lower, "сет")) &&
(strings.Contains(lower, "работает") || strings.Contains(lower, "доступ") || strings.Contains(lower, "проверь") || strings.Contains(lower, "связ"))
}
func nearestFlightQuery(query string) bool {
@@ -1745,6 +1849,170 @@ func nearestFlightQuery(query string) bool {
return strings.Contains(lower, "ближ") && (strings.Contains(lower, "рейс") || strings.Contains(lower, "самолет") || strings.Contains(lower, "самолёт") || strings.Contains(lower, "вылет"))
}
// researchFindingMatchesIntent is a final relevance check over evidence
// already obtained by the read-only research route. It prevents unrelated
// search-engine snippets from becoming a human-facing answer when a search
// term has a common non-travel meaning.
func researchFindingMatchesIntent(query string, finding epistemics.ResearchFinding) bool {
if !findingContainsRequestedIdentifier(query, finding) {
return false
}
if ticketSearchQuery(query) && !ticketFindingMatchesDestination(query, finding) {
return false
}
if distanceResearchQuery(query) && !containsDistanceEvidence(finding.Excerpt.Text) {
return false
}
if localPlaceSearchQuery(query) && !containsLocalPlaceEvidence(finding.Excerpt.Text) {
return false
}
if !nearestFlightQuery(query) {
return true
}
displayedExcerpt := strings.ToLower(humanResearchExcerpt(query, finding.Excerpt.Text))
travelEvidence := strings.Contains(displayedExcerpt, "рейс") ||
strings.Contains(displayedExcerpt, "вылет") ||
strings.Contains(displayedExcerpt, "авиабил") ||
strings.Contains(displayedExcerpt, "аэропорт") ||
strings.Contains(displayedExcerpt, "самолет") ||
strings.Contains(displayedExcerpt, "самолёт") ||
strings.Contains(displayedExcerpt, "расписан")
if !travelEvidence {
return false
}
routeTerms := nearestFlightRouteTerms(query)
if len(routeTerms) < 2 {
return true
}
// A route-looking URL or page title alone is not enough for a human-facing
// answer: the displayed excerpt itself must support both endpoints.
excerptEvidence := strings.ToLower(finding.Excerpt.Text)
for _, term := range routeTerms {
if !strings.Contains(excerptEvidence, term) {
return false
}
}
return true
}
func localPlaceSearchQuery(query string) bool {
lower := strings.ToLower(query)
return (strings.Contains(lower, "ресторан") || strings.Contains(lower, "кафе")) &&
(strings.Contains(lower, "адрес") || strings.Contains(lower, "отзыв") || strings.Contains(lower, "меню"))
}
func containsLocalPlaceEvidence(value string) bool {
lower := strings.ToLower(value)
for _, term := range []string{"ресторан", "кафе", "адрес", "меню", "отзыв", "кухн"} {
if strings.Contains(lower, term) {
return true
}
}
return false
}
func distanceResearchQuery(query string) bool {
lower := strings.ToLower(query)
return strings.Contains(lower, "расстоян") || strings.Contains(lower, "километр")
}
func containsDistanceEvidence(value string) bool {
return regexp.MustCompile(`(?i)\b\d[\d\s]*\s*(?:км|километр)`).MatchString(value)
}
func ticketSearchQuery(query string) bool {
return interactiondomain.TicketSearchDestination(query) != ""
}
func ticketFindingMatchesDestination(query string, finding epistemics.ResearchFinding) bool {
destination := strings.ToLower(interactiondomain.TicketSearchDestination(query))
if destination == "" {
return true
}
// The source title or URL may describe a category; human-facing proof must
// mention the requested destination in the actual displayed excerpt.
return strings.Contains(strings.ToLower(finding.Excerpt.Text), destination)
}
// findingContainsRequestedIdentifier prevents a generic landing page from
// being presented as a result for a concrete model, article or brand request.
// Identifiers are detected by their syntax, not by a catalogue of providers or
// entities, so the rule stays valid as user vocabulary changes.
func findingContainsRequestedIdentifier(query string, finding epistemics.ResearchFinding) bool {
identifiers := requestedResearchIdentifiers(query)
if len(identifiers) == 0 {
return true
}
evidence := strings.ToLower(strings.Join([]string{finding.Source.Title, finding.Source.Locator, finding.Excerpt.Text}, " "))
for _, identifier := range identifiers {
if !strings.Contains(evidence, strings.ToLower(identifier)) {
return false
}
}
return true
}
func requestedResearchIdentifiers(query string) []string {
rawIdentifiers := regexp.MustCompile(`(?i)[a-z0-9][a-z0-9._-]{3,}`).FindAllString(query, -1)
identifiers := make([]string, 0, len(rawIdentifiers))
exact := make([]string, 0, len(rawIdentifiers))
for _, identifier := range rawIdentifiers {
if researchDateIdentifier(identifier) {
continue
}
identifiers = append(identifiers, identifier)
if strings.ContainsAny(identifier, "._-") || strings.IndexFunc(identifier, func(r rune) bool { return r >= '0' && r <= '9' }) >= 0 {
exact = append(exact, identifier)
}
}
if len(exact) > 0 {
return exact
}
return identifiers
}
func researchDateIdentifier(value string) bool {
return regexp.MustCompile(`^\d{1,2}[.-]\d{1,2}[.-]\d{2,4}$`).MatchString(value) ||
regexp.MustCompile(`^\d{4}[.-]\d{1,2}[.-]\d{1,2}$`).MatchString(value)
}
// nearestFlightRouteTerms retains only the two endpoint-shaped terms from a
// structured flight search. It has no city or provider vocabulary: endpoint
// relevance is determined from the request itself.
func nearestFlightRouteTerms(query string) []string {
fields := regexp.MustCompile(`[\p{L}]{4,}`).FindAllString(strings.ToLower(query), -1)
ignored := []string{"ближай", "авиарейс", "сегодня", "самолет", "самолёт", "вылет", "рейс", "пункт", "отправлен"}
terms := make([]string, 0, 2)
for _, field := range fields {
skip := false
for _, prefix := range ignored {
if strings.HasPrefix(field, prefix) {
skip = true
break
}
}
if skip {
continue
}
prefixLength := 4
if len([]rune(field)) < prefixLength {
prefixLength = len([]rune(field))
}
term := string([]rune(field)[:prefixLength])
already := false
for _, current := range terms {
if current == term {
already = true
break
}
}
if !already {
terms = append(terms, term)
}
}
return terms
}
func containsFlightTimeEvidence(value string) bool {
return regexp.MustCompile(`(?m)\b(?:[01]?\d|2[0-3]):[0-5]\d\b`).MatchString(value)
}
@@ -1769,9 +2037,32 @@ func humanResearchExcerpt(query, raw string) string {
return text
}
func containsPriceEvidence(value string) bool {
pricePattern := regexp.MustCompile(`(?i)(\d[\d\s.,]{2,})(?:\s*(?:₽|руб\.?|р\.?|usd|\$|€))`)
return pricePattern.MatchString(value)
func trainScheduleQuery(query string) bool {
lower := strings.ToLower(query)
return strings.Contains(lower, "поезд") && strings.Contains(lower, "время отправления")
}
func containsScheduleTimeEvidence(value string) bool {
return regexp.MustCompile(`\b(?:[01]?\d|2[0-3]):[0-5]\d\b`).MatchString(value)
}
func stableKnowledgeAnswer(answer string) bool {
return strings.TrimSpace(answer) != "" && strings.TrimSpace(answer) != "NEEDS_VERIFIED_RESEARCH"
}
// shouldGenerateNonMutatingTextDirective identifies a request that can be
// completed entirely in the reply. It excludes specialized routes and durable
// work, so cognition can produce content but cannot stand in for an executor.
func shouldGenerateNonMutatingTextDirective(semantic interactiondomain.SemanticResult, routes []chatRoute, helpPath work.HelpPath, creativeRequest bool) bool {
if semantic.Interpretation.SpeechAct != interaction.SpeechActDirective || creativeRequest || helpPath.NeedsDurableWork {
return false
}
// ANSWER and COGNITION are reply-only help paths. They do not execute an
// external action, unlike direct capabilities, gaps or durable work.
if helpPath.Kind != work.HelpPathAnswer && helpPath.Kind != work.HelpPathCognition && helpPath.Kind != "" {
return false
}
return !hasChatRoute(routes, chatRouteResearch) && !hasChatRoute(routes, chatRouteMedia) && !hasChatRoute(routes, chatRouteAgent)
}
func reviewPreservesResearchEvidence(reviewed, draft string) bool {
@@ -1784,6 +2075,26 @@ func reviewPreservesResearchEvidence(reviewed, draft string) bool {
return true
}
// reviewMayReplacePlanningReply keeps ownership of a concrete capability
// result with that capability. A review may improve source-backed research,
// but must not turn an honest no-result into an invented clarification.
func reviewMayReplacePlanningReply(stableSemanticReply, stableKnowledgeReply, researchAttempted, researchBacked bool, reviewed, draft string) bool {
// A stable-knowledge answer is a model-produced draft rather than an owned
// capability result. It therefore goes through a second cognitive pass for
// conversational quality, while identity, memory, media and action outcomes
// remain immutable at this boundary.
if stableKnowledgeReply {
return true
}
if stableSemanticReply {
return false
}
if !researchAttempted {
return true
}
return researchBacked && reviewPreservesResearchEvidence(reviewed, draft)
}
func humanMemoryInventory(history []interaction.HumanUtterance, assistantName string) string {
rows := make([]string, 0, 4)
if assistantName != "" {
@@ -1826,14 +2137,6 @@ func latestAssistantName(history []interaction.HumanUtterance) string {
return latestName
}
func humanTimeDifferenceReply(message string) string {
lower := strings.ToLower(message)
if strings.Contains(lower, "моск") && strings.Contains(lower, "шанх") {
return "Шанхай опережает Москву на 5 часов. Если в Москве 12:00, в Шанхае 17:00."
}
return "Уточните два города — я сравню их часовые пояса."
}
func researchSourceLabel(finding epistemics.ResearchFinding) string {
title := strings.TrimSpace(finding.Source.Title)
locator := strings.TrimSpace(finding.Source.Locator)
@@ -2003,6 +2306,26 @@ func humanCognitiveChannelReply(kind interaction.InformationRequestKind, act int
}
}
// humanCurrentCognitiveModelReply answers about the route that produced this
// reply. It intentionally does not infer a provider/model name from health:
// that would claim a model was used when this direct status path did not call it.
func humanCurrentCognitiveModelReply(health capability.Health, healthErr error) string {
base := "Этот ответ сформирован встроенным режимом Домового; внешняя модель для него не использовалась."
if healthErr != nil {
return base + " Состояние канала мышления сейчас не удалось проверить."
}
switch health.State {
case capability.HealthAvailable:
return base + " Канал мышления доступен для следующих задач."
case capability.HealthDegraded:
return base + " Канал мышления работает с ограничениями."
case capability.HealthUnavailable:
return base + " Канал мышления сейчас недоступен."
default:
return base + " Состояние канала мышления пока не подтверждено."
}
}
func humanCognitiveDegradedReply(message string) string {
if strings.TrimSpace(message) == "" {
return "Сейчас не удалось обработать запрос."
+189 -5
View File
@@ -11,7 +11,9 @@ import (
"time"
"git.cin.su/m/Assistant/contracts/capability"
"git.cin.su/m/Assistant/contracts/epistemics"
"git.cin.su/m/Assistant/contracts/interaction"
"git.cin.su/m/Assistant/contracts/work"
interactiondomain "git.cin.su/m/Assistant/modules/interaction/domain"
)
@@ -34,6 +36,158 @@ func TestNearestFlightEvidenceDoesNotClaimMissingDepartureTime(t *testing.T) {
}
}
func TestNearestFlightReplyFiltersUnrelatedSearchSnippets(t *testing.T) {
result := epistemics.ResearchResult{Findings: []epistemics.ResearchFinding{
{State: epistemics.FindingSupported, Source: epistemics.Source{Locator: "https://naidy.example", Title: "Мебельная фурнитура"}, Excerpt: epistemics.SourceExcerpt{Text: "Комплектующие для мебели оптом и в розницу."}},
{State: epistemics.FindingSupported, Source: epistemics.Source{Locator: "https://rasp.example", Title: "Рейсы Москва — Казань"}, Excerpt: epistemics.SourceExcerpt{Text: "Расписание самолётов Москва — Казань, время вылета и прилёта."}},
}}
reply, backed := renderResearchReply("ближайшие авиарейсы Москва Казань сегодня", result, nil)
if !backed || !strings.Contains(reply, "Рейсы Москва") || strings.Contains(reply, "Мебельная") {
t.Fatalf("unrelated source leaked into flight reply: %q", reply)
}
}
func TestNearestFlightReplyDoesNotAppendWeakerSecondMatch(t *testing.T) {
result := epistemics.ResearchResult{Findings: []epistemics.ResearchFinding{
{State: epistemics.FindingSupported, Source: epistemics.Source{Locator: "https://schedule.example", Title: "Рейсы Москва — Казань"}, Excerpt: epistemics.SourceExcerpt{Text: "Расписание авиарейсов Москва — Казань, время вылета и прилёта."}},
{State: epistemics.FindingSupported, Source: epistemics.Source{Locator: "https://category.example", Title: "Категория направлений"}, Excerpt: epistemics.SourceExcerpt{Text: "Список близлежащих городов и ориентировочные цены."}},
}}
reply, backed := renderResearchReply("ближайшие авиарейсы Москва Казань сегодня", result, nil)
if !backed || !strings.Contains(reply, "Рейсы Москва") || strings.Contains(reply, "Категория направлений") {
t.Fatalf("weaker second finding leaked into nearest-flight reply: %q", reply)
}
}
func TestNearestFlightEvidenceRequiresBothRouteEndpointsWhenKnown(t *testing.T) {
query := "ближайшие авиарейсы Москва Казань сегодня"
matched := epistemics.ResearchFinding{Source: epistemics.Source{Title: "Рейсы Москва — Казань"}, Excerpt: epistemics.SourceExcerpt{Text: "Расписание авиарейсов из Москвы в Казань."}}
if !researchFindingMatchesIntent(query, matched) {
t.Fatal("route evidence with both endpoints was rejected")
}
unrelated := epistemics.ResearchFinding{Source: epistemics.Source{Title: "Рейсы Москва — Казань", Locator: "https://example.test/moscow-kazan"}, Excerpt: epistemics.SourceExcerpt{Text: "Рейсы Москва — Казань — Ближайшие к Казани города; цена указана ориентировочно."}}
if researchFindingMatchesIntent(query, unrelated) {
t.Fatal("one-ended travel evidence was accepted")
}
}
func TestTicketReplyRejectsGenericCategoryPageWithoutDestination(t *testing.T) {
query := "найди билеты до Ялты сегодня"
generic := epistemics.ResearchFinding{Source: epistemics.Source{Title: "Купить билеты", Locator: "https://tickets.example"}, Excerpt: epistemics.SourceExcerpt{Text: "Поиск авиабилетов среди множества направлений."}}
if researchFindingMatchesIntent(query, generic) {
t.Fatal("generic ticket category was presented as destination result")
}
relevant := epistemics.ResearchFinding{Source: epistemics.Source{Title: "Билеты"}, Excerpt: epistemics.SourceExcerpt{Text: "Билеты до Ялты: варианты на сегодня."}}
if !researchFindingMatchesIntent(query, relevant) {
t.Fatal("destination-specific ticket result was rejected")
}
}
func TestDistanceReplyRejectsCalculatorPageWithoutDistance(t *testing.T) {
query := "расстояние между Москве и Сочи в километрах по прямой и по дороге"
calculator := epistemics.ResearchFinding{Source: epistemics.Source{Title: "Расчет расстояний"}, Excerpt: epistemics.SourceExcerpt{Text: "Калькулятор рассчитывает точное расстояние между городами."}}
if researchFindingMatchesIntent(query, calculator) {
t.Fatal("distance calculator landing page was presented without a measured distance")
}
measured := epistemics.ResearchFinding{Source: epistemics.Source{Title: "Маршрут"}, Excerpt: epistemics.SourceExcerpt{Text: "Расстояние по дороге составляет 1 620 км."}}
if !researchFindingMatchesIntent(query, measured) {
t.Fatal("measured distance evidence was rejected")
}
}
func TestResearchReplyRejectsGenericLandingPageForConcreteIdentifier(t *testing.T) {
result := epistemics.ResearchResult{Findings: []epistemics.ResearchFinding{{
State: epistemics.FindingSupported,
Source: epistemics.Source{Locator: "https://market.example", Title: "Интернет-магазин"},
Excerpt: epistemics.SourceExcerpt{Text: "Широкий ассортимент товаров и услуг."},
}}}
reply, backed := renderResearchReply("на WB бренд marka-wear", result, nil)
if backed || !strings.Contains(reply, "marka-wear") || strings.Contains(reply, "wildberries") || !strings.Contains(reply, "уточните написание") {
t.Fatalf("generic page was presented as a brand result: %q", reply)
}
}
func TestLocalPlaceReplyRejectsDictionaryFinding(t *testing.T) {
result := epistemics.ResearchResult{Findings: []epistemics.ResearchFinding{{
State: epistemics.FindingSupported,
Source: epistemics.Source{Locator: "https://dictionary.example", Title: "Ближайший — словарь"},
Excerpt: epistemics.SourceExcerpt{Text: "Ближайший — значение слова и пример употребления."},
}}}
reply, backed := renderResearchReply("места ресторан в Сочи адрес отзывы меню", result, nil)
if backed || !strings.Contains(reply, "Проверяемых данных") {
t.Fatalf("dictionary finding was presented as local place result: %q", reply)
}
}
func TestResearchReplyKeepsFindingContainingConcreteIdentifier(t *testing.T) {
result := epistemics.ResearchResult{Findings: []epistemics.ResearchFinding{{
State: epistemics.FindingSupported,
Source: epistemics.Source{Locator: "https://market.example/marka-wear", Title: "Marka-wear"},
Excerpt: epistemics.SourceExcerpt{Text: "Бренд marka-wear: товары и карточки."},
}}}
reply, backed := renderResearchReply("на WB бренд marka-wear", result, nil)
if !backed || !strings.Contains(strings.ToLower(reply), "marka-wear") {
t.Fatalf("concrete identifier finding was rejected: %q", reply)
}
}
func TestResearchIdentifiersExcludeSearchDate(t *testing.T) {
identifiers := requestedResearchIdentifiers("ближайший поезд в Петербург сегодня 26.08.2026")
if len(identifiers) != 0 {
t.Fatalf("search date was treated as a concrete identifier: %#v", identifiers)
}
}
func TestResearchQueryKeepsDistanceRelationBeforeSearchNormalization(t *testing.T) {
history := []interaction.HumanUtterance{{Content: "я сейчас в Москве"}}
query := interactiondomain.TravelResearchQuery("сколько километров до Сочи?", history, time.Time{})
query = interactiondomain.SearchQueryWithLexicon(query, interactiondomain.TaskLexicon{})
if query != "расстояние между Москве и Сочи в километрах по прямой и по дороге" {
t.Fatalf("distance query lost remembered origin: %q", query)
}
}
func TestResponseReviewPreservesAttemptedResearchOutcome(t *testing.T) {
if reviewMayReplacePlanningReply(false, false, true, false, "Уточните аэропорт.", "Пока не смог получить проверяемый ответ.") {
t.Fatal("review replaced an honest unbacked research outcome")
}
if !reviewMayReplacePlanningReply(false, false, true, true, "Расписание. Источник: https://example.test", "Расписание. Источник: https://example.test") {
t.Fatal("review should be able to improve a source-backed research outcome")
}
if reviewMayReplacePlanningReply(false, false, true, true, "Расписание без ссылки", "Расписание. Источник: https://example.test") {
t.Fatal("review dropped the research evidence")
}
if !reviewMayReplacePlanningReply(false, false, false, false, "Нормальный ответ", "Черновик") {
t.Fatal("ordinary conversation review was unexpectedly blocked")
}
if !reviewMayReplacePlanningReply(true, true, false, false, "Санкт-Петербург — город в России.", "Меня зовут Домовой. Санкт-Петербург — город в России.") {
t.Fatal("stable-knowledge draft must be eligible for semantic quality review")
}
// The caller must not mark a source-backed research result as immutable
// semantic state: it may be rewritten, but only with its evidence retained.
if !reviewMayReplacePlanningReply(false, false, true, true, "Из Москвы в Сочи можно добраться самолётом или поездом. Источник: https://example.test", "Сырые результаты. Источник: https://example.test") {
t.Fatal("source-backed research draft must be eligible for human-facing review")
}
}
func TestNonMutatingTextDirectiveCanUseCognitiveReply(t *testing.T) {
semantic := interactiondomain.SemanticResult{Interpretation: interaction.UtteranceInterpretation{SpeechAct: interaction.SpeechActDirective}}
if !shouldGenerateNonMutatingTextDirective(semantic, nil, work.HelpPath{}, false) {
t.Fatal("ordinary formatting directive was not eligible for a cognitive reply")
}
if !shouldGenerateNonMutatingTextDirective(semantic, nil, work.HelpPath{Kind: work.HelpPathCognition}, false) {
t.Fatal("reply-only cognition path was incorrectly rejected")
}
if shouldGenerateNonMutatingTextDirective(semantic, nil, work.HelpPath{Kind: work.HelpPathDirectCapability}, false) {
t.Fatal("direct capability was incorrectly replaced by a textual reply")
}
if shouldGenerateNonMutatingTextDirective(semantic, []chatRoute{{Kind: chatRouteMedia}}, work.HelpPath{}, false) {
t.Fatal("media route was incorrectly replaced by a textual reply")
}
if shouldGenerateNonMutatingTextDirective(semantic, nil, work.HelpPath{NeedsDurableWork: true}, false) {
t.Fatal("durable work was incorrectly replaced by a textual reply")
}
}
func TestBearerTokenRequiresBearerScheme(t *testing.T) {
request := httptest.NewRequest("GET", "/", nil)
request.Header.Set("Authorization", "Basic value")
@@ -67,12 +221,35 @@ func TestHumanMemoryInventoryUsesNewestPreference(t *testing.T) {
}
}
func TestContainsPriceEvidenceDistinguishesLinksFromPrices(t *testing.T) {
if containsPriceEvidence("RTX 4090 — market.yandex.ru") {
t.Fatal("a product link is not price evidence")
func TestContainsScheduleTimeEvidence(t *testing.T) {
if containsScheduleTimeEvidence("расписание поездов и цена билета") {
t.Fatal("a price or schedule label is not a departure time")
}
if !containsPriceEvidence("Цена: 189 990 ₽") {
t.Fatal("expected a currency amount to count as price evidence")
if !containsScheduleTimeEvidence("Отправление в 07:45") {
t.Fatal("expected an explicit departure time to be recognized")
}
}
func TestInternetStatusQueryRecognizesConnectionChecks(t *testing.T) {
for _, query := range []string{"проверь, работает ли интернет", "есть доступ к сети?"} {
if !isInternetStatusQuery(query) {
t.Fatalf("connection check was not recognized: %q", query)
}
}
if isInternetStatusQuery("найди интернет-магазин") {
t.Fatal("ordinary search must not be treated as a connectivity check")
}
}
func TestInternetStatusReplyDoesNotLeakIncidentalSearchResults(t *testing.T) {
result := epistemics.ResearchResult{Findings: []epistemics.ResearchFinding{{
State: epistemics.FindingSupported,
Source: epistemics.Source{Locator: "https://example.test", Title: "Incidental page"},
Excerpt: epistemics.SourceExcerpt{Text: "A response was received."},
}}}
reply, backed := renderResearchReply("проверь, работает ли интернет", result, nil)
if !backed || reply != "Интернет работает: Домовой получил ответ от внешнего источника." {
t.Fatalf("unexpected internet status reply: %q", reply)
}
}
@@ -83,6 +260,13 @@ func TestCognitiveChannelQuestionUsesHumanSafeHealthReply(t *testing.T) {
}
}
func TestCurrentModelReplyDoesNotInventProvider(t *testing.T) {
reply := humanCurrentCognitiveModelReply(capability.Health{State: capability.HealthDegraded, CapabilityID: "provider-secret-model"}, nil)
if !strings.Contains(reply, "встроенным режимом") || !strings.Contains(reply, "ограничениями") || strings.Contains(reply, "provider-secret-model") {
t.Fatalf("unexpected current-model reply: %q", reply)
}
}
func TestCognitiveConfigurationRequestDoesNotPretendToMutate(t *testing.T) {
reply := humanCognitiveChannelReply(interaction.InformationRequestCognitiveRecovery, interaction.SpeechActDirective, capability.Health{State: capability.HealthUnavailable}, nil)
if reply != "Канал мышления недоступен. Домовой остаётся на связи." {
+32
View File
@@ -251,6 +251,38 @@ func TestChatMessageUsesLocalAdvisoryForOrdinaryConversationalQuestion(t *testin
}
}
func TestChatMessagePreservesCompletedCoreAnswerInsteadOfSecondAdvisory(t *testing.T) {
core := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.Method == http.MethodGet && r.URL.Path == "/v1/creator/sessions/current":
_ = json.NewEncoder(w).Encode(identity.CreatorSession{ActorID: "actor-1", PrincipalID: "principal-1"})
case r.Method == http.MethodPost && r.URL.Path == "/v1/creator/chat/messages":
w.WriteHeader(http.StatusCreated)
_ = json.NewEncoder(w).Encode(interaction.ChatMessageResponse{ConversationID: "conversation-1", UtteranceID: "utterance-1", SpeechAct: interaction.SpeechActQuestion, NeedsCognition: true, FallbackText: "fallback", PlanningReply: "Готовый ответ ядра."})
default:
t.Fatalf("unexpected core route %s %s", r.Method, r.URL.Path)
}
}))
defer core.Close()
cognitiveRuntime := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Fatal("completed core answer must not be replaced by a second advisory")
}))
defer cognitiveRuntime.Close()
handler, err := newHandler(core.URL, "http://continuity", "http://commit", core.Client(), cognitiveRuntime.URL)
if err != nil {
t.Fatal(err)
}
request := httptest.NewRequest(http.MethodPost, "/api/chat/messages", strings.NewReader(`{"message":"Обычный вопрос"}`))
request.Header.Set("Authorization", "Bearer session-token")
request.Header.Set("Content-Type", "application/json")
recorder := httptest.NewRecorder()
handler.ServeHTTP(recorder, request)
var response browserChatResponse
if recorder.Code != http.StatusOK || json.NewDecoder(recorder.Body).Decode(&response) != nil || response.ReplyText != "Готовый ответ ядра." {
t.Fatalf("unexpected browser response: status=%d body=%s", recorder.Code, recorder.Body.String())
}
}
func TestChatMessageReturnsHumanCapabilityMetadata(t *testing.T) {
core := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
+9 -2
View File
@@ -28,7 +28,11 @@ import (
const (
maxRequestBytes = 8 << 10
maxAdvisoryRequestBytes = 20 << 10
maxResponseBytes = 1 << 20
// Chat responses may contain a locally generated image encoded as base64.
// Keep the gateway limit aligned with the bounded media transport (32 MiB),
// otherwise a successfully generated image is incorrectly surfaced as an
// unavailable runtime to the human.
maxResponseBytes = 32 << 20
)
//go:embed static
@@ -476,7 +480,10 @@ func (g *gateway) handleChatMessage(w http.ResponseWriter, r *http.Request) {
saved.NeedsCognition = false
}
}
if saved.NeedsCognition && !saved.WorkPlanned && saved.Clarification != interaction.ClarificationRequired {
// Core owns the completed planning answer. The browser may ask for a local
// advisory only when core explicitly left the turn unanswered; otherwise a
// second model pass can replace a grounded result with a weaker one.
if saved.NeedsCognition && saved.PlanningReply == "" && !saved.WorkPlanned && saved.Clarification != interaction.ClarificationRequired {
cognition = "unavailable"
requestID, idErr := ids.New()
if idErr == nil {
+20
View File
@@ -1,6 +1,7 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
@@ -13,6 +14,25 @@ import (
"git.cin.su/m/Assistant/contracts/interaction"
)
func TestMaxResponseBytesAcceptsGeneratedImagePayload(t *testing.T) {
// A 1024px PNG can exceed the former 1 MiB gateway limit once base64
// encoded. The browser gateway must forward that successful core response.
payload, err := json.Marshal(interaction.ChatMessageResponse{
GeneratedImageContentType: "image/png",
GeneratedImageBase64: strings.Repeat("A", 2<<20),
})
if err != nil {
t.Fatal(err)
}
var decoded interaction.ChatMessageResponse
if err := decodeStrictJSON(bytes.NewReader(payload), maxResponseBytes, &decoded); err != nil {
t.Fatalf("generated image response must fit gateway limit: %v", err)
}
if len(decoded.GeneratedImageBase64) != 2<<20 {
t.Fatalf("generated image payload was truncated: %d", len(decoded.GeneratedImageBase64))
}
}
func TestLocalChatContextIncludesDomovoyIdentityAndOptionalActiveProject(t *testing.T) {
context := localChatContext(interaction.ChatMessageResponse{AssistantName: "Фея", ActiveProjectName: "Домовой"})
if len(context) != 2 || context[0].SourceID != "domovoy" || !strings.Contains(context[0].Text, "Ты — Фея") || !strings.Contains(context[0].Text, "Меня зовут Фея") || context[1].Text != "Текущий проект: Домовой" {
+21
View File
@@ -49,6 +49,9 @@ func validateTaskPacket(root string, task TaskPacket, taskPath string) error {
if err := validateArchitectureRevision(root, task.ArchitectureRevision); err != nil {
return fmt.Errorf("task %s architecture_revision: %w", task.TaskID, err)
}
if err := validateGenerationTask(task); err != nil {
return err
}
if _, err := resolveBaseCommit(root, task.BaseRepoRevision); err != nil {
return fmt.Errorf("task %s base_repo_revision: %w", task.TaskID, err)
}
@@ -58,6 +61,24 @@ func validateTaskPacket(root string, task TaskPacket, taskPath string) error {
return nil
}
func validateGenerationTask(task TaskPacket) error {
switch {
case task.TaskID == "PRE-GEN2-000":
if task.BaseRepoRevision != "origin/main" || task.ArchitectureRevision != "ADR-0019" {
return fmt.Errorf("task %s must use origin/main and ADR-0019", task.TaskID)
}
case task.TaskID == "ARCH-GEN2-000":
if task.BaseRepoRevision != "gen2-integration" || task.ArchitectureRevision != "ADR-0019" {
return fmt.Errorf("task %s must use gen2-integration and ADR-0019", task.TaskID)
}
case strings.HasPrefix(task.TaskID, "GEN2-"):
if task.BaseRepoRevision != "gen2-integration" || task.ArchitectureRevision != "ARCH-GEN2-000" {
return fmt.Errorf("task %s must use gen2-integration and ARCH-GEN2-000", task.TaskID)
}
}
return nil
}
func validateRequiredTests(tests []string) error {
joined := strings.Join(tests, "\n")
for _, required := range []string{"go test", "go vet", "preflight", "check-diff", "git diff --check", "independent"} {
+39
View File
@@ -25,3 +25,42 @@ func TestValidateDeltaRejectsUnknownOrMissingFields(t *testing.T) {
t.Fatalf("delta error = %v", err)
}
}
func TestValidateGenerationTaskRequiresGen2BaseAndArchitecture(t *testing.T) {
tests := []struct {
name string
task TaskPacket
want string
}{
{
name: "architecture task requires integration base",
task: TaskPacket{TaskID: "ARCH-GEN2-000", BaseRepoRevision: "origin/main", ArchitectureRevision: "ADR-0019"},
want: "gen2-integration",
},
{
name: "implementation task requires accepted architecture root",
task: TaskPacket{TaskID: "GEN2-001", BaseRepoRevision: "gen2-integration", ArchitectureRevision: "ADR-0019"},
want: "ARCH-GEN2-000",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
err := validateGenerationTask(tc.task)
if err == nil || !strings.Contains(err.Error(), tc.want) {
t.Fatalf("generation validation error = %v, want %q", err, tc.want)
}
})
}
}
func TestValidateGenerationTaskAcceptsExecutionRoots(t *testing.T) {
for _, task := range []TaskPacket{
{TaskID: "PRE-GEN2-000", BaseRepoRevision: "origin/main", ArchitectureRevision: "ADR-0019"},
{TaskID: "ARCH-GEN2-000", BaseRepoRevision: "gen2-integration", ArchitectureRevision: "ADR-0019"},
{TaskID: "GEN2-001", BaseRepoRevision: "gen2-integration", ArchitectureRevision: "ARCH-GEN2-000"},
} {
if err := validateGenerationTask(task); err != nil {
t.Fatalf("validateGenerationTask(%+v) = %v", task, err)
}
}
}
+10
View File
@@ -0,0 +1,10 @@
package main
import "net/http"
func main() {
_ = http.ListenAndServe(":8088", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("lifeboat-ready\n"))
}))
}
+12
View File
@@ -5,6 +5,18 @@ import "git.cin.su/m/Assistant/platform/ids"
import "errors"
type ArtifactID ids.ID
type MediaArtifact struct {
ID ArtifactID
ContentType string
SizeBytes int64
ContentDigest string
SourceRef string
RecordedAtUnixMillis int64
}
func (a MediaArtifact) Valid() bool {
return a.ID != "" && a.ContentType != "" && a.SizeBytes > 0 && a.ContentDigest != "" && a.SourceRef != "" && a.RecordedAtUnixMillis > 0
}
type AgentArtifactAttestation struct {
ArtifactID ArtifactID
+41
View File
@@ -0,0 +1,41 @@
package capability
type IntelligencePath string
const (
PathRule IntelligencePath = "RULE"
PathReflex IntelligencePath = "REFLEX"
PathSkill IntelligencePath = "SKILL"
PathSmallLocal IntelligencePath = "SMALL_LOCAL"
PathStrongLocal IntelligencePath = "STRONG_LOCAL"
PathExternal IntelligencePath = "EXTERNAL"
PathResearch IntelligencePath = "RESEARCH"
PathTeam IntelligencePath = "TEAM"
)
type StrategyRequest struct {
RequiredQuality int64
PreferLowLatency bool
CostBudgetMicros int64
RiskClass string
FreshnessRequired bool
CostOfError int64
}
type StrategyDecision struct {
Path IntelligencePath
Reason string
Escalate bool
}
func (r StrategyRequest) Select() StrategyDecision {
if r.RiskClass == "HIGH" || r.CostOfError >= 800 {
return StrategyDecision{Path: PathStrongLocal, Reason: "high consequence requires deeper reasoning", Escalate: true}
}
if r.RequiredQuality <= 500 && r.CostBudgetMicros > 0 {
return StrategyDecision{Path: PathRule, Reason: "bounded low-risk path"}
}
if r.PreferLowLatency {
return StrategyDecision{Path: PathReflex, Reason: "latency preference with later escalation"}
}
return StrategyDecision{Path: PathSkill, Reason: "validated reusable strategy"}
}
+11 -7
View File
@@ -15,11 +15,15 @@ const (
)
type MultimodalResponse struct {
Operation MultimodalOperation `json:"operation"`
Text string `json:"text"`
Provider string `json:"provider,omitempty"`
ObservedAt int64 `json:"observed_at_unix_millis"`
ConfidenceNote string `json:"confidence_note,omitempty"`
ContentType string `json:"content_type,omitempty"`
DataBase64 string `json:"data_base64,omitempty"`
Operation MultimodalOperation `json:"operation"`
Text string `json:"text"`
Provider string `json:"provider,omitempty"`
ObservedAt int64 `json:"observed_at_unix_millis"`
ConfidenceNote string `json:"confidence_note,omitempty"`
ContentType string `json:"content_type,omitempty"`
DataBase64 string `json:"data_base64,omitempty"`
Model string `json:"model,omitempty"`
ModelVersion string `json:"model_version,omitempty"`
ConfidenceMillis int64 `json:"confidence_millis,omitempty"`
EvidenceRef string `json:"evidence_ref,omitempty"`
}
+61
View File
@@ -0,0 +1,61 @@
package capability
type ReflexID string
type ReflexLifecycle string
type ReflexKind string
const (
ReflexCandidate ReflexLifecycle = "CANDIDATE"
ReflexValidating ReflexLifecycle = "VALIDATING"
ReflexActive ReflexLifecycle = "ACTIVE"
ReflexDegraded ReflexLifecycle = "DEGRADED"
ReflexStale ReflexLifecycle = "STALE"
ReflexSuspended ReflexLifecycle = "SUSPENDED"
ReflexRetired ReflexLifecycle = "RETIRED"
ReflexDeterministicCode ReflexKind = "DETERMINISTIC_CODE"
ReflexRule ReflexKind = "RULE"
ReflexWorkflow ReflexKind = "WORKFLOW"
ReflexQueryTemplate ReflexKind = "QUERY_TEMPLATE"
ReflexSmallModelChain ReflexKind = "SMALL_MODEL_CHAIN"
ReflexBoundedAdapter ReflexKind = "BOUNDED_ADAPTER_OPERATION"
)
type ShadowPolicy struct {
Enabled bool
SampleRateMillis int64
ComparatorRef string
MaxShadowCostMicros *int64
EligibleErrorCostClasses []string
}
type RevalidationPolicy struct {
MaxAgeMillis *int64
RevalidateOnDependencyRevisionChange bool
RevalidateOnWorldVersionChange bool
RevalidateAfterFailureCount *int64
RevalidateAfterCorrectionCount *int64
SampleAuditRateMillis *int64
}
type Reflex struct {
ID ReflexID
PrincipalID string
SourceSkillRef SkillID
CreatedAt int64
}
type ReflexRevision struct {
ReflexID ReflexID
Revision int64
SourceSkillRevision int64
Kind ReflexKind
Applicability ApplicabilitySpec
ImplementationRef string
ImplementationVersion string
ArtifactDigest string
DependencyRefs []string
ValidationEvidenceRefs []SkillEvidenceRef
KnownFailureExperienceRefs []SkillEvidenceRef
Shadow ShadowPolicy
Revalidation RevalidationPolicy
LastValidatedAt int64
Lifecycle ReflexLifecycle
RecordedAt int64
}
+36
View File
@@ -0,0 +1,36 @@
package capability
type SkillID string
type SkillRevision struct {
SkillID SkillID
Revision int64
Description string
Applicability ApplicabilitySpec
ImplementationRef string
ImplementationVersion string
DependencyRefs []string
SupportingExperienceRefs []SkillEvidenceRef
KnownFailureExperienceRefs []SkillEvidenceRef
ValidationEvidenceRefs []SkillEvidenceRef
QualityAssessmentRefs []string
EnvironmentVersionConstraints []string
LastValidatedAt int64
Lifecycle SkillLifecycleStatus
SupersedesRevision int64
RecordedAt int64
}
type ApplicabilitySpec struct {
RequiredContextBindings []string
PreferredContextBindings []string
ExcludedContextBindings []string
RequiredWorldKinds []string
VersionConstraints []string
InputConditions []string
MinimumEvidenceFreshness string
}
type Skill struct {
ID SkillID
PrincipalID string
Name string
CreatedAt int64
}
+41 -5
View File
@@ -11,14 +11,24 @@ import (
var ErrInvalidContextBudget = errors.New("context budget must be positive")
type ContextCandidate struct {
Excerpt ContextExcerpt
Relevance int
Excerpt ContextExcerpt
Relevance int
Lane string
ContextScopeRef string
FreshnessState string
Negative bool
}
type ContextCompileInput struct {
Candidates []ContextCandidate
DataPolicy capability.DataPolicy
MaxBytes int
Candidates []ContextCandidate
DataPolicy capability.DataPolicy
MaxBytes int
TaskRef string
FocusFrameRef string
ContextScopeRef string
FreshnessRequirement string
RiskClass string
TokenBudget int
}
type ContextOmission struct {
@@ -30,6 +40,24 @@ type ContextBundle struct {
Excerpts []ContextExcerpt
Omissions []ContextOmission
Bytes int
Trace ContextAssemblyTrace
}
type ContextAssemblyTrace struct {
Included []ContextExcerptID
Excluded []ContextOmission
Coverage string
CompilerVersion string
}
type IterativeRetrievalRequest struct {
Query string
RemainingBytes int
Pass int
}
type IterativeRetrievalResponse struct {
Candidates []ContextCandidate
Exhausted bool
}
// CompileContext deterministically selects permitted, relevant excerpts for a
@@ -54,6 +82,10 @@ func CompileContext(input ContextCompileInput) (ContextBundle, error) {
continue
}
seen[excerpt.ID] = struct{}{}
if input.ContextScopeRef != "" && candidate.ContextScopeRef != input.ContextScopeRef {
bundle.Omissions = append(bundle.Omissions, ContextOmission{ID: excerpt.ID, Reason: "context_scope"})
continue
}
reason := permittedContextReason(excerpt, input.DataPolicy)
if reason != "" {
bundle.Omissions = append(bundle.Omissions, ContextOmission{ID: excerpt.ID, Reason: reason})
@@ -70,7 +102,11 @@ func CompileContext(input ContextCompileInput) (ContextBundle, error) {
}
bundle.Excerpts = append(bundle.Excerpts, excerpt)
bundle.Bytes += bytes
bundle.Trace.Included = append(bundle.Trace.Included, excerpt.ID)
}
bundle.Trace.Excluded = append([]ContextOmission(nil), bundle.Omissions...)
bundle.Trace.CompilerVersion = "context-compiler-v2-additive"
bundle.Trace.Coverage = "BOUNDED"
return bundle, nil
}
@@ -0,0 +1,14 @@
package cognitive_test
import (
"git.cin.su/m/Assistant/contracts/capability"
"git.cin.su/m/Assistant/contracts/cognitive"
"testing"
)
func TestContextCompilerV2TraceAndBudgetRemainDeterministic(t *testing.T) {
b, err := cognitive.CompileContext(cognitive.ContextCompileInput{MaxBytes: 5, DataPolicy: capability.DataPolicyLocalOnly, TaskRef: "task", FocusFrameRef: "frame", ContextScopeRef: "company-a", Candidates: []cognitive.ContextCandidate{{Excerpt: cognitive.ContextExcerpt{ID: "a", Text: "123", Sensitivity: cognitive.SensitivityPrivateAllowed}, ContextScopeRef: "company-a", Relevance: 10}, {Excerpt: cognitive.ContextExcerpt{ID: "b", Text: "123456", Sensitivity: cognitive.SensitivityPrivateAllowed}, ContextScopeRef: "company-b", Relevance: 100}}})
if err != nil || len(b.Excerpts) != 1 || len(b.Trace.Excluded) != 1 {
t.Fatalf("bundle=%#v err=%v", b, err)
}
}
+32
View File
@@ -0,0 +1,32 @@
package commit
type ExecutorResult string
type AmbiguityState string
const (
ExecutorAccepted ExecutorResult = "ACCEPTED"
ExecutorReportedSuccess ExecutorResult = "REPORTED_SUCCESS"
ExecutorReportedFailure ExecutorResult = "REPORTED_FAILURE"
ExecutorNoResponse ExecutorResult = "NO_RESPONSE"
ExecutorAmbiguous ExecutorResult = "AMBIGUOUS"
)
type ExecutionReceipt struct {
ID string
ActionAttemptRef ActionAttemptID
ExecutorImplementationRef string
ExternalOperationRef string
ExternalRequestID string
RequestDigest string
ResponseDigest string
DispatchAtUnixMillis int64
CompletedAtUnixMillis *int64
ExecutorResult ExecutorResult
Ambiguity AmbiguityState
ReconciliationKey string
RawArtifactRef string
}
func (r ExecutionReceipt) Valid() bool {
return r.ID != "" && r.ActionAttemptRef != "" && r.ExecutorImplementationRef != "" && r.RequestDigest != "" && r.ExecutorResult != "" && r.ReconciliationKey != "" && r.DispatchAtUnixMillis > 0
}
+7
View File
@@ -0,0 +1,7 @@
# Configuration contract boundary
Configuration owns typed and versioned `SettingDefinition` and
`SettingAssignment` records plus scoped resolution and change provenance.
Effective configuration is a derived result. Secret values never enter a
setting assignment; only a `SecretRef`/`CredentialRef` crosses the secrets
boundary into an authorized adapter or runtime.
+7
View File
@@ -0,0 +1,7 @@
package configuration
import "git.cin.su/m/Assistant/platform/ids"
// SemanticReference is a typed cross-owner reference; settings remain
// Configuration-owned records.
type SemanticReference = ids.SemanticRef
+101
View File
@@ -0,0 +1,101 @@
package configuration
import (
"fmt"
"git.cin.su/m/Assistant/contracts/secrets"
"git.cin.su/m/Assistant/platform/ids"
)
type SettingDefinitionID ids.StableID
type SettingAssignmentID ids.StableID
type ConfigurationRevision ids.Revision
type ValueType string
type ResolutionMode string
type SettingLifecycle string
type SettingSource string
const (
ValueString ValueType = "STRING"
ValueInteger ValueType = "INTEGER"
ValueBoolean ValueType = "BOOLEAN"
ValueSecretRef ValueType = "SECRET_REF"
ResolutionMostSpecific ResolutionMode = "MOST_SPECIFIC_WINS"
ResolutionFirstHuman ResolutionMode = "FIRST_EXPLICIT_HUMAN_WINS"
ResolutionMergeList ResolutionMode = "MERGE_LIST"
SettingActive SettingLifecycle = "ACTIVE"
SettingDeprecated SettingLifecycle = "DEPRECATED"
SettingRetired SettingLifecycle = "RETIRED"
SourceHumanDirective SettingSource = "HUMAN_DIRECTIVE"
SourceMigrated SettingSource = "MIGRATED_CONFIG"
SourceSkillDefault SettingSource = "SKILL_DEFAULT"
SourceSystemDefault SettingSource = "SYSTEM_DEFAULT"
SourceGovernedChange SettingSource = "GOVERNED_CHANGE"
)
type SettingDefinition struct {
ID SettingDefinitionID
OwnerNamespace string
StableKey string
Revision ConfigurationRevision
ValueType ValueType
DefaultValue string
Sensitivity string
Lifecycle SettingLifecycle
RecordedAtUnixMillis int64
}
type ScopeSelector struct {
PrincipalRef string
RequiredContextBindings []string
ActivityRef string
SkillRef string
TaskRef string
SessionRef string
TemporaryOverride bool
}
type SettingAssignment struct {
ID SettingAssignmentID
PrincipalID string
DefinitionRef string
DefinitionRevision ConfigurationRevision
Revision ConfigurationRevision
Selector ScopeSelector
TypedValue string
SecretRef *secrets.CredentialRef
EffectiveFromUnixMillis int64
EffectiveUntilUnixMillis *int64
Source SettingSource
SourceRef string
Lifecycle SettingLifecycle
RecordedAtUnixMillis int64
}
type EffectiveSetting struct {
DefinitionRef string
Value string
WinningAssignmentRef string
ResolutionTrace []string
}
type BootstrapConfig struct {
NodeIdentity string
ControlDatabaseLocator string
RootSecretResolverLocator string
RecoveryLocator string
}
// ConversationalConfigurationCommand is an intent, not an assignment. Only
// Configuration may turn a SET command into durable state.
func (d SettingDefinition) Validate() error {
if d.ID == "" || d.OwnerNamespace == "" || d.StableKey == "" || !ids.Revision(d.Revision).Valid() || d.ValueType == "" || d.Lifecycle == "" || d.RecordedAtUnixMillis < 1 {
return fmt.Errorf("invalid setting definition")
}
return nil
}
func (a SettingAssignment) Validate() error {
if a.ID == "" || a.PrincipalID == "" || a.DefinitionRef == "" || !ids.Revision(a.Revision).Valid() || a.Source == "" || a.Lifecycle == "" || a.RecordedAtUnixMillis < 1 {
return fmt.Errorf("invalid setting assignment")
}
if a.SecretRef != nil && a.TypedValue != "" {
return fmt.Errorf("secret assignment must not contain typed value")
}
return nil
}
+90
View File
@@ -0,0 +1,90 @@
package epistemics
import (
"fmt"
"git.cin.su/m/Assistant/contracts/world"
)
type VolatilityMode string
const (
VolatilityImmutable VolatilityMode = "IMMUTABLE"
VolatilityVersionBound VolatilityMode = "VERSION_BOUND"
VolatilityVerySlow VolatilityMode = "VERY_SLOW"
VolatilitySlow VolatilityMode = "SLOW"
VolatilityMedium VolatilityMode = "MEDIUM"
VolatilityFast VolatilityMode = "FAST"
VolatilityEphemeral VolatilityMode = "EPHEMERAL"
VolatilityCustom VolatilityMode = "CUSTOM"
)
type TemporalApplicability struct {
ObservedAtUnixMillis int64
ValidFromUnixMillis *int64
ValidUntilUnixMillis *int64
LastVerifiedAtUnixMillis *int64
Volatility VolatilitySpec
VersionBindings []world.VersionBinding
}
type VolatilitySpec struct {
Mode VolatilityMode
ExpectedChangeIntervalMillis *int64
RevalidateAfterMillis *int64
HardStaleAfterMillis *int64
InvalidateOnVersionChange bool
RevalidationPolicyRef string
}
type FreshnessAssessmentState string
const (
FreshnessAssessmentCurrent FreshnessAssessmentState = "CURRENT"
FreshnessAssessmentAcceptable FreshnessAssessmentState = "ACCEPTABLE"
FreshnessAssessmentAging FreshnessAssessmentState = "AGING"
FreshnessAssessmentStale FreshnessAssessmentState = "STALE"
FreshnessAssessmentVersionMismatch FreshnessAssessmentState = "VERSION_MISMATCH"
FreshnessAssessmentHistoricalOnly FreshnessAssessmentState = "HISTORICAL_ONLY"
FreshnessAssessmentUnknown FreshnessAssessmentState = "UNKNOWN"
)
type FreshnessAssessment struct {
SourceKnowledgeRef string
TaskRef string
State FreshnessAssessmentState
Reason string
AgeMillis int64
VersionMatchState string
RevalidationAttemptRef string
AssessedAtUnixMillis int64
}
type RevalidationRequest struct {
ID string
SourceKnowledgeRef string
TaskRef string
RequiredVersionRefs []world.SemanticReference
RequestedAtUnixMillis int64
}
type RevalidationResponse struct {
RequestID string
Assessment FreshnessAssessment
NewEvidenceRefs []EvidenceRef
CompletedAtUnixMillis int64
}
func (v VolatilitySpec) Validate() error {
if v.Mode == "" {
return fmt.Errorf("volatility mode is required")
}
return nil
}
func (t TemporalApplicability) Validate() error {
if t.ObservedAtUnixMillis < 1 {
return fmt.Errorf("observed time is required")
}
return t.Volatility.Validate()
}
func (a FreshnessAssessment) Validate() error {
if a.SourceKnowledgeRef == "" || a.TaskRef == "" || a.State == "" || a.AgeMillis < 0 || a.AssessedAtUnixMillis < 1 {
return fmt.Errorf("freshness assessment is incomplete")
}
return nil
}
+30
View File
@@ -0,0 +1,30 @@
package epistemics
type WorldOutcomeState string
const (
OutcomeVerifiedSuccess WorldOutcomeState = "VERIFIED_SUCCESS"
OutcomeVerifiedPartial WorldOutcomeState = "VERIFIED_PARTIAL"
OutcomeVerifiedFailure WorldOutcomeState = "VERIFIED_FAILURE"
OutcomeUnverified WorldOutcomeState = "UNVERIFIED"
OutcomeUnknownState WorldOutcomeState = "UNKNOWN"
OutcomeConflicted WorldOutcomeState = "CONFLICTED"
)
type WorldOutcomeAssessment struct {
ID string
PrincipalID string
ActionAttemptRef string
ExecutionReceiptRefs []string
ExpectedEffectRef string
ObservationRefs []ObservationID
ClaimRefs []ClaimID
State WorldOutcomeState
ConfidenceMillis int64
EvidenceRefs []EvidenceRef
AssessedAt int64
}
func (a WorldOutcomeAssessment) Valid() bool {
return a.ID != "" && a.PrincipalID != "" && a.ActionAttemptRef != "" && a.State != "" && a.ConfidenceMillis >= 0 && a.ConfidenceMillis <= 1000 && a.AssessedAt > 0
}
+7
View File
@@ -0,0 +1,7 @@
package epistemics
import "git.cin.su/m/Assistant/platform/ids"
// SemanticReference identifies evidence-related records without transferring
// canonical ownership to Epistemics.
type SemanticReference = ids.SemanticRef
+34 -15
View File
@@ -17,23 +17,27 @@ type CoverageState string
type ConflictState string
type EvidenceKind string
type ResearchFindingState string
type ReliabilityState string
const (
FreshnessCurrent FreshnessState = "CURRENT"
FreshnessStale FreshnessState = "STALE"
FreshnessUnknown FreshnessState = "UNKNOWN"
CoverageComplete CoverageState = "COMPLETE"
CoveragePartial CoverageState = "PARTIAL"
CoverageUnknown CoverageState = "UNKNOWN"
ConflictNone ConflictState = "NONE"
ConflictPresent ConflictState = "PRESENT"
ConflictUnknown ConflictState = "UNKNOWN"
EvidenceObserved EvidenceKind = "OBSERVED"
EvidenceAssumed EvidenceKind = "ASSUMED"
FindingSupported ResearchFindingState = "SUPPORTED"
FindingStale ResearchFindingState = "STALE"
FindingConflicted ResearchFindingState = "CONFLICTED"
FindingUnknown ResearchFindingState = "UNKNOWN"
FreshnessCurrent FreshnessState = "CURRENT"
FreshnessStale FreshnessState = "STALE"
FreshnessUnknown FreshnessState = "UNKNOWN"
CoverageComplete CoverageState = "COMPLETE"
CoveragePartial CoverageState = "PARTIAL"
CoverageUnknown CoverageState = "UNKNOWN"
ConflictNone ConflictState = "NONE"
ConflictPresent ConflictState = "PRESENT"
ConflictUnknown ConflictState = "UNKNOWN"
EvidenceObserved EvidenceKind = "OBSERVED"
EvidenceAssumed EvidenceKind = "ASSUMED"
FindingSupported ResearchFindingState = "SUPPORTED"
FindingStale ResearchFindingState = "STALE"
FindingConflicted ResearchFindingState = "CONFLICTED"
FindingUnknown ResearchFindingState = "UNKNOWN"
ReliabilityCurrent ReliabilityState = "CURRENT"
ReliabilityAging ReliabilityState = "AGING"
ReliabilityUnknown ReliabilityState = "UNKNOWN"
)
type ResearchPlan struct {
@@ -52,6 +56,21 @@ type Source struct {
Publisher string
}
type SourceReliabilityAssessment struct {
SourceRef string
DomainRef string
Freshness FreshnessState
HistoryScoreMillis int64
ReliabilityScoreMillis int64
State ReliabilityState
EvidenceRefs []string
AssessedAtUnixMillis int64
}
func (a SourceReliabilityAssessment) Valid() bool {
return a.SourceRef != "" && a.DomainRef != "" && a.Freshness != "" && a.HistoryScoreMillis >= 0 && a.HistoryScoreMillis <= 1000 && a.ReliabilityScoreMillis >= 0 && a.ReliabilityScoreMillis <= 1000 && a.State != "" && a.AssessedAtUnixMillis > 0
}
type SourceSnapshot struct {
ID SourceSnapshotID
SourceID SourceID
+20 -10
View File
@@ -1,5 +1,7 @@
package epistemics
import "git.cin.su/m/Assistant/platform/ids"
type BeliefState string
const (
@@ -9,19 +11,27 @@ const (
)
type Observation struct {
ID ObservationID
SourceSnapshot SourceSnapshotID
Excerpt SourceExcerptID
Text string
ObservedAt int64
ID ObservationID
SourceSnapshot SourceSnapshotID
Excerpt SourceExcerptID
Text string
ObservedAt int64
PrincipalID string
ContextScopeRef string
ObservationKind string
Payload string
ExtractorRef string
}
type Claim struct {
ID ClaimID
Statement string
ObservationID ObservationID
CitationID CitationID
Verification VerificationState
ID ClaimID
Statement string
ObservationID ObservationID
CitationID CitationID
Verification VerificationState
PropositionID ids.ID
RevisedFrom *ClaimID
RecordedAtUnixMillis int64
}
type Belief struct {
+48
View File
@@ -24,6 +24,8 @@ type HelpMethodKind string
type OutcomeClass string
type ReflectionTriggerKind string
type ReflectionCandidateState string
type PropositionKind string
type BeliefAssessmentState string
const (
VerificationUnverified VerificationState = "UNVERIFIED"
@@ -73,6 +75,12 @@ const (
ReflectionCandidateEvaluating ReflectionCandidateState = "EVALUATING"
ReflectionCandidateSuperseded ReflectionCandidateState = "SUPERSEDED"
ReflectionCandidateResolved ReflectionCandidateState = "RESOLVED"
PropositionWorldFacet PropositionKind = "WORLD_FACET"
PropositionWorldRelation PropositionKind = "WORLD_RELATION"
PropositionOwnerDefined PropositionKind = "OWNER_DEFINED"
PropositionTextual PropositionKind = "TEXTUAL"
BeliefAssessmentCurrent BeliefAssessmentState = "CURRENT"
BeliefAssessmentSuperseded BeliefAssessmentState = "SUPERSEDED"
)
// SystemExpectation records what Domovoy expected a meaningful help path to
@@ -114,6 +122,15 @@ type ExperienceRecord struct {
VerificationEvidence []EvidenceRef
ConfidenceMillis int64
RecordedAtUnixMillis int64
ProblemStatement string
AttemptRef string
WhyAttempted string
ApplicabilityConditions []string
ContextScopeRef string
EpisodeRef string
GoalRef string
TaskRef string
WhySucceededOrFailed string
}
// ReflectionCandidate records that broader reflection may be warranted.
@@ -134,3 +151,34 @@ type ReflectionCandidate struct {
ClaimedBy string
ClaimExpiresAtUnixMillis int64
}
type Proposition struct {
ID ids.ID
Kind PropositionKind
SubjectRef string
PredicateRef string
ObjectValue string
ObjectRef string
Qualifiers []string
TextFallback string
}
type BeliefAssessment struct {
ID ids.ID
ClaimID ClaimID
Revision ids.Revision
State BeliefAssessmentState
ConfidenceMillis int64
EvidenceRefs []EvidenceRef
AssessedAtUnixMillis int64
}
type EpisodeID ids.ID
type Episode struct {
ID EpisodeID
PrincipalID string
ExperienceRefs []ExperienceRecordID
Summary string
Outcome OutcomeClass
RecordedAtUnixMillis int64
}
+24
View File
@@ -6,6 +6,30 @@ type ActorID ids.ID
type PrincipalID ids.ID
type IdentityID ids.ID
type DataRealmKind string
const (
DataRealmPersonal DataRealmKind = "PERSONAL"
DataRealmShared DataRealmKind = "SHARED"
DataRealmPublic DataRealmKind = "PUBLIC"
)
// PrincipalDataRealm is an identity-owned access boundary. It does not make
// a speaker or World person referent an authenticated principal.
type PrincipalDataRealm struct {
ID string
OwnerPrincipalID PrincipalID
Kind DataRealmKind
MemberPrincipalIDs []PrincipalID
Shared bool
Revision int64
RecordedAtUnixMillis int64
}
func (r PrincipalDataRealm) Valid() bool {
return r.ID != "" && r.OwnerPrincipalID != "" && (r.Kind == DataRealmPersonal || r.Kind == DataRealmShared || r.Kind == DataRealmPublic) && r.Revision > 0 && r.RecordedAtUnixMillis > 0 && (r.Kind != DataRealmShared || r.Shared)
}
// PrincipalBinding keeps the operational actor separate from the interest on
// whose behalf it acts. A Creator is not exempt from this distinction.
type PrincipalBinding struct {
+100 -45
View File
@@ -25,53 +25,96 @@ type SemanticApplicability string
type SemanticCandidateSource string
type SemanticCandidateSelectionState string
type InformationRequestKind string
type ConfigurationCommandKind string
type SpeakerAttribution struct {
SourceRef string
PrincipalCandidate string
ConfidenceMillis int64
Authenticated bool
ObservationRef string
}
type IngressModality string
const (
ChannelWebChat Channel = "WEB_CHAT"
ConversationOpen ConversationState = "OPEN"
ConversationArchived ConversationState = "ARCHIVED"
SpeechActDirective SpeechAct = "DIRECTIVE"
SpeechActAssertion SpeechAct = "ASSERTION"
SpeechActDecision SpeechAct = "DECISION"
SpeechActPreference SpeechAct = "PREFERENCE"
SpeechActQuestion SpeechAct = "QUESTION"
SpeechActHypothesis SpeechAct = "HYPOTHESIS"
SpeechActCorrection SpeechAct = "CORRECTION"
SpeechActRequestToInvestigate SpeechAct = "REQUEST_TO_INVESTIGATE"
SpeechActConfirmation SpeechAct = "CONFIRMATION"
SpeechActRejection SpeechAct = "REJECTION"
SpeechActCancellation SpeechAct = "CANCELLATION"
SpeechActConversational SpeechAct = "CONVERSATIONAL"
SpeechActUnknown SpeechAct = "UNKNOWN"
InterpretationRecorded InterpretationState = "RECORDED"
InterpretationInterpreted InterpretationState = "INTERPRETED"
RelationCorrects InteractionRelationKind = "CORRECTS"
RelationRespondsTo InteractionRelationKind = "RESPONDS_TO"
RelationRequestsCognition InteractionRelationKind = "REQUESTS_COGNITION"
RelationCognitionFallback InteractionRelationKind = "COGNITION_FALLBACK"
RelationSupersedes InteractionRelationKind = "SUPERSEDES"
RelationClarifies InteractionRelationKind = "CLARIFIES"
ProjectRolePrimary ProjectReferenceRole = "PRIMARY"
ProjectRoleRelated ProjectReferenceRole = "RELATED"
ProjectRoleReferenceSource ProjectReferenceRole = "REFERENCE_SOURCE"
ClarificationNotRequired ClarificationState = "NOT_REQUIRED"
ClarificationRequired ClarificationState = "REQUIRED"
SemanticApplicable SemanticApplicability = "APPLICABLE"
SemanticLowConfidence SemanticApplicability = "LOW_CONFIDENCE"
SemanticMixedIntent SemanticApplicability = "MIXED_INTENT"
SemanticNeedsBroaderInterpret SemanticApplicability = "NEEDS_BROADER_INTERPRETATION"
SemanticCandidateClarify SemanticApplicability = "CLARIFICATION_REQUIRED"
CandidateSourceDeterministic SemanticCandidateSource = "DETERMINISTIC_V2"
CandidateSourceCognitive SemanticCandidateSource = "COGNITIVE_V1"
CandidateSelected SemanticCandidateSelectionState = "SELECTED"
CandidateObserved SemanticCandidateSelectionState = "OBSERVED"
CandidateRejected SemanticCandidateSelectionState = "REJECTED"
InformationRequestCapabilityInventory InformationRequestKind = "CAPABILITY_INVENTORY"
InformationRequestCognitiveModelInventory InformationRequestKind = "COGNITIVE_MODEL_INVENTORY"
InformationRequestCognitiveChannelStatus InformationRequestKind = "COGNITIVE_CHANNEL_STATUS"
InformationRequestCognitiveRecovery InformationRequestKind = "COGNITIVE_RECOVERY"
InformationRequestMemoryInventory InformationRequestKind = "MEMORY_INVENTORY"
InformationRequestTimeDifference InformationRequestKind = "TIME_DIFFERENCE"
IngressText IngressModality = "TEXT"
IngressAudio IngressModality = "AUDIO"
IngressImage IngressModality = "IMAGE"
IngressVideo IngressModality = "VIDEO"
IngressDevice IngressModality = "DEVICE"
)
type IngressEnvelope struct {
ID string
Modality IngressModality
SourceRef string
DeviceRef string
LocationRef string
PrincipalID string
ArtifactRef string
ObservationRef string
ProviderRef string
ModelRef string
ModelVersion string
ConfidenceMillis int64
Degraded bool
RecordedAtUnixMillis int64
}
func (e IngressEnvelope) Valid() bool {
return e.ID != "" && e.Modality != "" && e.SourceRef != "" && e.ConfidenceMillis >= 0 && e.ConfidenceMillis <= 1000 && e.RecordedAtUnixMillis > 0 && (!e.Degraded || e.ObservationRef == "")
}
const (
ChannelWebChat Channel = "WEB_CHAT"
ConversationOpen ConversationState = "OPEN"
ConversationArchived ConversationState = "ARCHIVED"
SpeechActDirective SpeechAct = "DIRECTIVE"
SpeechActAssertion SpeechAct = "ASSERTION"
SpeechActDecision SpeechAct = "DECISION"
SpeechActPreference SpeechAct = "PREFERENCE"
SpeechActQuestion SpeechAct = "QUESTION"
SpeechActHypothesis SpeechAct = "HYPOTHESIS"
SpeechActCorrection SpeechAct = "CORRECTION"
SpeechActRequestToInvestigate SpeechAct = "REQUEST_TO_INVESTIGATE"
SpeechActConfirmation SpeechAct = "CONFIRMATION"
SpeechActRejection SpeechAct = "REJECTION"
SpeechActCancellation SpeechAct = "CANCELLATION"
SpeechActConversational SpeechAct = "CONVERSATIONAL"
SpeechActUnknown SpeechAct = "UNKNOWN"
InterpretationRecorded InterpretationState = "RECORDED"
InterpretationInterpreted InterpretationState = "INTERPRETED"
RelationCorrects InteractionRelationKind = "CORRECTS"
RelationRespondsTo InteractionRelationKind = "RESPONDS_TO"
RelationRequestsCognition InteractionRelationKind = "REQUESTS_COGNITION"
RelationCognitionFallback InteractionRelationKind = "COGNITION_FALLBACK"
RelationSupersedes InteractionRelationKind = "SUPERSEDES"
RelationClarifies InteractionRelationKind = "CLARIFIES"
ProjectRolePrimary ProjectReferenceRole = "PRIMARY"
ProjectRoleRelated ProjectReferenceRole = "RELATED"
ProjectRoleReferenceSource ProjectReferenceRole = "REFERENCE_SOURCE"
ClarificationNotRequired ClarificationState = "NOT_REQUIRED"
ClarificationRequired ClarificationState = "REQUIRED"
SemanticApplicable SemanticApplicability = "APPLICABLE"
SemanticLowConfidence SemanticApplicability = "LOW_CONFIDENCE"
SemanticMixedIntent SemanticApplicability = "MIXED_INTENT"
SemanticNeedsBroaderInterpret SemanticApplicability = "NEEDS_BROADER_INTERPRETATION"
SemanticCandidateClarify SemanticApplicability = "CLARIFICATION_REQUIRED"
CandidateSourceDeterministic SemanticCandidateSource = "DETERMINISTIC_V2"
CandidateSourceCognitive SemanticCandidateSource = "COGNITIVE_V1"
CandidateSelected SemanticCandidateSelectionState = "SELECTED"
CandidateObserved SemanticCandidateSelectionState = "OBSERVED"
CandidateRejected SemanticCandidateSelectionState = "REJECTED"
InformationRequestCapabilityInventory InformationRequestKind = "CAPABILITY_INVENTORY"
InformationRequestLocalCapabilityInventory InformationRequestKind = "LOCAL_CAPABILITY_INVENTORY"
InformationRequestCognitiveModelInventory InformationRequestKind = "COGNITIVE_MODEL_INVENTORY"
InformationRequestCognitiveCurrentModel InformationRequestKind = "COGNITIVE_CURRENT_MODEL"
InformationRequestCognitiveChannelStatus InformationRequestKind = "COGNITIVE_CHANNEL_STATUS"
InformationRequestCognitiveRecovery InformationRequestKind = "COGNITIVE_RECOVERY"
InformationRequestMemoryInventory InformationRequestKind = "MEMORY_INVENTORY"
InformationRequestTimeDifference InformationRequestKind = "TIME_DIFFERENCE"
InformationRequestResearchFailureExplanation InformationRequestKind = "RESEARCH_FAILURE_EXPLANATION"
ConfigurationCommandSet ConfigurationCommandKind = "SET"
ConfigurationCommandQuery ConfigurationCommandKind = "QUERY"
)
type Conversation struct {
@@ -103,6 +146,18 @@ type OriginalHumanIntent struct {
RecordedAtUnixMillis int64
Text string
}
// ConfigurationCommand is Interaction-owned intent. Configuration remains
// the only owner allowed to materialise a SettingAssignment.
type ConfigurationCommand struct {
Kind ConfigurationCommandKind
PrincipalID string
DefinitionRef string
TypedValue string
TemporaryOverride bool
SessionRef string
SourceRef string
}
type InteractionRelation struct {
ID InteractionRelationID
FromUtteranceID HumanUtteranceID
+9
View File
@@ -0,0 +1,9 @@
# SELF contract boundary
SELF owns evidence-backed competence, weakness, dependency, learning, and
self-evaluation records. Raw evidence remains Epistemics-owned; capability
health remains Capability-owned; tasks and development remain Work-owned;
release switching remains Supervisor/runtime-owned.
SELF is observational/evaluative and is not a mandatory request-path
orchestrator or an authority source.
+25
View File
@@ -0,0 +1,25 @@
package self
type BenchmarkCaseRef string
type PersonalBenchmark struct {
ID string
PrincipalID string
ApprovedCaseRefs []BenchmarkCaseRef
GoalProfile []string
PreferenceEvidenceRefs []SemanticReference
RecordedAt int64
}
type BenchmarkEvaluation struct {
CaseRef BenchmarkCaseRef
Path string
QualityMillis int64
ReliabilityMillis int64
LatencyMillis int64
CostMicros int64
CorrectionCount int64
EvidenceRefs []SemanticReference
}
func (e BenchmarkEvaluation) Valid() bool {
return e.CaseRef != "" && len(e.EvidenceRefs) > 0 && e.QualityMillis >= 0 && e.ReliabilityMillis >= 0 && e.CorrectionCount >= 0
}
+7
View File
@@ -0,0 +1,7 @@
package self
import "git.cin.su/m/Assistant/platform/ids"
// SemanticReference lets SELF cite evidence and capabilities without owning
// their canonical state.
type SemanticReference = ids.SemanticRef
+92
View File
@@ -0,0 +1,92 @@
package self
import "fmt"
type AssessmentID string
type LearningLedgerEntryID string
type AssessmentState string
const (
AssessmentCandidate AssessmentState = "CANDIDATE"
AssessmentConfirmed AssessmentState = "CONFIRMED"
AssessmentMonitoring AssessmentState = "MONITORING"
AssessmentResolved AssessmentState = "RESOLVED"
)
type CompetenceAssessment struct {
ID AssessmentID
PrincipalID string
SubjectRef SemanticReference
Revision uint64
ContextMatcher []string
QualityMillis int64
ReliabilityMillis int64
ConfidenceMillis int64
EvidenceRefs []SemanticReference
LastValidatedAt int64
AssessedAt int64
SupersedesRef *SemanticReference
}
type WeaknessPattern struct {
ID AssessmentID
PrincipalID string
Revision uint64
PatternKey string
ContextMatcher []string
FailureMode string
DetectionEvidenceRefs []SemanticReference
State AssessmentState
RecordedAt int64
}
type DependencyAssessment struct {
ID AssessmentID
SubjectRef SemanticReference
DependencyRef SemanticReference
ImpactClass string
CurrentEffect string
EvidenceRefs []SemanticReference
AssessedAt int64
}
type ImprovementNeed struct {
ID AssessmentID
PrincipalID string
SubjectRef SemanticReference
ProblemSummary string
EvidenceRefs []SemanticReference
ExpectedBenefit string
Priority int
State string
CreatedAt int64
}
type LearningLedgerEntry struct {
ID LearningLedgerEntryID
PrincipalID string
ImprovementNeedRef *SemanticReference
ObservedProblem string
EvidenceRefs []SemanticReference
Diagnosis string
Hypothesis string
ProposedChangeRef SemanticReference
ExpectedImprovement string
ActualEvaluationRefs []SemanticReference
DevelopmentGateRef *SemanticReference
BeforeVersionRefs []SemanticReference
AfterVersionRefs []SemanticReference
Decision string
SideEffects []string
RollbackRef *SemanticReference
RecordedAt int64
}
func (a CompetenceAssessment) Validate() error {
if a.ID == "" || a.PrincipalID == "" || !a.SubjectRef.Valid() || a.Revision < 1 || a.ConfidenceMillis < 0 || a.ConfidenceMillis > 1000 || len(a.EvidenceRefs) == 0 || a.AssessedAt < 1 {
return fmt.Errorf("competence requires evidence")
}
return nil
}
func (l LearningLedgerEntry) Validate() error {
if l.ID == "" || l.PrincipalID == "" || l.ObservedProblem == "" || len(l.EvidenceRefs) == 0 || l.Decision == "" || l.RecordedAt < 1 {
return fmt.Errorf("learning ledger entry is incomplete")
}
return nil
}
+141
View File
@@ -0,0 +1,141 @@
package situation
import (
"fmt"
"git.cin.su/m/Assistant/contracts/authority"
"git.cin.su/m/Assistant/contracts/identity"
"git.cin.su/m/Assistant/contracts/work"
"git.cin.su/m/Assistant/platform/clock"
"git.cin.su/m/Assistant/platform/ids"
)
type ContextScopeID ids.StableID
type FocusFrameID ids.StableID
type FocusTransitionID ids.StableID
type FocusRevision ids.Revision
type RoleKey string
type MatchPolicy string
type FocusFrameState string
type FocusProvenance string
type FocusTransitionOperation string
const (
MatchRequired MatchPolicy = "REQUIRED"
MatchPreferred MatchPolicy = "PREFERRED"
MatchRelated MatchPolicy = "RELATED"
MatchExcluded MatchPolicy = "EXCLUDED"
RolePerson RoleKey = "PERSON"
RoleOrganization RoleKey = "ORGANIZATION"
RoleFamily RoleKey = "FAMILY"
RoleEnvironment RoleKey = "ENVIRONMENT"
RoleLocation RoleKey = "LOCATION"
RoleSystem RoleKey = "SYSTEM"
RoleDatabase RoleKey = "DATABASE"
RoleRepository RoleKey = "REPOSITORY"
RoleBranch RoleKey = "BRANCH"
RoleVersion RoleKey = "VERSION"
RoleActivity RoleKey = "ACTIVITY"
RoleProject RoleKey = "PROJECT"
RoleActiveEntity RoleKey = "ACTIVE_ENTITY"
FocusCandidate FocusFrameState = "CANDIDATE"
FocusActive FocusFrameState = "ACTIVE"
FocusSuspended FocusFrameState = "SUSPENDED"
FocusExpired FocusFrameState = "EXPIRED"
FocusSuperseded FocusFrameState = "SUPERSEDED"
FocusExplicitHuman FocusProvenance = "EXPLICIT_HUMAN"
FocusUserConfirmed FocusProvenance = "USER_CONFIRMED"
FocusInherited FocusProvenance = "INHERITED"
FocusEntityReference FocusProvenance = "ENTITY_REFERENCE"
FocusTaskReference FocusProvenance = "TASK_REFERENCE"
FocusRepositoryReference FocusProvenance = "REPOSITORY_REFERENCE"
FocusEnvironmentObservation FocusProvenance = "ENVIRONMENT_OBSERVATION"
FocusInferred FocusProvenance = "INFERRED"
TransitionActivate FocusTransitionOperation = "ACTIVATE"
TransitionSuspend FocusTransitionOperation = "SUSPEND"
TransitionResume FocusTransitionOperation = "RESUME"
TransitionSupersede FocusTransitionOperation = "SUPERSEDE"
TransitionExpire FocusTransitionOperation = "EXPIRE"
)
type ContextBinding struct {
RoleKey RoleKey
TargetRef SemanticReference
MatchPolicy MatchPolicy
Provenance string
ConfidenceMillis int64
SourceRef *SemanticReference
}
type ContextScope struct {
ID ContextScopeID
PrincipalID identity.PrincipalID
Revision FocusRevision
Bindings []ContextBinding
RecordedAt clock.Instant
}
type FocusFrame struct {
ID FocusFrameID
PrincipalID identity.PrincipalID
ActorID identity.ActorID
Revision FocusRevision
AuthorityScopeRef authority.ScopeID
ContextScopeRef SemanticReference
GoalRef *work.GoalID
TaskRef *work.TaskID
SourceUtteranceRef string
Provenance FocusProvenance
ConfidenceMillis int64
State FocusFrameState
ParentFrameRef *FocusFrameID
ActivatedAt clock.Instant
SuspendedAt *clock.Instant
ExpiredAt *clock.Instant
RecordedAt clock.Instant
}
type FocusTransition struct {
TransitionID FocusTransitionID
FrameID FocusFrameID
FromRevision FocusRevision
ToRevision FocusRevision
Operation FocusTransitionOperation
CauseRef string
RecordedAt clock.Instant
}
func (s ContextScope) Validate() error {
if s.ID == "" || s.PrincipalID == "" || !ids.Revision(s.Revision).Valid() || !s.RecordedAt.Valid() {
return fmt.Errorf("invalid context scope")
}
for _, b := range s.Bindings {
if b.RoleKey == "" || !b.TargetRef.Valid() || !validMatchPolicy(b.MatchPolicy) {
return fmt.Errorf("invalid context binding")
}
}
return nil
}
func (f FocusFrame) Validate() error {
if f.ID == "" || f.PrincipalID == "" || f.ActorID == "" || !ids.Revision(f.Revision).Valid() || !f.ContextScopeRef.Valid() || f.State == "" || f.Provenance == "" || !f.RecordedAt.Valid() {
return fmt.Errorf("invalid focus frame")
}
return nil
}
func (t FocusTransition) Validate() error {
if t.TransitionID == "" || t.FrameID == "" || !ids.Revision(t.FromRevision).Valid() || !ids.Revision(t.ToRevision).Valid() || t.Operation == "" || !t.RecordedAt.Valid() {
return fmt.Errorf("invalid focus transition")
}
return nil
}
func validMatchPolicy(p MatchPolicy) bool {
return p == MatchRequired || p == MatchPreferred || p == MatchRelated || p == MatchExcluded
}
+22
View File
@@ -0,0 +1,22 @@
package situation_test
import (
"testing"
"git.cin.su/m/Assistant/contracts/identity"
contract "git.cin.su/m/Assistant/contracts/situation"
"git.cin.su/m/Assistant/platform/clock"
"git.cin.su/m/Assistant/platform/ids"
)
func TestFocusV2ContractsValidateTypedScopeAndFrame(t *testing.T) {
rev := ids.Revision(1)
scope := contract.ContextScope{ID: "scope", PrincipalID: identity.PrincipalID("company-a"), Revision: contract.FocusRevision(rev), RecordedAt: clock.Instant(1), Bindings: []contract.ContextBinding{{RoleKey: contract.RoleOrganization, TargetRef: contract.SemanticReference{OwnerNamespace: "world", SemanticKind: "organization", StableID: "a"}, MatchPolicy: contract.MatchRequired}}}
if err := scope.Validate(); err != nil {
t.Fatal(err)
}
frame := contract.FocusFrame{ID: "frame", PrincipalID: scope.PrincipalID, ActorID: "actor", Revision: 1, ContextScopeRef: contract.SemanticReference{OwnerNamespace: "situation", SemanticKind: "context_scope", StableID: ids.StableID(scope.ID), Revision: &rev}, State: contract.FocusActive, Provenance: contract.FocusExplicitHuman, RecordedAt: 1}
if err := frame.Validate(); err != nil {
t.Fatal(err)
}
}
+7
View File
@@ -0,0 +1,7 @@
package situation
import "git.cin.su/m/Assistant/platform/ids"
// SemanticReference keeps Situation references transport-neutral while
// ContextScope semantics remain owned by Situation.
type SemanticReference = ids.SemanticRef
+24
View File
@@ -0,0 +1,24 @@
package work
type ConsequenceAssessment struct {
ID string
TargetRefs []string
Impact int64
Reversibility int64
Uncertainty int64
Scope int64
Recoverability int64
CostOfError int64
ExpectedConsequences []string
MitigationOptions []string
RequiresDryRun bool
RequiresBackup bool
RecommendedConfirmation string
OwnerAccepted bool
EvidenceRefs []EvidenceRef
RecordedAtUnixMillis int64
}
func (a ConsequenceAssessment) Valid() bool {
return a.ID != "" && len(a.TargetRefs) > 0 && a.Impact >= 0 && a.Impact <= 1000 && a.Reversibility >= 0 && a.Reversibility <= 1000 && a.Uncertainty >= 0 && a.Uncertainty <= 1000 && a.Recoverability >= 0 && a.Recoverability <= 1000 && a.RecordedAtUnixMillis > 0
}
+28
View File
@@ -0,0 +1,28 @@
package work
import "git.cin.su/m/Assistant/contracts/world"
type FreshnessRequirementMode string
type FreshnessFallbackPolicy string
const (
FreshnessAny FreshnessRequirementMode = "ANY"
FreshnessPreferCurrent FreshnessRequirementMode = "PREFER_CURRENT"
FreshnessRequireCurrent FreshnessRequirementMode = "REQUIRE_CURRENT"
FreshnessRequireWithinAge FreshnessRequirementMode = "REQUIRE_WITHIN_AGE"
FreshnessRequireVersionMatch FreshnessRequirementMode = "REQUIRE_VERSION_MATCH"
FreshnessLiveRequired FreshnessRequirementMode = "LIVE_REQUIRED"
FallbackAllowStaleDisclosure FreshnessFallbackPolicy = "ALLOW_STALE_WITH_DISCLOSURE"
FallbackHypothesisOnly FreshnessFallbackPolicy = "USE_AS_HYPOTHESIS_ONLY"
FallbackWaitForSource FreshnessFallbackPolicy = "WAIT_FOR_SOURCE"
FallbackAskOwner FreshnessFallbackPolicy = "ASK_OWNER"
FallbackStopUnknown FreshnessFallbackPolicy = "STOP_WITH_UNKNOWN"
)
type TaskFreshnessRequirement struct {
Mode FreshnessRequirementMode
MaximumAgeMillis *int64
RequiredVersionRefs []world.SemanticReference
RevalidationRequired bool
FallbackPolicy FreshnessFallbackPolicy
}
+39
View File
@@ -0,0 +1,39 @@
package work
type EvolutionRunStage string
const (
EvolutionNeedRecorded EvolutionRunStage = "IMPROVEMENT_NEED"
EvolutionCandidateBuilt EvolutionRunStage = "CANDIDATE"
EvolutionIndependentlyEvaluated EvolutionRunStage = "INDEPENDENT_EVALUATION"
EvolutionSandboxed EvolutionRunStage = "SANDBOX_BUILD"
EvolutionBenchmarked EvolutionRunStage = "BENCHMARK"
EvolutionCanaried EvolutionRunStage = "CANARY"
EvolutionPromoted EvolutionRunStage = "PROMOTION"
EvolutionRolledBack EvolutionRunStage = "ROLLBACK"
)
type GovernedEvolutionResult struct {
NeedRef string
CandidateRef string
EvaluationRef string
Stages []EvolutionRunStage
EvidenceRefs []EvidenceRef
LearningLedgerOutcomeRef string
Promoted bool
RollbackRef string
}
// GovernedEvolutionOps are explicit gates. The caller supplies existing
// development executor/supervisor operations; this interface grants no new
// authority and has no autonomous promotion implementation.
type GovernedEvolutionOps struct {
CreateCandidate func() (EvolutionCandidate, error)
Evaluate func(EvolutionCandidate) (EvolutionEvaluation, error)
SandboxBuild func(EvolutionCandidate) (EvidenceRef, error)
Benchmark func(EvolutionCandidate) (EvidenceRef, bool, error)
Canary func(EvolutionCandidate) (EvidenceRef, bool, error)
Promote func(EvolutionCandidate, EvolutionEvaluation) (string, error)
Rollback func(EvolutionCandidate) (string, error)
LearningLedgerOutcome func(GovernedEvolutionResult) (string, error)
}
+51
View File
@@ -0,0 +1,51 @@
package work
type LongRunningWorkID string
type LongRunningState string
const (
LongRunningProposed LongRunningState = "PROPOSED"
LongRunningRunning LongRunningState = "RUNNING"
LongRunningPaused LongRunningState = "PAUSED"
LongRunningBlocked LongRunningState = "BLOCKED"
LongRunningCompleted LongRunningState = "COMPLETED"
LongRunningExhausted LongRunningState = "EXHAUSTED"
LongRunningCancelled LongRunningState = "CANCELLED"
)
type Investigation struct {
ID LongRunningWorkID
Objective string
HypothesisRefs []EvidenceRef
AttemptRefs []AgentRunID
FindingRefs []EvidenceRef
Blockers []string
CheckpointRefs []AgentCheckpointID
NextStep string
State LongRunningState
Revision int64
TimeBudgetMillis int64
CostBudgetMicros int64
MaxAttempts int
RecordedAtUnixMillis int64
}
// InvestigationCheckpoint is the durable boundary between attempts. A
// checkpoint is written only after an attempt has been verified, so a worker
// restart can resume at NextStep without replaying that attempt.
type InvestigationCheckpoint struct {
ID AgentCheckpointID
InvestigationID LongRunningWorkID
CompletedAttemptRefs []AgentRunID
CompletedFindingRefs []EvidenceRef
NextStep string
RecordedAtUnixMillis int64
}
func (c InvestigationCheckpoint) Valid() bool {
return c.ID != "" && c.InvestigationID != "" && c.NextStep != "" && c.RecordedAtUnixMillis > 0
}
func (w Investigation) Valid() bool {
return w.ID != "" && w.Objective != "" && w.State != "" && w.Revision > 0 && w.TimeBudgetMillis >= 0 && w.CostBudgetMicros >= 0 && w.MaxAttempts >= 0 && w.RecordedAtUnixMillis > 0
}
+32
View File
@@ -0,0 +1,32 @@
package work
type PerspectiveID string
type PerspectiveSpec struct {
ID PerspectiveID
ObjectiveLens string
FocusRef string
RetrievalProfileRef string
SkillRefs []string
ToolRefs []string
EvaluationCriteria []string
CapabilityRequirements []string
ExpectedOutputShape string
Critic bool
}
type SpecialistAssignment struct {
Perspective PerspectiveSpec
SubtaskRef string
FocusRef string
SkillRefs []string
ToolRefs []string
EvidenceRefs []EvidenceRef
}
type TeamDecision struct {
UseTeam bool
Reason string
Assignments []SpecialistAssignment
}
func (p PerspectiveSpec) Valid() bool {
return p.ID != "" && p.ObjectiveLens != "" && p.FocusRef != "" && len(p.SkillRefs) > 0 && len(p.ToolRefs) > 0 && len(p.EvaluationCriteria) > 0 && p.ExpectedOutputShape != ""
}
+36
View File
@@ -0,0 +1,36 @@
package work
type EvolutionChangeLevel string
const (
EvolutionKnowledge EvolutionChangeLevel = "KNOWLEDGE"
EvolutionBehavior EvolutionChangeLevel = "BEHAVIOR"
EvolutionCapability EvolutionChangeLevel = "CAPABILITY"
EvolutionCore EvolutionChangeLevel = "CORE"
)
type EvolutionCandidate struct {
ID string
ProposalRef string
ChangeLevel EvolutionChangeLevel
CreatorIdentity string
BaseVersionRef string
CandidateVersionRef string
MustNotWorsen []string
SandboxEvidenceRefs []EvidenceRef
BenchmarkEvidenceRefs []EvidenceRef
RollbackRef string
State string
}
type EvolutionEvaluation struct {
CandidateRef string
EvaluatorIdentity string
Approved bool
EvidenceRefs []EvidenceRef
MustNotWorsenPassed bool
RecordedAtUnixMillis int64
}
func (e EvolutionEvaluation) ValidFor(c EvolutionCandidate) bool {
return e.CandidateRef == c.ID && e.EvaluatorIdentity != "" && e.EvaluatorIdentity != c.CreatorIdentity && e.Approved && e.MustNotWorsenPassed && len(e.EvidenceRefs) > 0 && e.RecordedAtUnixMillis > 0
}
+9
View File
@@ -0,0 +1,9 @@
# World contract boundary
World owns typed, versioned referents and vocabulary: `WorldObject`, kind and
facet/relation definitions, aliases, identity-resolution decisions, and
merge/split lineage. It does not own observations, claims, beliefs, or the
truth of values about a referent; those remain Epistemics-owned evidence.
Cross-owner references are typed semantic references. They do not create
cross-owner foreign keys, joins, writes, or a generic `Entity(any)` API.
+322
View File
@@ -0,0 +1,322 @@
package world
import (
"fmt"
"git.cin.su/m/Assistant/contracts/identity"
"git.cin.su/m/Assistant/platform/clock"
"git.cin.su/m/Assistant/platform/ids"
)
// SemanticReference is the transport envelope used by World contracts. It is
// a reference only; it does not expose another owner's storage.
type SemanticReference = ids.SemanticRef
// VersionBinding is a typed applicability constraint. Absence of VersionRef
// means unknown, never an implicit "latest".
type VersionMatchMode string
const (
VersionExact VersionMatchMode = "EXACT"
VersionCompatibleFamily VersionMatchMode = "COMPATIBLE_FAMILY"
VersionAtOrBefore VersionMatchMode = "AT_OR_BEFORE"
VersionUnknown VersionMatchMode = "UNKNOWN"
)
type VersionBinding struct {
SubjectRef SemanticReference
VersionRef SemanticReference
MatchMode VersionMatchMode
}
type EnvironmentReference struct {
EnvironmentRef SemanticReference
VersionRef *SemanticReference
}
func (b VersionBinding) Validate() error {
if !b.SubjectRef.Valid() || !b.VersionRef.Valid() {
return fmt.Errorf("version binding references are invalid")
}
if b.MatchMode != VersionExact && b.MatchMode != VersionCompatibleFamily && b.MatchMode != VersionAtOrBefore && b.MatchMode != VersionUnknown {
return fmt.Errorf("version binding match mode is invalid")
}
return nil
}
func (r EnvironmentReference) Validate() error {
if !r.EnvironmentRef.Valid() {
return fmt.Errorf("environment reference is invalid")
}
if r.VersionRef != nil && !r.VersionRef.Valid() {
return fmt.Errorf("environment version reference is invalid")
}
return nil
}
type PrincipalRealm string
const (
RealmPersonal PrincipalRealm = "PERSONAL"
RealmShared PrincipalRealm = "SHARED"
RealmPublic PrincipalRealm = "PUBLIC"
RealmSystem PrincipalRealm = "SYSTEM"
)
type SensitivityClass string
const (
SensitivityPublic SensitivityClass = "PUBLIC"
SensitivityPrivate SensitivityClass = "PRIVATE"
SensitivityRestricted SensitivityClass = "RESTRICTED"
SensitivitySecretReference SensitivityClass = "SECRET_REFERENCE"
)
type ValueTypeKind string
const (
ValueString ValueTypeKind = "STRING"
ValueInteger ValueTypeKind = "INTEGER"
ValueDecimal ValueTypeKind = "DECIMAL"
ValueBoolean ValueTypeKind = "BOOLEAN"
ValueTime ValueTypeKind = "TIME"
ValueDuration ValueTypeKind = "DURATION"
ValueEnum ValueTypeKind = "ENUM"
ValueReference ValueTypeKind = "REFERENCE"
ValueBinaryRef ValueTypeKind = "BINARY_REF"
ValueList ValueTypeKind = "LIST"
ValueStruct ValueTypeKind = "STRUCT"
)
type ValueField struct {
Name string
Type ValueTypeSpec
}
type ValueTypeSpec struct {
Kind ValueTypeKind
Element *ValueTypeSpec
Fields []ValueField
EnumValues []string
ReferenceKind string
}
type WorldObjectID ids.StableID
type KindDefinitionID ids.StableID
type WorldAliasID ids.StableID
type PersonReferent struct {
WorldObjectRef SemanticReference
DisplayName string
ConfidenceMillis int64
}
func (p PersonReferent) Valid() bool {
return p.WorldObjectRef.Valid() && p.DisplayName != "" && p.ConfidenceMillis >= 0 && p.ConfidenceMillis <= 1000
}
type FacetDefinitionID ids.StableID
type RelationDefinitionID ids.StableID
type ResolutionDecisionID ids.StableID
type LineageID ids.StableID
type LifecycleState string
const (
LifecycleActive LifecycleState = "ACTIVE"
LifecycleMerged LifecycleState = "MERGED"
LifecycleSplit LifecycleState = "SPLIT"
LifecycleRetired LifecycleState = "RETIRED"
LifecycleUnknownIdentity LifecycleState = "UNKNOWN_IDENTITY"
)
type WorldObject struct {
ID WorldObjectID
PrincipalID identity.PrincipalID
KindDefinitionRef SemanticReference
KindRevision ids.Revision
Lifecycle LifecycleState
CreatedAt clock.Instant
}
type WorldObjectKindDefinition struct {
ID KindDefinitionID
KindKey string
Revision ids.Revision
DisplayName string
ParentKindRef *SemanticReference
Lifecycle LifecycleState
DefinitionDigest string
RecordedAt clock.Instant
}
type WorldAlias struct {
ID WorldAliasID
PrincipalID identity.PrincipalID
ObjectID WorldObjectID
Alias string
RecordedAt clock.Instant
}
type FacetDefinition struct {
ID FacetDefinitionID
KindKey string
Revision ids.Revision
FacetKey string
ValueType ValueTypeSpec
DefinitionDigest string
RecordedAt clock.Instant
}
type RelationDefinition struct {
ID RelationDefinitionID
KindKey string
Revision ids.Revision
RelationKey string
TargetKindKey string
DefinitionDigest string
RecordedAt clock.Instant
}
type ResolutionDecision string
const (
ResolutionSame ResolutionDecision = "SAME"
ResolutionDistinct ResolutionDecision = "DISTINCT"
ResolutionMerge ResolutionDecision = "MERGE"
ResolutionSplit ResolutionDecision = "SPLIT"
ResolutionUnresolved ResolutionDecision = "UNRESOLVED"
)
type IdentityResolutionCandidate struct {
ObjectRef SemanticReference
Evidence []SemanticReference
Confidence int64
}
type IdentityResolutionDecisionRecord struct {
ID ResolutionDecisionID
PrincipalID identity.PrincipalID
Candidates []IdentityResolutionCandidate
Decision ResolutionDecision
Evidence []SemanticReference
ConfidenceMillis int64
DecidedAt clock.Instant
Revision ids.Revision
}
type WorldLineage struct {
ID LineageID
Operation ResolutionDecision
SourceRefs []SemanticReference
SuccessorRefs []SemanticReference
RecordedAt clock.Instant
}
func (w WorldObject) Validate() error {
if w.ID == "" || !w.KindDefinitionRef.Valid() || !w.KindRevision.Valid() || !validLifecycle(w.Lifecycle) || !w.CreatedAt.Valid() {
return fmt.Errorf("world object is incomplete")
}
return nil
}
func (k WorldObjectKindDefinition) Validate() error {
if k.ID == "" || k.KindKey == "" || !k.Revision.Valid() || k.DisplayName == "" || !validLifecycle(k.Lifecycle) || k.DefinitionDigest == "" || !k.RecordedAt.Valid() {
return fmt.Errorf("world kind definition is incomplete")
}
if k.ParentKindRef != nil && !k.ParentKindRef.Valid() {
return fmt.Errorf("world kind parent reference is invalid")
}
return nil
}
func (a WorldAlias) Validate() error {
if a.ID == "" || a.ObjectID == "" || a.Alias == "" || !a.RecordedAt.Valid() {
return fmt.Errorf("world alias is incomplete")
}
return nil
}
func (f FacetDefinition) Validate() error {
if f.ID == "" || f.KindKey == "" || !f.Revision.Valid() || f.FacetKey == "" || f.DefinitionDigest == "" || !f.RecordedAt.Valid() {
return fmt.Errorf("facet definition is incomplete")
}
return f.ValueType.Validate()
}
func (r RelationDefinition) Validate() error {
if r.ID == "" || r.KindKey == "" || !r.Revision.Valid() || r.RelationKey == "" || r.TargetKindKey == "" || r.DefinitionDigest == "" || !r.RecordedAt.Valid() {
return fmt.Errorf("relation definition is incomplete")
}
return nil
}
func (d IdentityResolutionDecisionRecord) Validate() error {
if d.ID == "" || !validDecision(d.Decision) || len(d.Candidates) == 0 || d.ConfidenceMillis < 0 || !d.DecidedAt.Valid() || !d.Revision.Valid() {
return fmt.Errorf("identity resolution decision is incomplete")
}
for _, candidate := range d.Candidates {
if !candidate.ObjectRef.Valid() || candidate.Confidence < 0 || candidate.Confidence > 1000 {
return fmt.Errorf("identity resolution candidate is invalid")
}
for _, evidence := range candidate.Evidence {
if !evidence.Valid() {
return fmt.Errorf("identity resolution evidence reference is invalid")
}
}
}
return nil
}
func (l WorldLineage) Validate() error {
if l.ID == "" || (l.Operation != ResolutionMerge && l.Operation != ResolutionSplit) || len(l.SourceRefs) == 0 || len(l.SuccessorRefs) == 0 || !l.RecordedAt.Valid() {
return fmt.Errorf("world lineage is incomplete")
}
return nil
}
func validLifecycle(value LifecycleState) bool {
return value == LifecycleActive || value == LifecycleMerged || value == LifecycleSplit || value == LifecycleRetired || value == LifecycleUnknownIdentity
}
func validDecision(value ResolutionDecision) bool {
return value == ResolutionSame || value == ResolutionDistinct || value == ResolutionMerge || value == ResolutionSplit || value == ResolutionUnresolved
}
func (s ValueTypeSpec) Validate() error {
if s.Kind == "" {
return fmt.Errorf("value type kind is required")
}
switch s.Kind {
case ValueList:
if s.Element == nil {
return fmt.Errorf("list element type is required")
}
return s.Element.Validate()
case ValueStruct:
if len(s.Fields) == 0 {
return fmt.Errorf("struct fields are required")
}
seen := map[string]struct{}{}
for _, field := range s.Fields {
if field.Name == "" {
return fmt.Errorf("struct field name is required")
}
if _, ok := seen[field.Name]; ok {
return fmt.Errorf("duplicate struct field %q", field.Name)
}
seen[field.Name] = struct{}{}
if err := field.Type.Validate(); err != nil {
return fmt.Errorf("field %s: %w", field.Name, err)
}
}
case ValueEnum:
if len(s.EnumValues) == 0 {
return fmt.Errorf("enum values are required")
}
case ValueReference:
if s.ReferenceKind == "" {
return fmt.Errorf("reference kind is required")
}
}
return nil
}
+17
View File
@@ -0,0 +1,17 @@
package world
import "testing"
func TestValueTypeSpecValidatesTypedRecursiveShape(t *testing.T) {
spec := ValueTypeSpec{Kind: ValueStruct, Fields: []ValueField{{Name: "name", Type: ValueTypeSpec{Kind: ValueString}}, {Name: "refs", Type: ValueTypeSpec{Kind: ValueList, Element: &ValueTypeSpec{Kind: ValueReference, ReferenceKind: "world.object"}}}}}
if err := spec.Validate(); err != nil {
t.Fatalf("ValueTypeSpec.Validate() = %v", err)
}
}
func TestValueTypeSpecRejectsDuplicateFields(t *testing.T) {
spec := ValueTypeSpec{Kind: ValueStruct, Fields: []ValueField{{Name: "same", Type: ValueTypeSpec{Kind: ValueString}}, {Name: "same", Type: ValueTypeSpec{Kind: ValueString}}}}
if err := spec.Validate(); err == nil {
t.Fatal("duplicate fields were accepted")
}
}
+22
View File
@@ -0,0 +1,22 @@
package world
import (
"testing"
"git.cin.su/m/Assistant/platform/clock"
"git.cin.su/m/Assistant/platform/ids"
)
func TestWorldObjectValidationKeepsReferentSeparateFromClaims(t *testing.T) {
object := WorldObject{ID: "object-1", KindDefinitionRef: ids.SemanticRef{OwnerNamespace: "world", SemanticKind: "kind", StableID: "kind-1"}, KindRevision: 1, Lifecycle: LifecycleActive, CreatedAt: clock.Instant(1)}
if err := object.Validate(); err != nil {
t.Fatalf("WorldObject.Validate() = %v", err)
}
}
func TestIdentityResolutionRequiresEvidenceBackedCandidates(t *testing.T) {
decision := IdentityResolutionDecisionRecord{ID: "decision-1", Decision: ResolutionSame, Candidates: []IdentityResolutionCandidate{{ObjectRef: ids.SemanticRef{OwnerNamespace: "world", SemanticKind: "object", StableID: "object-1"}, Confidence: 900}}, DecidedAt: clock.Instant(1), Revision: 1}
if err := decision.Validate(); err != nil {
t.Fatalf("IdentityResolutionDecisionRecord.Validate() = %v", err)
}
}
@@ -0,0 +1,82 @@
BEGIN;
CREATE SCHEMA IF NOT EXISTS world;
SET ROLE world_role;
CREATE TABLE IF NOT EXISTS world.kind_definitions (
kind_definition_id TEXT PRIMARY KEY,
kind_key TEXT NOT NULL,
revision BIGINT NOT NULL CHECK (revision > 0),
display_name TEXT NOT NULL,
parent_owner_namespace TEXT NOT NULL DEFAULT '',
parent_semantic_kind TEXT NOT NULL DEFAULT '',
parent_stable_id TEXT NOT NULL DEFAULT '',
parent_revision BIGINT,
lifecycle TEXT NOT NULL,
definition_digest TEXT NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0),
UNIQUE (kind_key, revision)
);
CREATE TABLE IF NOT EXISTS world.objects (
world_object_id TEXT PRIMARY KEY,
principal_id TEXT,
kind_owner_namespace TEXT NOT NULL,
kind_semantic_kind TEXT NOT NULL,
kind_stable_id TEXT NOT NULL,
kind_revision BIGINT,
lifecycle TEXT NOT NULL,
created_at_unix_millis BIGINT NOT NULL CHECK (created_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS world.aliases (
world_alias_id TEXT PRIMARY KEY,
principal_id TEXT,
world_object_id TEXT NOT NULL,
alias TEXT NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS world.facet_definitions (
facet_definition_id TEXT PRIMARY KEY,
kind_key TEXT NOT NULL,
revision BIGINT NOT NULL CHECK (revision > 0),
facet_key TEXT NOT NULL,
value_type JSONB NOT NULL,
definition_digest TEXT NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0),
UNIQUE (kind_key, facet_key, revision)
);
CREATE TABLE IF NOT EXISTS world.relation_definitions (
relation_definition_id TEXT PRIMARY KEY,
kind_key TEXT NOT NULL,
revision BIGINT NOT NULL CHECK (revision > 0),
relation_key TEXT NOT NULL,
target_kind_key TEXT NOT NULL,
definition_digest TEXT NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0),
UNIQUE (kind_key, relation_key, revision)
);
CREATE TABLE IF NOT EXISTS world.identity_resolution_decisions (
resolution_decision_id TEXT PRIMARY KEY,
principal_id TEXT,
candidates JSONB NOT NULL,
decision TEXT NOT NULL,
evidence JSONB NOT NULL,
confidence_millis BIGINT NOT NULL CHECK (confidence_millis >= 0),
decided_at_unix_millis BIGINT NOT NULL CHECK (decided_at_unix_millis > 0),
revision BIGINT NOT NULL CHECK (revision > 0)
);
CREATE TABLE IF NOT EXISTS world.lineage (
lineage_id TEXT PRIMARY KEY,
operation TEXT NOT NULL,
source_refs JSONB NOT NULL,
successor_refs JSONB NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0)
);
RESET ROLE;
COMMIT;
@@ -0,0 +1,47 @@
BEGIN;
SET ROLE situation_role;
CREATE TABLE IF NOT EXISTS situation.context_scopes (
context_scope_id TEXT PRIMARY KEY,
principal_id TEXT NOT NULL,
revision BIGINT NOT NULL CHECK (revision > 0),
bindings JSONB NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS situation.focus_frames (
focus_frame_id TEXT PRIMARY KEY,
principal_id TEXT NOT NULL,
actor_id TEXT NOT NULL,
revision BIGINT NOT NULL CHECK (revision > 0),
authority_scope_ref TEXT NOT NULL,
context_scope_ref JSONB NOT NULL,
goal_ref TEXT,
task_ref TEXT,
source_utterance_ref TEXT,
provenance TEXT NOT NULL,
confidence_millis BIGINT NOT NULL CHECK (confidence_millis >= 0),
state TEXT NOT NULL,
parent_frame_ref TEXT,
activated_at_unix_millis BIGINT NOT NULL CHECK (activated_at_unix_millis > 0),
suspended_at_unix_millis BIGINT,
expired_at_unix_millis BIGINT,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS situation.focus_transitions (
transition_id TEXT PRIMARY KEY,
focus_frame_id TEXT NOT NULL,
from_revision BIGINT NOT NULL CHECK (from_revision > 0),
to_revision BIGINT NOT NULL CHECK (to_revision > 0),
operation TEXT NOT NULL,
cause_ref TEXT NOT NULL,
recorded_at_unix_millis BIGINT NOT NULL CHECK (recorded_at_unix_millis > 0)
);
CREATE INDEX IF NOT EXISTS focus_transitions_frame_order ON situation.focus_transitions(focus_frame_id, recorded_at_unix_millis, transition_id);
GRANT SELECT, INSERT, UPDATE ON situation.context_scopes, situation.focus_frames, situation.focus_transitions TO situation_role;
RESET ROLE;
COMMIT;
@@ -0,0 +1,7 @@
BEGIN;
SET ROLE configuration_role;
CREATE TABLE IF NOT EXISTS configuration.setting_definitions (setting_definition_id TEXT PRIMARY KEY, owner_namespace TEXT NOT NULL, stable_key TEXT NOT NULL, revision BIGINT NOT NULL CHECK(revision>0), value_type TEXT NOT NULL, default_value TEXT, sensitivity TEXT NOT NULL, lifecycle TEXT NOT NULL, recorded_at_unix_millis BIGINT NOT NULL);
CREATE TABLE IF NOT EXISTS configuration.setting_assignments (setting_assignment_id TEXT PRIMARY KEY, principal_id TEXT NOT NULL, definition_ref JSONB NOT NULL, revision BIGINT NOT NULL CHECK(revision>0), selector JSONB NOT NULL, typed_value TEXT, secret_ref TEXT, effective_from_unix_millis BIGINT NOT NULL, effective_until_unix_millis BIGINT, source TEXT NOT NULL, source_ref TEXT NOT NULL, lifecycle TEXT NOT NULL, recorded_at_unix_millis BIGINT NOT NULL);
GRANT SELECT, INSERT, UPDATE ON configuration.setting_definitions, configuration.setting_assignments TO configuration_role;
RESET ROLE;
COMMIT;
@@ -0,0 +1,7 @@
BEGIN;
SET ROLE self_role;
CREATE TABLE IF NOT EXISTS self.competence_assessments (assessment_id TEXT PRIMARY KEY, principal_id TEXT NOT NULL, subject_ref JSONB NOT NULL, revision BIGINT NOT NULL CHECK(revision>0), context_matcher JSONB NOT NULL, confidence_millis BIGINT NOT NULL, evidence_refs JSONB NOT NULL, assessed_at_unix_millis BIGINT NOT NULL);
CREATE TABLE IF NOT EXISTS self.learning_ledger (entry_id TEXT PRIMARY KEY, principal_id TEXT NOT NULL, observed_problem TEXT NOT NULL, evidence_refs JSONB NOT NULL, diagnosis TEXT NOT NULL, hypothesis TEXT NOT NULL, decision TEXT NOT NULL, recorded_at_unix_millis BIGINT NOT NULL);
GRANT SELECT, INSERT, UPDATE ON self.competence_assessments, self.learning_ledger TO self_role;
RESET ROLE;
COMMIT;
@@ -0,0 +1,22 @@
BEGIN;
SET ROLE work_role;
CREATE TABLE IF NOT EXISTS work.long_running_work (
investigation_id TEXT PRIMARY KEY, objective TEXT NOT NULL,
hypothesis_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], attempt_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[],
finding_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], blockers TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[],
checkpoint_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], next_step TEXT NOT NULL, state TEXT NOT NULL,
revision BIGINT NOT NULL, time_budget_millis BIGINT NOT NULL, cost_budget_micros BIGINT NOT NULL,
max_attempts INTEGER NOT NULL, recorded_at_unix_millis BIGINT NOT NULL,
CHECK (investigation_id <> ''), CHECK (objective <> ''), CHECK (next_step <> ''), CHECK (revision > 0), CHECK (time_budget_millis >= 0), CHECK (cost_budget_micros >= 0), CHECK (max_attempts >= 0), CHECK (recorded_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS work.investigation_checkpoints (
checkpoint_id TEXT PRIMARY KEY, investigation_id TEXT NOT NULL, completed_attempt_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[],
completed_finding_refs TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], next_step TEXT NOT NULL, recorded_at_unix_millis BIGINT NOT NULL,
CHECK (checkpoint_id <> ''), CHECK (investigation_id <> ''), CHECK (next_step <> ''), CHECK (recorded_at_unix_millis > 0)
);
CREATE TABLE IF NOT EXISTS work.investigation_attempts (
investigation_id TEXT NOT NULL, attempt_ref TEXT NOT NULL, verified_at_unix_millis BIGINT NOT NULL,
PRIMARY KEY (investigation_id, attempt_ref), CHECK (investigation_id <> ''), CHECK (attempt_ref <> ''), CHECK (verified_at_unix_millis > 0)
);
RESET ROLE;
COMMIT;
@@ -0,0 +1,11 @@
BEGIN;
SET ROLE identity_role;
CREATE TABLE IF NOT EXISTS identity.principal_data_realms (
realm_id TEXT PRIMARY KEY, owner_principal_id TEXT NOT NULL, realm_kind TEXT NOT NULL,
member_principal_ids TEXT[] NOT NULL DEFAULT ARRAY[]::TEXT[], shared BOOLEAN NOT NULL DEFAULT FALSE,
revision BIGINT NOT NULL, recorded_at_unix_millis BIGINT NOT NULL,
CHECK (realm_id <> ''), CHECK (owner_principal_id <> ''), CHECK (realm_kind IN ('PERSONAL','SHARED','PUBLIC')),
CHECK (realm_kind <> 'SHARED' OR shared), CHECK (revision > 0), CHECK (recorded_at_unix_millis > 0)
);
RESET ROLE;
COMMIT;
+1 -5
View File
@@ -1,5 +1 @@
{
"task_file": "dev/tasks/DEV-000295-household-scenario-audit.json",
"task_id": "DEV-000295",
"task_revision": 2
}
{"task_file":"dev/tasks/GEN2-027-production-canary-and-controlled-gen2-traffic-transition.json","task_id":"GEN2-027","task_revision":1}
@@ -0,0 +1,101 @@
{
"task_id": "ARCH-GEN2-000",
"task_revision": 1,
"architecture_revision": "ADR-0019",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Сделать Gen2 официальным архитектурным поколением, а не внешним пожеланием.",
"requirement_ids": [
"REQ-ARCH-GEN2-000-GOAL",
"REQ-ARCH-GEN2-000-BOUNDARY",
"REQ-ARCH-GEN2-000-GATE"
],
"allowed_change_scope": {
"modules": [],
"paths": [
"architecture/**",
"development/**",
"docs/**",
"AGENTS.md",
"cmd/devctl/**",
"ci/architecture/**",
".gitea/workflows/ci.yml",
"dev/**"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [],
"may_change": []
},
"semantic_owner": "Architecture/Governance. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"нет runtime writer change",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"V1 governance -> Gen2 documents accepted -> architecture authority/registry updated -> later implementation tasks become legal"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No runtime schema change. This task adopts Gen2 canonical documents/governance only."
],
"failure_retry_restart": [
"Rollback rule: revert architecture adoption до начала schema migration; baseline tag остаётся неизменным",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M0; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Executable task id is ARCH-GEN2-000 because current devctl accepts ARCH-* as an architecture_revision root; this corresponds exactly to GEN2-000 in the Master Plan.",
"Depends on: PRE-GEN2-000."
],
"acceptance_scenarios": [
"ARCH-GEN2-000-SCN-01: внести DOMOVOY_CONSTITUTION, GEN2_TARGET_ARCHITECTURE, GEN2_CANONICAL_DATA_MODEL, GEN2_MIGRATION_MAP и GEN2_MASTER_PLAN в repo",
"ARCH-GEN2-000-SCN-02: принять ADR/architecture-generation decision, который разрешает новые owners World/Configuration/SELF и Gen2 migrations",
"ARCH-GEN2-000-SCN-03: обновить authority order архитектурных документов",
"ARCH-GEN2-000-SCN-04: закрыть/заморозить DEV-000295 как V1 baseline/audit evidence или явно supersede его Gen2 program",
"ARCH-GEN2-000-SCN-05: добавить Gen2 task validation в devctl",
"ARCH-GEN2-000-SCN-06: добавить FAST/MILESTONE/FULL test profiles или эквивалентную profile metadata без тяжёлого переписывания CI",
"ARCH-GEN2-000-SCN-07: внести GEN2_EXECUTION_CONTRACT, GEN2_TASK_INDEX и все последующие GEN2 task packets; сделать их canonical execution program",
"ARCH-GEN2-000-EXIT: Codex перед каждым Gen2 task обязан читать canonical Gen2 docs; ordinary V1 task больше не имеет права менять Gen2 architecture."
],
"required_tests": [
"FAST: go test ./cmd/devctl/...",
"FAST: go vet ./cmd/devctl/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --",
"FAST architecture: go run ./cmd/devctl check-architecture"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,102 @@
{
"task_id": "GEN2-001",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Формально закрепить owners, forbidden dependencies и migration law before tables.",
"requirement_ids": [
"REQ-GEN2-001-GOAL",
"REQ-GEN2-001-BOUNDARY",
"REQ-GEN2-001-GATE"
],
"allowed_change_scope": {
"modules": [],
"paths": [
"architecture/**",
"contracts/world/**",
"contracts/configuration/**",
"contracts/self/**",
"cmd/devctl/**",
"ci/architecture/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-001-accept-gen2-owner-registry-and-dependency-rules.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 32,
"new_canonical_owners": 3,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 3
},
"contracts": {
"consume": [],
"may_change": [
"Only contracts explicitly within GEN2-001 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Architecture Registry. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"нет data writer change",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"V1 governance -> Gen2 documents accepted -> architecture authority/registry updated -> later implementation tasks become legal"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: architecture revert возможен только до первого зависимого Gen2 task; далее через новый ADR",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M0; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: ARCH-GEN2-000."
],
"acceptance_scenarios": [
"GEN2-001-SCN-01: принять owner registry Gen2",
"GEN2-001-SCN-02: развести AuthorityScope и ContextScope",
"GEN2-001-SCN-03: зафиксировать World != truth owner, SELF != orchestrator, Memory != owner",
"GEN2-001-SCN-04: зафиксировать single canonical writer, no cross-owner SQL/FK/JOIN by default",
"GEN2-001-SCN-05: зафиксировать Supervisor как runtime layer, не semantic owner",
"GEN2-001-SCN-06: добавить architecture checks для новых границ там, где это возможно дешёво",
"GEN2-001-EXIT: все последующие task packets могут однозначно указать current_owner/target_owner."
],
"required_tests": [
"FAST: go test ./cmd/devctl/...",
"FAST: go vet ./cmd/devctl/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --",
"FAST architecture: go run ./cmd/devctl check-architecture"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,113 @@
{
"task_id": "GEN2-002",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Дать Gen2 стабильные ID/revision/time/SemanticRef/PrincipalRealm/Sensitivity primitives без giant shared domain model.",
"requirement_ids": [
"REQ-GEN2-002-GOAL",
"REQ-GEN2-002-BOUNDARY",
"REQ-GEN2-002-GATE"
],
"allowed_change_scope": {
"modules": [
"world",
"situation",
"epistemics",
"configuration",
"self"
],
"paths": [
"platform/ids/**",
"platform/clock/**",
"platform/errors/**",
"contracts/world/**",
"contracts/situation/**",
"contracts/epistemics/**",
"contracts/configuration/**",
"contracts/self/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-002-introduce-shared-gen2-data-primitives-without-shared-domain-semantics.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.identity@v1",
"contracts.authority@v1"
],
"may_change": [
"Only contracts explicitly within GEN2-002 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Platform/Contracts. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"существующие owners остаются writers",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: существующие owners остаются writers"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: additive primitives; old code не удалять",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M1; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-001."
],
"acceptance_scenarios": [
"GEN2-002-SCN-01: определить StableID/Revision primitives",
"GEN2-002-SCN-02: определить SemanticRef как cross-owner reference без прямого DB ownership",
"GEN2-002-SCN-03: определить time primitives и data realm/sensitivity primitives",
"GEN2-002-SCN-04: реализовать typed value algebra там, где он действительно общий технический контракт",
"GEN2-002-SCN-05: не переносить domain meaning в platform/common",
"GEN2-002-EXIT: World/Focus/Epistemics/Configuration могут ссылаться на одинаковые технические refs без shared semantic owner."
],
"required_tests": [
"FAST: go test ./platform/ids/... ./contracts/world/... ./contracts/situation/... ./contracts/epistemics/... ./contracts/configuration/... ./contracts/self/...",
"FAST: go vet ./platform/ids/... ./contracts/world/... ./contracts/situation/... ./contracts/epistemics/... ./contracts/configuration/... ./contracts/self/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,110 @@
{
"task_id": "GEN2-003",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Создать устойчивые referents/aliases/types/facet definitions/relation definitions, не присваивая World владение истиной значений.",
"requirement_ids": [
"REQ-GEN2-003-GOAL",
"REQ-GEN2-003-BOUNDARY",
"REQ-GEN2-003-GATE"
],
"allowed_change_scope": {
"modules": [
"world"
],
"paths": [
"modules/world/**",
"contracts/world/**",
"adapters/postgres/world_repository.go",
"adapters/postgres/world_*.go",
"database/migrations/*.sql",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-003-add-narrow-world-owner-and-typed-vocabulary.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.identity@v1",
"contracts.authority@v1"
],
"may_change": [
"Only contracts explicitly within GEN2-003 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "World (new). Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"before: project/situation/ad-hoc identifiers; after: World canonical only for referent vocabulary, not facts",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: before: project/situation/ad-hoc identifiers; after: World canonical only for referent vocabulary, not facts"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: V1 identifiers остаются compatibility refs; World tables additive; switch readers back без удаления World evidence",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M1; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-002."
],
"acceptance_scenarios": [
"GEN2-003-SCN-01: создать WorldObject stable identity",
"GEN2-003-SCN-02: WorldObjectKindDefinition",
"GEN2-003-SCN-03: WorldAlias",
"GEN2-003-SCN-04: FacetDefinition и RelationDefinition с versioned typed schemas",
"GEN2-003-SCN-05: identity-resolution candidate/decision structures",
"GEN2-003-SCN-06: обеспечить split/merge lineage",
"GEN2-003-SCN-07: начать с минимального набора объектов, необходимых для Focus/Scope migration",
"GEN2-003-EXIT: одинаковые имена разных компаний/баз могут иметь разные stable referents; World не хранит claim «какое значение истинно»."
],
"required_tests": [
"FAST: go test ./modules/world/... ./contracts/world/... ./adapters/postgres",
"FAST: go vet ./modules/world/... ./contracts/world/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,116 @@
{
"task_id": "GEN2-004",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Сделать Focus многомерным: person/org/system/database/repository/version/activity/goal/task/entities, а Project оставить лишь возможной гранью.",
"requirement_ids": [
"REQ-GEN2-004-GOAL",
"REQ-GEN2-004-BOUNDARY",
"REQ-GEN2-004-GATE"
],
"allowed_change_scope": {
"modules": [
"situation",
"interaction"
],
"paths": [
"modules/situation/**",
"contracts/situation/**",
"adapters/postgres/situation_repository.go",
"database/migrations/*.sql",
"cmd/core-runtime/**",
"modules/interaction/**",
"contracts/interaction/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-004-replace-project-centric-focus-with-contextscope-focusframe-focusstack.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.identity@v1",
"contracts.authority@v1",
"contracts.world@gen2",
"contracts.work@v1",
"contracts.capability@v1"
],
"may_change": [
"Only contracts explicitly within GEN2-004 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Situation. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"before: V1 situation/project focus; after: Situation FocusFrame/Transition; ActiveProjectFocus becomes projection/compatibility",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: before: V1 situation/project focus; after: Situation FocusFrame/Transition; ActiveProjectFocus becomes projection/compatibility"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: feature switch возвращает V1 read path; Gen2 transitions сохраняются",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M1; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-003."
],
"acceptance_scenarios": [
"GEN2-004-SCN-01: добавить ContextScope RoleKey/ScopeValue/MatchPolicy",
"GEN2-004-SCN-02: добавить FocusFrame stable ID + revision",
"GEN2-004-SCN-03: добавить FocusTransition append-only ledger",
"GEN2-004-SCN-04: добавить FocusStack/parent/suspended/resume semantics",
"GEN2-004-SCN-05: реализовать explicit focus command и inferred focus как разные evidence paths",
"GEN2-004-SCN-06: построить compatibility projection ActiveProjectFocus из FocusFrame",
"GEN2-004-SCN-07: переключить core/context readers на Focus V2 постепенно",
"GEN2-004-EXIT: короткое отвлечение может push/pop focus; Company A/UNF и Company B/UNF не смешиваются по текущему scope."
],
"required_tests": [
"FAST: go test ./modules/situation/... ./contracts/situation/... ./modules/interaction/... ./cmd/core-runtime/... ./adapters/postgres",
"FAST: go vet ./modules/situation/... ./contracts/situation/... ./modules/interaction/... ./cmd/core-runtime/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,107 @@
{
"task_id": "GEN2-005",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Заложить безопасное same_as?/merge/split и привязку Focus к конкретной версии/окружению.",
"requirement_ids": [
"REQ-GEN2-005-GOAL",
"REQ-GEN2-005-BOUNDARY",
"REQ-GEN2-005-GATE"
],
"allowed_change_scope": {
"modules": [
"world",
"situation"
],
"paths": [
"modules/world/**",
"contracts/world/**",
"modules/situation/**",
"contracts/situation/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-005-world-identity-resolution-and-version-environment-bindings.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.world@gen2",
"contracts.situation@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-005 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "World + Situation contracts, no truth ownership. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"World writer только identity/referent resolution",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: World writer только identity/referent resolution"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: resolution decisions versioned/reversible; no destructive identity merge",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M1; test profile: MILESTONE.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-004."
],
"acceptance_scenarios": [
"GEN2-005-SCN-01: реализовать identity resolution candidate с confidence/evidence refs",
"GEN2-005-SCN-02: не объединять автоматически неоднозначных людей/системы",
"GEN2-005-SCN-03: добавить reversible merge/split lineage",
"GEN2-005-SCN-04: добавить version/environment reference primitives, используемые позже Epistemics freshness",
"GEN2-005-EXIT: «Иван Telegram» и «Иван CRM» могут быть связаны с уверенностью без необратимого склеивания; две УНФ не путаются."
],
"required_tests": [
"FAST: go test ./modules/world/... ./modules/situation/...",
"FAST: go vet ./modules/world/... ./modules/situation/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --",
"MILESTONE M1: go test ./modules/world/... ./modules/situation/... ./modules/interaction/... ./cmd/core-runtime/...",
"MILESTONE M1: run focused scope/focus company-A-vs-company-B and focus-stack regressions; do not run full repository suite."
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,111 @@
{
"task_id": "GEN2-006",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Убрать зависимость от denormalized truth_bundles как конечной модели истины и создать переоцениваемую канонику evidence/claim/belief.",
"requirement_ids": [
"REQ-GEN2-006-GOAL",
"REQ-GEN2-006-BOUNDARY",
"REQ-GEN2-006-GATE"
],
"allowed_change_scope": {
"modules": [
"epistemics"
],
"paths": [
"modules/epistemics/**",
"contracts/epistemics/**",
"adapters/postgres/epistemics_repository.go",
"adapters/research/**",
"database/migrations/*.sql",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-006-normalize-epistemics-evidence-propositions-claims-and-belief-assessments.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.identity@v1",
"contracts.artifact@v1",
"contracts.world@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-006 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Epistemics. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"before: V1 truth bundle paths; after: normalized Epistemics for new Gen2 knowledge; old bundle writer disabled at cutover or made projection",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: before: V1 truth bundle paths; after: normalized Epistemics for new Gen2 knowledge; old bundle writer disabled at cutover or made projection"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: read switch назад на V1 bundle; normalized evidence не удалять",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M2; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-005."
],
"acceptance_scenarios": [
"GEN2-006-SCN-01: добавить Source/SourceSnapshot/SourceExcerpt",
"GEN2-006-SCN-02: добавить immutable Observation",
"GEN2-006-SCN-03: добавить Proposition/Claim",
"GEN2-006-SCN-04: добавить versioned BeliefAssessment",
"GEN2-006-SCN-05: backfill существующих truth/research данных с lineage",
"GEN2-006-SCN-06: оставить truth_bundles read compatibility до позднего retirement",
"GEN2-006-SCN-07: обеспечить возможность новой модели переоценить старый Claim без переписывания Observation",
"GEN2-006-EXIT: источник, наблюдение, утверждение и текущая оценка уверенности раздельны и traceable."
],
"required_tests": [
"FAST: go test ./modules/epistemics/... ./contracts/epistemics/... ./adapters/research/... ./adapters/postgres",
"FAST: go vet ./modules/epistemics/... ./contracts/epistemics/... ./adapters/research/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,111 @@
{
"task_id": "GEN2-007",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Сделать старение знания контекстным: прошлогодняя УНФ может быть stale для live-debug и полезной аналогией без live-доступа.",
"requirement_ids": [
"REQ-GEN2-007-GOAL",
"REQ-GEN2-007-BOUNDARY",
"REQ-GEN2-007-GATE"
],
"allowed_change_scope": {
"modules": [
"epistemics",
"work"
],
"paths": [
"modules/epistemics/**",
"contracts/epistemics/**",
"contracts/work/**",
"database/migrations/*.sql",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-007-general-freshness-volatility-temporal-applicability-and-revalidation.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.epistemics@gen2",
"contracts.work@v1",
"contracts.world@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-007 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Epistemics. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Epistemics writes observation/verification metadata; freshness status computed",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: Epistemics writes observation/verification metadata; freshness status computed"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: metadata additive; old readers ignore it",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M2; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-006."
],
"acceptance_scenarios": [
"GEN2-007-SCN-01: добавить TemporalApplicability",
"GEN2-007-SCN-02: VolatilitySpec/decay class",
"GEN2-007-SCN-03: last_verified/observed metadata",
"GEN2-007-SCN-04: VersionBinding",
"GEN2-007-SCN-05: TaskFreshnessRequirement",
"GEN2-007-SCN-06: вычисляемый FreshnessAssessment вместо permanent `stale` flag",
"GEN2-007-SCN-07: active revalidation request/response contract",
"GEN2-007-SCN-08: fallback semantics: memory-only solution должен быть явно маркирован как непроверенный текущими данными",
"GEN2-007-EXIT: один и тот же Claim получает разную пригодность в зависимости от task freshness/risk."
],
"required_tests": [
"FAST: go test ./modules/epistemics/... ./contracts/epistemics/... ./contracts/work/...",
"FAST: go vet ./modules/epistemics/... ./contracts/epistemics/... ./contracts/work/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,110 @@
{
"task_id": "GEN2-008",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Сохранять не только «что сработало», но problem/attempt/why/result/why failed/conditions/evidence.",
"requirement_ids": [
"REQ-GEN2-008-GOAL",
"REQ-GEN2-008-BOUNDARY",
"REQ-GEN2-008-GATE"
],
"allowed_change_scope": {
"modules": [
"epistemics",
"artifact"
],
"paths": [
"modules/epistemics/**",
"contracts/epistemics/**",
"adapters/postgres/epistemics_repository.go",
"contracts/artifact/**",
"database/migrations/*.sql",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-008-promote-episode-and-experience-v2-including-negative-experience.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.epistemics@gen2",
"contracts.artifact@v1",
"contracts.world@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-008 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Epistemics. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Epistemics remains canonical Experience writer; Episode projection derived",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: Epistemics remains canonical Experience writer; Episode projection derived"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: старые Experience records остаются валидны; Episode projection rebuildable",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M2; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-007."
],
"acceptance_scenarios": [
"GEN2-008-SCN-01: расширить ExperienceRecord V1 без потери старых IDs/evidence",
"GEN2-008-SCN-02: сделать success/failure first-class",
"GEN2-008-SCN-03: добавить conditions/applicability/version bindings",
"GEN2-008-SCN-04: создать Episode как derived/rebuildable episodic projection",
"GEN2-008-SCN-05: связать user correction с ReflectionCandidate/Experience",
"GEN2-008-SCN-06: добавить anti-pattern: failure under conditions != forever wrong",
"GEN2-008-EXIT: retrieval позже может отдельно запросить «что уже пробовали и почему не сработало»."
],
"required_tests": [
"FAST: go test ./modules/epistemics/... ./contracts/epistemics/... ./adapters/postgres",
"FAST: go vet ./modules/epistemics/... ./contracts/epistemics/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,114 @@
{
"task_id": "GEN2-009",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Дать многоканальный retrieval по canonical owners без единой memory_items каноники.",
"requirement_ids": [
"REQ-GEN2-009-GOAL",
"REQ-GEN2-009-BOUNDARY",
"REQ-GEN2-009-GATE"
],
"allowed_change_scope": {
"modules": [],
"paths": [
"runtime/retrieval/**",
"contracts/cognitive/**",
"adapters/postgres/*retrieval*.go",
"adapters/postgres/*search*.go",
"database/migrations/*.sql",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-009-build-memory-retrieval-fabric-as-rebuildable-projections.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.interaction@v1",
"contracts.world@gen2",
"contracts.epistemics@gen2",
"contracts.work@v1",
"contracts.continuity@v1",
"contracts.capability@v1",
"contracts.configuration@gen2",
"contracts.self@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-009 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "No canonical Memory owner; projection layer. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"canonical writers unchanged; retrieval index only projection writer",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: canonical writers unchanged; retrieval index only projection writer"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: drop/rebuild projection and use V1 memory retrieval",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M2; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-008."
],
"acceptance_scenarios": [
"GEN2-009-SCN-01: создать RetrievalDocument projection с source SemanticRef",
"GEN2-009-SCN-02: projection builders из Interaction/World/Epistemics/Work/Continuity/Capability/Configuration/SELF",
"GEN2-009-SCN-03: жёсткий ContextScope/realm/version filter before similarity",
"GEN2-009-SCN-04: lanes: semantic, entity/graph-like refs, temporal, goal/commitment, positive experience, negative experience, contradiction, skill",
"GEN2-009-SCN-05: ranking signals: relevance, freshness, confidence, salience, scope distance, cost",
"GEN2-009-SCN-06: hot/warm/cold/archive retrieval policy как operational storage concern, не truth",
"GEN2-009-SCN-07: projection versioning/rebuild command",
"GEN2-009-EXIT: vector index можно полностью перестроить без изменения canonical memory; cross-company leak blocked before embedding rank."
],
"required_tests": [
"FAST: go test ./runtime/retrieval/... ./contracts/cognitive/... ./adapters/postgres",
"FAST: go vet ./runtime/retrieval/... ./contracts/cognitive/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,110 @@
{
"task_id": "GEN2-010",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Формировать минимально достаточный model context под текущий Task/Focus/Model/Risk/Freshness и уметь дозапрашивать память во время reasoning.",
"requirement_ids": [
"REQ-GEN2-010-GOAL",
"REQ-GEN2-010-BOUNDARY",
"REQ-GEN2-010-GATE"
],
"allowed_change_scope": {
"modules": [],
"paths": [
"contracts/cognitive/**",
"cmd/cognitive-worker/**",
"cmd/core-runtime/**",
"runtime/retrieval/**",
"tests/context_compiler/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-010-context-compiler-v2-with-budgets-coverage-and-iterative-retrieval.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.cognitive@v1",
"contracts.situation@gen2",
"contracts.epistemics@gen2",
"contracts.capability@v1"
],
"may_change": [
"Only contracts explicitly within GEN2-010 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Cognitive contract/read path, no canonical owner. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"none; read/compile only",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"task input -> bounded Gen2 change -> FAST verification -> merge to gen2-integration; canonical writer rule: none; read/compile only"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: feature switch to Context Compiler V1; V2 trace/projections retained",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M2; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-009."
],
"acceptance_scenarios": [
"GEN2-010-SCN-01: ContextCompileRequest: task/focus/scope/model/token budget/freshness/risk",
"GEN2-010-SCN-02: candidate lanes + deterministic scope filtering",
"GEN2-010-SCN-03: positive+negative experience balancing",
"GEN2-010-SCN-04: contradiction pass",
"GEN2-010-SCN-05: coverage check: не упущены ли critical commitments/known failures",
"GEN2-010-SCN-06: ContextBundle с explicit token allocation",
"GEN2-010-SCN-07: ContextAssemblyTrace: почему элемент включён/исключён",
"GEN2-010-SCN-08: iterative memory search tool для model reasoning",
"GEN2-010-SCN-09: маленькой локальной модели давать меньше и точнее, а не просто урезать хвост",
"GEN2-010-EXIT: локальная модель получает релевантный пакет без любимого цвета в 1C-debug; нужные прошлые грабли попадают в context."
],
"required_tests": [
"FAST: go test ./contracts/cognitive/... ./cmd/cognitive-worker/... ./cmd/core-runtime/... ./runtime/retrieval/... ./tests/context_compiler/...",
"FAST: go vet ./contracts/cognitive/... ./cmd/cognitive-worker/... ./cmd/core-runtime/... ./runtime/retrieval/... ./tests/context_compiler/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,112 @@
{
"task_id": "GEN2-011",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Перестать использовать ad-hoc PersonalMemory ContextText как долгосрочную основу памяти, не теряя utterance history.",
"requirement_ids": [
"REQ-GEN2-011-GOAL",
"REQ-GEN2-011-BOUNDARY",
"REQ-GEN2-011-GATE"
],
"allowed_change_scope": {
"modules": [
"interaction"
],
"paths": [
"modules/interaction/**",
"contracts/interaction/**",
"adapters/postgres/interaction_repository.go",
"cmd/core-runtime/**",
"cmd/cognitive-worker/**",
"runtime/retrieval/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-011-cut-personalmemory-v1-to-compatibility-fallback.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.interaction@v1",
"contracts.cognitive@gen2",
"contracts.situation@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-011 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Interaction -> retrieval fabric reads multiple owners. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"utterance writer unchanged; PersonalMemory derived writer frozen; retrieval projection primary",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: utterance writer unchanged; PersonalMemory derived writer frozen; retrieval projection primary"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: switch reads back to PersonalMemory; no canonical loss",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M2; test profile: MILESTONE.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-010."
],
"acceptance_scenarios": [
"GEN2-011-SCN-01: оставить HumanUtterance append-only canonical history",
"GEN2-011-SCN-02: построить Gen2 retrieval из этой истории",
"GEN2-011-SCN-03: сравнить V1 PersonalMemory vs Gen2 context on representative cases",
"GEN2-011-SCN-04: переключить primary read на Gen2",
"GEN2-011-SCN-05: оставить PersonalMemory read fallback до M6",
"GEN2-011-SCN-06: запретить новый semantic growth V1 PersonalMemory",
"GEN2-011-EXIT: PersonalMemory больше не определяет архитектуру новых features."
],
"required_tests": [
"FAST: go test ./modules/interaction/... ./cmd/core-runtime/... ./cmd/cognitive-worker/... ./runtime/retrieval/...",
"FAST: go vet ./modules/interaction/... ./cmd/core-runtime/... ./cmd/cognitive-worker/... ./runtime/retrieval/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --",
"MILESTONE M2: go test ./modules/epistemics/... ./modules/interaction/... ./cmd/cognitive-worker/... ./cmd/core-runtime/... ./runtime/retrieval/... ./tests/context_compiler/...",
"MILESTONE M2: run freshness, negative-experience, contradiction, scope-isolation and PersonalMemory-fallback regressions only."
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,119 @@
{
"task_id": "GEN2-012",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Убрать ordinary runtime settings из ENV и дать Skills/capabilities возможность объявлять новые typed scoped settings без глобальной schema rewrite.",
"requirement_ids": [
"REQ-GEN2-012-GOAL",
"REQ-GEN2-012-BOUNDARY",
"REQ-GEN2-012-GATE"
],
"allowed_change_scope": {
"modules": [
"configuration"
],
"paths": [
"modules/configuration/**",
"contracts/configuration/**",
"adapters/postgres/configuration_repository.go",
"platform/secrets/**",
"database/migrations/*.sql",
"cmd/core-runtime/**",
"cmd/cognitive-worker/**",
"adapters/models/**",
"adapters/research/**",
"adapters/multimodal/**",
"deploy/docker-compose.prod.yml",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-012-add-typed-scoped-versioned-configuration-owner-and-bootstrap-boundary.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 1,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.identity@v1",
"contracts.world@gen2",
"contracts.secrets@v1"
],
"may_change": [
"Only contracts explicitly within GEN2-012 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Configuration (new). Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"before: ENV/files/ad-hoc DB; after: Configuration for migrated non-bootstrap settings",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: before: ENV/files/ad-hoc DB; after: Configuration for migrated non-bootstrap settings"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass.",
"Deploy/release surface changes are allowed only for the bounded purpose of this packet; production promotion requires the packet's stated evidence and rollback path."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: per-consumer fallback to old read path; Configuration values retained",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M3; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-011."
],
"acceptance_scenarios": [
"GEN2-012-SCN-01: inventory всех ENV/config consumers",
"GEN2-012-SCN-02: создать SettingDefinition stable identity + schema/version/owner/type/default/validation",
"GEN2-012-SCN-03: SettingAssignment + ScopeSelector",
"GEN2-012-SCN-04: deterministic inheritance/resolution",
"GEN2-012-SCN-05: EffectiveConfiguration trace",
"GEN2-012-SCN-06: SecretRef only for credentials",
"GEN2-012-SCN-07: определить минимальный bootstrap, который может остаться вне Configuration",
"GEN2-012-SCN-08: импортировать non-secret текущие значения",
"GEN2-012-SCN-09: shadow compare old vs resolved configuration",
"GEN2-012-SCN-10: cutover consumers по одному, Commit runtime последним из критических",
"GEN2-012-EXIT: можно сказать «для Skill X в Company A значение Y», а Company B получает другое значение без новых ENV vars/columns."
],
"required_tests": [
"FAST: go test ./modules/configuration/... ./contracts/configuration/... ./platform/secrets/... ./cmd/core-runtime/... ./adapters/models/... ./adapters/research/...",
"FAST: go vet ./modules/configuration/... ./contracts/configuration/... ./platform/secrets/... ./cmd/core-runtime/... ./adapters/models/... ./adapters/research/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,115 @@
{
"task_id": "GEN2-013",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Сделать Skill долговечным обучаемым способом решения, а не только профилем capability.",
"requirement_ids": [
"REQ-GEN2-013-GOAL",
"REQ-GEN2-013-BOUNDARY",
"REQ-GEN2-013-GATE"
],
"allowed_change_scope": {
"modules": [
"capability",
"work"
],
"paths": [
"modules/capability/**",
"contracts/capability/**",
"adapters/postgres/capability_repository.go",
"database/migrations/*.sql",
"modules/work/**",
"contracts/work/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-013-migrate-skill-v1-to-skill-v2-with-applicability-versioning-and-evidence.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.capability@v1",
"contracts.work@v1",
"contracts.epistemics@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-013 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Capability. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Capability remains Skill canonical writer",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: Capability remains Skill canonical writer"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: V1 skill view/projected compatibility; revisions additive",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M3; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-012."
],
"acceptance_scenarios": [
"GEN2-013-SCN-01: сохранить stable Skill identity",
"GEN2-013-SCN-02: ввести revisions",
"GEN2-013-SCN-03: ApplicabilitySpec с Scope/version/conditions",
"GEN2-013-SCN-04: связать positive/negative Experience evidence",
"GEN2-013-SCN-05: validation/promotion evidence",
"GEN2-013-SCN-06: known failure conditions",
"GEN2-013-SCN-07: quality history",
"GEN2-013-SCN-08: dependency refs",
"GEN2-013-SCN-09: сохранить совместимость с существующими SkillProfile/ReflectionCandidate",
"GEN2-013-EXIT: успешное решение может стать Candidate/Validated/Active Skill и знает, где он применим."
],
"required_tests": [
"FAST: go test ./modules/capability/... ./contracts/capability/... ./modules/work/... ./adapters/postgres",
"FAST: go vet ./modules/capability/... ./contracts/capability/... ./modules/work/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,112 @@
{
"task_id": "GEN2-014",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Дать быстрый локальный путь для проверенных повторяемых задач без закостенения.",
"requirement_ids": [
"REQ-GEN2-014-GOAL",
"REQ-GEN2-014-BOUNDARY",
"REQ-GEN2-014-GATE"
],
"allowed_change_scope": {
"modules": [
"capability"
],
"paths": [
"modules/capability/**",
"contracts/capability/**",
"adapters/postgres/capability_repository.go",
"database/migrations/*.sql",
"cmd/cognitive-worker/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-014-add-explicit-reflex-lifecycle-shadow-reasoning-and-revalidation.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.capability@gen2",
"contracts.cognitive@gen2",
"contracts.epistemics@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-014 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Capability. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Capability writes Reflex lifecycle; routing reads only ACTIVE applicable reflex",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"task input -> bounded Gen2 change -> FAST verification -> merge to gen2-integration; canonical writer rule: Capability writes Reflex lifecycle; routing reads only ACTIVE applicable reflex"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: disable reflex feature switch; route returns to Skill/model",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M3; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-013."
],
"acceptance_scenarios": [
"GEN2-014-SCN-01: Reflex stable ID/revisions",
"GEN2-014-SCN-02: link Reflex -> originating Skill/evidence",
"GEN2-014-SCN-03: applicability/dependencies",
"GEN2-014-SCN-04: ShadowPolicy/RevalidationPolicy",
"GEN2-014-SCN-05: fallback/escalation Reflex -> Skill -> reasoning",
"GEN2-014-SCN-06: drift/stale detection",
"GEN2-014-SCN-07: candidate/active/suspended/retired states",
"GEN2-014-SCN-08: не считать один успешный run достаточным для promotion",
"GEN2-014-EXIT: частая стабильная задача может выполняться быстро локально и автоматически вернуться к reasoning при сомнении."
],
"required_tests": [
"FAST: go test ./modules/capability/... ./contracts/capability/... ./cmd/cognitive-worker/... ./adapters/postgres",
"FAST: go vet ./modules/capability/... ./contracts/capability/... ./cmd/cognitive-worker/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,111 @@
{
"task_id": "GEN2-015",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Домовой должен знать, что умеет, при каких условиях, где ошибается и что изменилось — без права самому объявить себя хорошим.",
"requirement_ids": [
"REQ-GEN2-015-GOAL",
"REQ-GEN2-015-BOUNDARY",
"REQ-GEN2-015-GATE"
],
"allowed_change_scope": {
"modules": [
"self"
],
"paths": [
"modules/self/**",
"contracts/self/**",
"adapters/postgres/self_repository.go",
"database/migrations/*.sql",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-015-add-evidence-backed-self-foundation-and-learning-ledger.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.capability@gen2",
"contracts.work@v1",
"contracts.epistemics@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-015 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "SELF (new). Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"SELF writes derived evidence-backed self assessments only",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"task input -> bounded Gen2 change -> FAST verification -> merge to gen2-integration; canonical writer rule: SELF writes derived evidence-backed self assessments only"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: SELF can be disabled; no mutation path depends on it initially",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M3; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-014."
],
"acceptance_scenarios": [
"GEN2-015-SCN-01: CompetenceAssessment from outcomes/tests/task evaluations",
"GEN2-015-SCN-02: WeaknessPattern",
"GEN2-015-SCN-03: DependencyAssessment",
"GEN2-015-SCN-04: ImprovementNeed",
"GEN2-015-SCN-05: LearningLedgerEntry",
"GEN2-015-SCN-06: SelfCompositionSnapshot",
"GEN2-015-SCN-07: provenance каждого self-assessment",
"GEN2-015-SCN-08: запрет arbitrary `competence=1.0` от Skill",
"GEN2-015-SCN-09: первый режим SELF только observe/evaluate/propose",
"GEN2-015-EXIT: система отличает «я разучился» от «зависимость IFCM временно недоступна» и хранит собственные повторяемые weakness patterns."
],
"required_tests": [
"FAST: go test ./modules/self/... ./contracts/self/... ./adapters/postgres",
"FAST: go vet ./modules/self/... ./contracts/self/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,120 @@
{
"task_id": "GEN2-016",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Выбирать минимально достаточный интеллект и доказуемо сравнивать модели/skills на реальных задачах владельца.",
"requirement_ids": [
"REQ-GEN2-016-GOAL",
"REQ-GEN2-016-BOUNDARY",
"REQ-GEN2-016-GATE"
],
"allowed_change_scope": {
"modules": [
"capability",
"work",
"self"
],
"paths": [
"modules/capability/**",
"contracts/capability/**",
"modules/work/**",
"contracts/work/**",
"modules/self/**",
"contracts/self/**",
"cmd/cognitive-worker/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-016-intelligence-strategy-resource-cost-policy-and-personal-benchmark.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.capability@gen2",
"contracts.work@gen2",
"contracts.self@gen2",
"contracts.cognitive@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-016 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Capability + Work evaluation; SELF observes. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Capability/Work existing evaluation writers extended; SELF reads assessments",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: Capability/Work existing evaluation writers extended; SELF reads assessments"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: routing returns to V1 selection; evidence retained",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M3; test profile: FULL.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-015."
],
"acceptance_scenarios": [
"GEN2-016-SCN-01: formalize path: rule/reflex/skill/small local/strong local/external/research/team",
"GEN2-016-SCN-02: input signals: required quality, latency preference, cost budget, risk, freshness, cost of error",
"GEN2-016-SCN-03: создать Personal Benchmark dataset refs из реальных approved task cases",
"GEN2-016-SCN-04: определить Goal/Preference evaluation profile: owner intent → long-term goals → current task → contextual preferences",
"GEN2-016-SCN-05: inferred preferences хранить как evidence-backed scoped hypotheses, а не вечные глобальные настройки",
"GEN2-016-SCN-06: сохранять decision-regret evidence: мог ли Домовой с доступными тогда данными выбрать лучше",
"GEN2-016-SCN-07: сохранять task-specific evaluation, user correction, latency/cost/retry evidence",
"GEN2-016-SCN-08: не сводить качество к одной метрике и не оптимизироваться под согласие владельца",
"GEN2-016-SCN-09: добавить exploration/shadow для low-risk paths",
"GEN2-016-SCN-10: новая модель не получает automatic promotion только из-за public benchmark",
"GEN2-016-EXIT: простая задача не запускает команду из 20 агентов; сложная high-risk задача может эскалировать глубину reasoning."
],
"required_tests": [
"FAST: go test ./modules/capability/... ./modules/work/... ./modules/self/... ./cmd/cognitive-worker/...",
"FAST: go vet ./modules/capability/... ./modules/work/... ./modules/self/... ./cmd/cognitive-worker/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --",
"FULL: go test ./...",
"FULL: go vet ./...",
"FULL M3: architecture + migration + configuration + skill/reflex + SELF benchmark regressions."
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,115 @@
{
"task_id": "GEN2-017",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "«Разбирайся хоть сутки» должно быть durable process с checkpoint, а не один длинный LLM request.",
"requirement_ids": [
"REQ-GEN2-017-GOAL",
"REQ-GEN2-017-BOUNDARY",
"REQ-GEN2-017-GATE"
],
"allowed_change_scope": {
"modules": [
"work",
"continuity"
],
"paths": [
"modules/work/**",
"contracts/work/**",
"adapters/postgres/work_repository.go",
"database/migrations/*.sql",
"cmd/work-graph-runtime/**",
"cmd/research-runtime/**",
"modules/continuity/**",
"contracts/continuity/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-017-extend-work-into-durable-longrunningwork-investigation.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.work@v1",
"contracts.continuity@v1",
"contracts.capability@gen2",
"contracts.epistemics@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-017 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Work. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Work canonical writer for long-running job state; Continuity only future relevance",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: Work canonical writer for long-running job state; Continuity only future relevance"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: old Work Graph path remains for normal tasks; new jobs can be paused/read-only",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M4; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-016."
],
"acceptance_scenarios": [
"GEN2-017-SCN-01: LongRunningWork/Investigation state",
"GEN2-017-SCN-02: objective, hypotheses, attempts, findings, blockers, next step",
"GEN2-017-SCN-03: budget: time/cost/model/resource",
"GEN2-017-SCN-04: checkpoint/resume/preempt semantics",
"GEN2-017-SCN-05: model/provider replacement between attempts",
"GEN2-017-SCN-06: stop condition «решение не найдено в бюджете» с сохранением проверенных вариантов",
"GEN2-017-SCN-07: Continuity integration для wake/attention without second scheduler",
"GEN2-017-EXIT: долгая задача переживает restart и продолжает с next step, не повторяя уже проверенные попытки."
],
"required_tests": [
"FAST: go test ./modules/work/... ./modules/continuity/... ./cmd/work-graph-runtime/... ./cmd/research-runtime/... ./adapters/postgres",
"FAST: go vet ./modules/work/... ./modules/continuity/... ./cmd/work-graph-runtime/... ./cmd/research-runtime/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,109 @@
{
"task_id": "GEN2-018",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Домовой может смотреть на задачу как архитектор/программист/директор/дизайнер или собрать временную команду без roleplay и без постоянного staff.",
"requirement_ids": [
"REQ-GEN2-018-GOAL",
"REQ-GEN2-018-BOUNDARY",
"REQ-GEN2-018-GATE"
],
"allowed_change_scope": {
"modules": [
"work",
"capability"
],
"paths": [
"modules/work/**",
"contracts/work/**",
"modules/capability/**",
"contracts/capability/**",
"cmd/work-graph-runtime/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-018-add-perspective-and-dynamic-specialist-team-semantics-on-existing-work-g.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.work@gen2",
"contracts.capability@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-018 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Work. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Work graph remains owner; no separate Agent Memory owner",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: Work graph remains owner; no separate Agent Memory owner"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: disable perspective/team routing; tasks execute single path",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M4; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-017."
],
"acceptance_scenarios": [
"GEN2-018-SCN-01: PerspectiveSpec = objectives/methods/knowledge profile/evaluation criteria",
"GEN2-018-SCN-02: dynamic specialist assembly from Perspective + Focus + Skills + tools",
"GEN2-018-SCN-03: work decomposition by independent subtasks",
"GEN2-018-SCN-04: structured findings/evidence/risks/artifacts",
"GEN2-018-SCN-05: critic/adversarial perspective optional",
"GEN2-018-SCN-06: criteria when team is justified vs single reasoning path",
"GEN2-018-SCN-07: не передавать каждому агенту весь глобальный context",
"GEN2-018-EXIT: «спроектируй систему» может вызвать несколько независимых перспектив; «исправь функцию» остаётся одной задачей."
],
"required_tests": [
"FAST: go test ./modules/work/... ./modules/capability/... ./cmd/work-graph-runtime/...",
"FAST: go vet ./modules/work/... ./modules/capability/... ./cmd/work-graph-runtime/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,109 @@
{
"task_id": "GEN2-019",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Оценивать последствия, обратимость, cost-of-error и mitigation до значимого действия, но не превращать систему в «нельзя».",
"requirement_ids": [
"REQ-GEN2-019-GOAL",
"REQ-GEN2-019-BOUNDARY",
"REQ-GEN2-019-GATE"
],
"allowed_change_scope": {
"modules": [
"work",
"authority"
],
"paths": [
"modules/work/**",
"contracts/work/**",
"contracts/authority/**",
"modules/authority/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-019-add-consequence-risk-assessment-without-artificial-capability-blacklist.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.work@gen2",
"contracts.authority@v1",
"contracts.commit@v1"
],
"may_change": [
"Only contracts explicitly within GEN2-019 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Work assessment feeding Authority/Commit. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Work writes assessment; Authority remains grant decision owner",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"task input -> bounded Gen2 change -> FAST verification -> merge to gen2-integration; canonical writer rule: Work writes assessment; Authority remains grant decision owner"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass.",
"Risk assessment may recommend mitigations but must not invent a blanket capability blacklist or override authenticated owner intent."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: risk assessment advisory disable; strict existing Authority unchanged",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M4; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-018."
],
"acceptance_scenarios": [
"GEN2-019-SCN-01: ConsequenceAssessment",
"GEN2-019-SCN-02: risk dimensions: impact, reversibility, uncertainty, scope, recoverability",
"GEN2-019-SCN-03: mitigation: backup/snapshot/dry-run/canary/extra confirmation",
"GEN2-019-SCN-04: clarification policy based on uncertainty × cost_of_wrong_action × irreversibility",
"GEN2-019-SCN-05: owner may explicitly accept high risk after warning",
"GEN2-019-SCN-06: consequence result becomes input Authority/Commit, не replacement",
"GEN2-019-EXIT: Домовой предупреждает о последствиях и предлагает rollback plan, но не самовольно запрещает владельцу разрешённое действие."
],
"required_tests": [
"FAST: go test ./modules/work/... ./modules/authority/...",
"FAST: go vet ./modules/work/... ./modules/authority/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,117 @@
{
"task_id": "GEN2-020",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Не считать «API 200» доказательством того, что пользовательская цель достигнута.",
"requirement_ids": [
"REQ-GEN2-020-GOAL",
"REQ-GEN2-020-BOUNDARY",
"REQ-GEN2-020-GATE"
],
"allowed_change_scope": {
"modules": [
"commit",
"epistemics",
"continuity"
],
"paths": [
"modules/commit/**",
"contracts/commit/**",
"modules/epistemics/**",
"contracts/epistemics/**",
"modules/continuity/**",
"contracts/continuity/**",
"adapters/postgres/commit_repository.go",
"adapters/postgres/epistemics_repository.go",
"database/migrations/*.sql",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-020-separate-execution-receipt-from-verified-world-outcome.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.commit@v1",
"contracts.epistemics@gen2",
"contracts.continuity@v1",
"contracts.work@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-020 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Commit + Epistemics. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Commit writer unchanged for execution facts; Epistemics writes world assessment",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: Commit writer unchanged for execution facts; Epistemics writes world assessment"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: old Commit status still readable; new assessments additive",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M4; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-019."
],
"acceptance_scenarios": [
"GEN2-020-SCN-01: ExecutionReceipt остаётся Commit-owned факт попытки",
"GEN2-020-SCN-02: WorldOutcomeAssessment становится Epistemics-owned verification",
"GEN2-020-SCN-03: связать expected effect / observation / evidence",
"GEN2-020-SCN-04: поддержать UNKNOWN/PARTIAL/CONTRADICTED outcome",
"GEN2-020-SCN-05: не выполнять destructive retry только потому, что verification отсутствует",
"GEN2-020-SCN-06: Continuity может создать follow-up/attention при неизвестном Outcome",
"GEN2-020-EXIT: ответ «выполнено» возможен только когда семантика операции это позволяет; неизвестность честно отражается."
],
"required_tests": [
"FAST: go test ./modules/commit/... ./modules/epistemics/... ./modules/continuity/... ./adapters/postgres",
"FAST: go vet ./modules/commit/... ./modules/epistemics/... ./modules/continuity/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,106 @@
{
"task_id": "GEN2-021",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Самоизменение Домового не должно уметь уничтожить единственный механизм собственного отката.",
"requirement_ids": [
"REQ-GEN2-021-GOAL",
"REQ-GEN2-021-BOUNDARY",
"REQ-GEN2-021-GATE"
],
"allowed_change_scope": {
"modules": [],
"paths": [
"runtime/supervisor/**",
"cmd/supervisor/**",
"deploy/**",
"runtime/health/**",
"scripts/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-021-add-independent-supervisor-lifeboat-for-release-health-and-rollback.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 1,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.commit@v1",
"contracts.configuration@gen2"
],
"may_change": []
},
"semantic_owner": "Runtime only. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Supervisor writes runtime release state only",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"task input -> bounded Gen2 change -> FAST verification -> merge to gen2-integration; canonical writer rule: Supervisor writes runtime release state only"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass.",
"Deploy/release surface changes are allowed only for the bounded purpose of this packet; production promotion requires the packet's stated evidence and rollback path.",
"Supervisor/Lifeboat must remain operationally independent from the candidate runtime it watches."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: Supervisor itself versioned conservatively; previous release remains bootable",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M4; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-020."
],
"acceptance_scenarios": [
"GEN2-021-SCN-01: candidate release start",
"GEN2-021-SCN-02: health/readiness contract",
"GEN2-021-SCN-03: controlled traffic/switch",
"GEN2-021-SCN-04: watchdog observation",
"GEN2-021-SCN-05: automatic rollback to last known good",
"GEN2-021-SCN-06: persist release/switch evidence outside candidate process dependency",
"GEN2-021-SCN-07: emergency manual control path",
"GEN2-021-SCN-08: не давать Supervisor доступ к semantic decisions пользователя",
"GEN2-021-EXIT: сломанный candidate Assistant не блокирует восстановление последней рабочей версии."
],
"required_tests": [
"FAST: go test ./runtime/supervisor/... ./runtime/health/... ./cmd/supervisor/...",
"FAST: go vet ./runtime/supervisor/... ./runtime/health/... ./cmd/supervisor/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,120 @@
{
"task_id": "GEN2-022",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Замкнуть цикл weakness → proposal → candidate → evaluator → canary → promote/rollback без автономного обхода governance.",
"requirement_ids": [
"REQ-GEN2-022-GOAL",
"REQ-GEN2-022-BOUNDARY",
"REQ-GEN2-022-GATE"
],
"allowed_change_scope": {
"modules": [
"work",
"self",
"capability"
],
"paths": [
"contracts/work/**",
"modules/work/**",
"adapters/developmentexecutor/**",
"modules/self/**",
"contracts/self/**",
"modules/capability/**",
"contracts/capability/**",
"runtime/supervisor/**",
"cmd/work-graph-runtime/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-022-wire-governed-self-evolution-loop-using-existing-development-gates.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.work@gen2",
"contracts.self@gen2",
"contracts.capability@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-022 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Work + SELF evidence + Supervisor promotion. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"existing governed-development writer remains; SELF proposes/evaluates, Supervisor handles release state",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: existing governed-development writer remains; SELF proposes/evaluates, Supervisor handles release state"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass.",
"Self-evolution may propose/build/test candidates but promotion remains governed and independently evaluated."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: existing development gates remain; autonomous promotion feature switch off",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M4; test profile: MILESTONE_RECOVERY.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-021."
],
"acceptance_scenarios": [
"GEN2-022-SCN-01: SELF ImprovementNeed -> Work development candidate",
"GEN2-022-SCN-02: expected improvement + must-not-worsen criteria",
"GEN2-022-SCN-03: Creator != Evaluator enforced",
"GEN2-022-SCN-04: historical replay/personal benchmark",
"GEN2-022-SCN-05: sandbox/candidate build",
"GEN2-022-SCN-06: shadow/canary where appropriate",
"GEN2-022-SCN-07: Supervisor promotion/rollback",
"GEN2-022-SCN-08: LearningLedger records accepted/rejected change and actual outcome",
"GEN2-022-SCN-09: уровни change: knowledge, behavior, capability, core — с возрастающей строгостью",
"GEN2-022-EXIT: Домовой способен доказуемо улучшить компонент и объяснить историю изменения, но не тайно переписать core."
],
"required_tests": [
"FAST: go test ./modules/work/... ./modules/self/... ./modules/capability/... ./adapters/developmentexecutor/... ./runtime/supervisor/...",
"FAST: go vet ./modules/work/... ./modules/self/... ./modules/capability/... ./adapters/developmentexecutor/... ./runtime/supervisor/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --",
"MILESTONE M4: go test ./modules/work/... ./modules/commit/... ./modules/epistemics/... ./modules/continuity/... ./runtime/supervisor/... ./cmd/work-graph-runtime/... ./cmd/research-runtime/...",
"MILESTONE M4 recovery: run focused restart/checkpoint/unknown-outcome/rollback drill; no automatic go test ./... if M3 FULL remains fresh and no global schema cutover occurred."
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,116 @@
{
"task_id": "GEN2-023",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Пользователь говорит, чего хочет; Домовой меняет scoped configuration/starts work through normal semantics instead of forcing admin panels.",
"requirement_ids": [
"REQ-GEN2-023-GOAL",
"REQ-GEN2-023-BOUNDARY",
"REQ-GEN2-023-GATE"
],
"allowed_change_scope": {
"modules": [
"interaction",
"configuration",
"work",
"authority"
],
"paths": [
"modules/interaction/**",
"contracts/interaction/**",
"cmd/core-runtime/**",
"cmd/creator-web/**",
"modules/configuration/**",
"contracts/configuration/**",
"modules/work/**",
"contracts/work/**",
"contracts/authority/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-023-make-conversational-control-the-primary-configuration-and-operational-ux.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.interaction@v1",
"contracts.configuration@gen2",
"contracts.work@gen2",
"contracts.authority@v1"
],
"may_change": [
"Only contracts explicitly within GEN2-023 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Interaction + Configuration/Work contracts. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Configuration remains setting writer; Interaction writes user instruction/intent only",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: Configuration remains setting writer; Interaction writes user instruction/intent only"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: admin/read APIs remain available; conversational mutations can be disabled",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M5; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-022."
],
"acceptance_scenarios": [
"GEN2-023-SCN-01: intent patterns for setting/querying configuration",
"GEN2-023-SCN-02: explain effective scope/value in natural language",
"GEN2-023-SCN-03: one-time override vs durable preference distinction",
"GEN2-023-SCN-04: conversation creates SettingAssignment only through Configuration contract",
"GEN2-023-SCN-05: dangerous config/core changes route through Consequence + Authority/Commit",
"GEN2-023-SCN-06: Creator Web admin screens остаются diagnostics/emergency, не primary UX",
"GEN2-023-EXIT: обычные настройки не требуют ручного редактирования ENV/admin UI."
],
"required_tests": [
"FAST: go test ./modules/interaction/... ./modules/configuration/... ./modules/work/... ./cmd/core-runtime/... ./cmd/creator-web/...",
"FAST: go vet ./modules/interaction/... ./modules/configuration/... ./modules/work/... ./cmd/core-runtime/... ./cmd/creator-web/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,122 @@
{
"task_id": "GEN2-024",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Не смешивать владельца, членов семьи, гостей, голосовые источники и shared/private memory.",
"requirement_ids": [
"REQ-GEN2-024-GOAL",
"REQ-GEN2-024-BOUNDARY",
"REQ-GEN2-024-GATE"
],
"allowed_change_scope": {
"modules": [
"identity",
"world",
"epistemics",
"interaction"
],
"paths": [
"modules/identity/**",
"contracts/identity/**",
"modules/world/**",
"contracts/world/**",
"modules/epistemics/**",
"contracts/epistemics/**",
"modules/interaction/**",
"contracts/interaction/**",
"adapters/postgres/identity_repository.go",
"adapters/postgres/world_repository.go",
"adapters/postgres/epistemics_repository.go",
"adapters/postgres/interaction_repository.go",
"database/migrations/*.sql",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-024-multi-person-realms-identity-boundaries-and-contextual-source-trust.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 1
},
"contracts": {
"consume": [
"contracts.identity@v1",
"contracts.world@gen2",
"contracts.epistemics@gen2",
"contracts.interaction@v1"
],
"may_change": [
"Only contracts explicitly within GEN2-024 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Identity + World + Epistemics, separate responsibilities. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Identity authenticates principals; World resolves referents; Epistemics evaluates source reliability",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: Identity authenticates principals; World resolves referents; Epistemics evaluates source reliability"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"Database changes must be additive next-numbered migrations only until an explicitly approved retirement task; never edit historical V1 migrations 001-045.",
"At most one canonical writer is active for each semantic state; backfill/shadow reads do not create a second canonical writer.",
"The positive new_database_owner_roles delta in this packet is a devctl-v1 database-surface compatibility gate; it does not authorize cross-owner SQL/FK/JOIN or an extra owner unless explicitly stated by this task."
],
"failure_retry_restart": [
"Rollback rule: single-owner mode remains possible; new realm metadata additive",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M5; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-023."
],
"acceptance_scenarios": [
"GEN2-024-SCN-01: PrincipalDataRealm/owner/shared scopes",
"GEN2-024-SCN-02: utterance/source attribution with confidence",
"GEN2-024-SCN-03: World person referents do not equal authenticated Principal automatically",
"GEN2-024-SCN-04: SourceReliabilityAssessment = source × domain × freshness × history",
"GEN2-024-SCN-05: identity ambiguity remains explicit",
"GEN2-024-SCN-06: future speaker-recognition result enters as Observation, not authentication truth",
"GEN2-024-SCN-07: Context Compiler respects realm/scope isolation",
"GEN2-024-EXIT: Домовой может знать семейный контекст, не превращая услышанное имя/голос в полномочия владельца."
],
"required_tests": [
"FAST: go test ./modules/identity/... ./modules/world/... ./modules/epistemics/... ./modules/interaction/... ./adapters/postgres",
"FAST: go vet ./modules/identity/... ./modules/world/... ./modules/epistemics/... ./modules/interaction/... ./adapters/postgres",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,117 @@
{
"task_id": "GEN2-025",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Закрепить единый путь для text/audio/image/video/device observations, чтобы будущие микрофоны/камеры не потребовали нового ядра.",
"requirement_ids": [
"REQ-GEN2-025-GOAL",
"REQ-GEN2-025-BOUNDARY",
"REQ-GEN2-025-GATE"
],
"allowed_change_scope": {
"modules": [
"interaction",
"capability",
"artifact",
"world"
],
"paths": [
"modules/interaction/**",
"contracts/interaction/**",
"modules/capability/**",
"contracts/capability/**",
"modules/artifact/**",
"contracts/artifact/**",
"modules/world/**",
"contracts/world/**",
"adapters/multimodal/**",
"cmd/creator-web/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-025-multimodal-and-ambient-ingress-readiness-without-implementing-the-whole-.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.interaction@v1",
"contracts.capability@gen2",
"contracts.artifact@v1",
"contracts.world@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-025 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Interaction ingress + Artifact + Capability + World refs. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"Interaction/Artifact/Epistemics existing responsibilities",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: Interaction/Artifact/Epistemics existing responsibilities"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: existing chat/file routes remain compatible",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M5; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-024."
],
"acceptance_scenarios": [
"GEN2-025-SCN-01: normalise ingress envelope: modality/source/device/location/principal attribution/evidence refs",
"GEN2-025-SCN-02: raw large media -> Artifact, derived transcript/vision result -> Observation",
"GEN2-025-SCN-03: device/location are World refs",
"GEN2-025-SCN-04: speech/OCR/vision results include provenance/model/version/confidence",
"GEN2-025-SCN-05: future ambient streams can feed bounded observations/episodes without bypassing Interaction/Epistemics",
"GEN2-025-SCN-06: output device choice остаётся будущим capability, не hardcoded in core",
"GEN2-025-EXIT: будущая команда «покажи камеру улицы на телевизоре здесь» вписывается через World/Focus/Capability/Authority без смены core model."
],
"required_tests": [
"FAST: go test ./modules/interaction/... ./modules/capability/... ./modules/artifact/... ./modules/world/... ./adapters/multimodal/... ./cmd/creator-web/...",
"FAST: go vet ./modules/interaction/... ./modules/capability/... ./modules/artifact/... ./modules/world/... ./adapters/multimodal/... ./cmd/creator-web/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,135 @@
{
"task_id": "GEN2-026",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Перевести реальные бытовые сценарии на Gen2 foundation и доказать, что технический протокол не просачивается пользователю.",
"requirement_ids": [
"REQ-GEN2-026-GOAL",
"REQ-GEN2-026-BOUNDARY",
"REQ-GEN2-026-GATE"
],
"allowed_change_scope": {
"modules": [
"interaction",
"situation",
"capability",
"epistemics",
"work",
"continuity",
"configuration",
"self",
"world"
],
"paths": [
"cmd/core-runtime/**",
"cmd/cognitive-worker/**",
"cmd/creator-web/**",
"modules/interaction/**",
"modules/situation/**",
"modules/capability/**",
"modules/epistemics/**",
"modules/work/**",
"modules/continuity/**",
"modules/configuration/**",
"modules/self/**",
"modules/world/**",
"runtime/retrieval/**",
"adapters/multimodal/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-026-migrate-household-behavior-to-gen2-context-memory-skills-with-local-degr.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.interaction@gen2",
"contracts.situation@gen2",
"contracts.capability@gen2",
"contracts.epistemics@gen2",
"contracts.work@gen2",
"contracts.continuity@v1",
"contracts.configuration@gen2",
"contracts.self@gen2",
"contracts.world@gen2",
"contracts.cognitive@gen2"
],
"may_change": []
},
"semantic_owner": "Existing owners, integration task. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"no new canonical owner; integration switches reads/routes to Gen2",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: no new canonical owner; integration switches reads/routes to Gen2"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: per-subsystem switches to V1 compatibility remain until M6",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M5; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-025."
],
"acceptance_scenarios": [
"GEN2-026-SCN-01: перенести SCN-HH-001..010 на Gen2 paths",
"GEN2-026-SCN-02: name/preference continuity through scoped retrieval",
"GEN2-026-SCN-03: current data uses freshness/revalidation",
"GEN2-026-SCN-04: travel/places follows Focus/location and source evidence",
"GEN2-026-SCN-05: multi-action uses Work",
"GEN2-026-SCN-06: reminder uses Continuity",
"GEN2-026-SCN-07: multimodal uses capability/degraded path",
"GEN2-026-SCN-08: creative request avoids unnecessary web",
"GEN2-026-SCN-09: partial/unavailable/contradictory results produce honest answer",
"GEN2-026-SCN-10: short natural response",
"GEN2-026-EXIT: обычный пользователь не замечает internal Gen2 protocols; baseline household behavior preserved/improved."
],
"required_tests": [
"FAST: go test ./cmd/core-runtime/... ./cmd/cognitive-worker/... ./cmd/creator-web/... ./modules/interaction/... ./modules/situation/... ./modules/capability/... ./modules/epistemics/... ./modules/work/... ./modules/continuity/... ./runtime/retrieval/...",
"FAST: go vet ./cmd/core-runtime/... ./cmd/cognitive-worker/... ./cmd/creator-web/... ./modules/interaction/... ./modules/situation/... ./modules/capability/... ./modules/epistemics/... ./modules/work/... ./modules/continuity/... ./runtime/retrieval/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,114 @@
{
"task_id": "GEN2-027",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Перевести production на Gen2 по контролируемому canary, сохранив мгновенный rollback к последнему good release.",
"requirement_ids": [
"REQ-GEN2-027-GOAL",
"REQ-GEN2-027-BOUNDARY",
"REQ-GEN2-027-GATE"
],
"allowed_change_scope": {
"modules": [
"configuration"
],
"paths": [
"deploy/**",
"runtime/supervisor/**",
"runtime/health/**",
"modules/configuration/**",
"contracts/configuration/**",
"docs/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-027-production-canary-and-controlled-gen2-traffic-transition.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 1,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [
"contracts.configuration@gen2"
],
"may_change": [
"Only contracts explicitly within GEN2-027 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Operations/Supervisor. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"runtime release state switches via Supervisor; semantic writers already cut over by prior tasks",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"current state -> additive/shadow Gen2 path -> evidence comparison -> controlled cutover -> compatibility retention; writer rule: runtime release state switches via Supervisor; semantic writers already cut over by prior tasks"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass.",
"Deploy/release surface changes are allowed only for the bounded purpose of this packet; production promotion requires the packet's stated evidence and rollback path."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: one-command/automatic revert to last-known-good release, schema remains backward compatible",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth.",
"Cutover must keep the previous read/compatibility path available until the task or milestone explicitly proves retirement."
],
"assumptions": [
"Program milestone: M5; test profile: FULL.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-026."
],
"acceptance_scenarios": [
"GEN2-027-SCN-01: build candidate from accepted milestone commit",
"GEN2-027-SCN-02: deploy alongside or controlled replacement according to existing platform constraints",
"GEN2-027-SCN-03: health + DB migration compatibility",
"GEN2-027-SCN-04: bounded traffic/canary",
"GEN2-027-SCN-05: compare errors/latency/unknown/recovery",
"GEN2-027-SCN-06: household smoke",
"GEN2-027-SCN-07: rollback drill",
"GEN2-027-SCN-08: promote only после evidence",
"GEN2-027-SCN-09: записать production composition snapshot в SELF/Learning Ledger where appropriate",
"GEN2-027-EXIT: Gen2 handles production household traffic and rollback proven."
],
"required_tests": [
"FAST: go test ./runtime/supervisor/... ./runtime/health/... ./modules/configuration/...",
"FAST: go vet ./runtime/supervisor/... ./runtime/health/... ./modules/configuration/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --",
"FULL: go test ./...",
"FULL: go vet ./...",
"FULL M5: household + multimodal + degraded-mode + restart/recovery + production canary/rollback smoke on docker.cin.su."
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}
@@ -0,0 +1,108 @@
{
"task_id": "GEN2-028",
"task_revision": 1,
"architecture_revision": "ARCH-GEN2-000",
"base_repo_revision": "gen2-integration",
"risk_tier": "E",
"intent": "Доказать, что legacy paths больше не являются активными writers/read dependencies.",
"requirement_ids": [
"REQ-GEN2-028-GOAL",
"REQ-GEN2-028-BOUNDARY",
"REQ-GEN2-028-GATE"
],
"allowed_change_scope": {
"modules": [],
"paths": [
"modules/**",
"contracts/**",
"cmd/**",
"adapters/**",
"runtime/**",
"platform/**",
"docs/**",
"tests/**",
"dev/ACTIVE_TASK.json",
"dev/tasks/GEN2-028-inventory-v1-compatibility-usage-and-prove-retirement-readiness.json"
]
},
"forbidden_change_scope": {
"paths": [
"security/**",
"go.mod",
"go.sum",
"architecture/**",
".gitea/workflows/**",
"deploy/**",
"database/**",
"adapters/models/**"
]
},
"allowed_architecture_delta": {
"new_cross_module_dependencies": 0,
"new_canonical_owners": 0,
"new_privileges": 0,
"new_third_party_dependencies": 0,
"new_database_owner_roles": 0
},
"contracts": {
"consume": [],
"may_change": [
"Only contracts explicitly within GEN2-028 allowed_change_scope; preserve Gen2 owner boundaries and backward compatibility unless this packet says cutover."
]
},
"semantic_owner": "Migration/Governance. Follow GEN2 target architecture: owner boundaries are authoritative; Memory remains a read/retrieval fabric, World is not truth owner, SELF is not a God orchestrator.",
"canonical_state": [
"no change",
"No task may create a second canonical owner for an already-owned mutable semantic concept."
],
"state_transitions": [
"task input -> bounded Gen2 change -> FAST verification -> merge to gen2-integration; canonical writer rule: no change"
],
"side_effects_and_privileges": [
"No external mutation may bypass existing Authority -> Commit -> Executor boundaries.",
"Do not weaken architecture/security/test guardrails to make the task pass."
],
"persistence_and_migrations": [
"No database schema change is authorized by this packet unless a revised task explicitly grants database/migration scope."
],
"failure_retry_restart": [
"Rollback rule: not applicable; this task is proof only",
"Retries/restarts must not create duplicate external side effects or a second canonical writer.",
"Durable state required by this task must survive process restart; process-local memory is never the only source of truth."
],
"assumptions": [
"Program milestone: M6; test profile: FAST.",
"Task branch starts from local gen2-integration; base_repo_revision=gen2-integration must resolve to the untouched integration base while the task branch is active.",
"Codex reads DOMOVOY_CONSTITUTION.md, GEN2_TARGET_ARCHITECTURE.md, GEN2_CANONICAL_DATA_MODEL.md, GEN2_MIGRATION_MAP.md, GEN2_MASTER_PLAN.md and GEN2_EXECUTION_CONTRACT.md before non-trivial edits.",
"Do not expand scope silently. If a required change falls outside allowed paths or changes ownership, return a typed gap and request a task revision.",
"Depends on: GEN2-027."
],
"acceptance_scenarios": [
"GEN2-028-SCN-01: caller inventory",
"GEN2-028-SCN-02: writer inventory",
"GEN2-028-SCN-03: feature-switch telemetry",
"GEN2-028-SCN-04: PersonalMemory fallback usage",
"GEN2-028-SCN-05: ActiveProjectFocus compatibility usage",
"GEN2-028-SCN-06: truth_bundles read usage",
"GEN2-028-SCN-07: ordinary ENV fallback usage",
"GEN2-028-SCN-08: V1 Skill view usage",
"GEN2-028-SCN-09: rollback observation window evidence",
"GEN2-028-SCN-10: сформировать explicit retirement list, каждый пункт с rollback consequence",
"GEN2-028-EXIT: для каждого legacy path есть доказательство ACTIVE / SAFE_TO_RETIRE / KEEP_LONGER."
],
"required_tests": [
"FAST: go test ./cmd/... ./modules/... ./runtime/...",
"FAST: go vet ./cmd/... ./modules/... ./runtime/...",
"FAST governance: go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json",
"FAST scope: go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json",
"FAST independent: go run ./cmd/devctl/independent",
"FAST whitespace: git diff --check gen2-integration --"
],
"terminal_gap_states": [
"BLOCKED_BY_SPEC_GAP",
"BLOCKED_BY_ARCHITECTURE_GAP",
"BLOCKED_BY_MISSING_CAPABILITY",
"BLOCKED_BY_CONFLICT",
"REQUIRES_MIGRATION_DECISION"
]
}

Some files were not shown because too many files have changed in this diff Show More