agentirc-cli 9.11.0__tar.gz → 9.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentirc_cli-9.12.0/.devague/current +1 -0
- agentirc_cli-9.12.0/.devague/current_plan +1 -0
- agentirc_cli-9.12.0/.devague/frames/agentirc-now-speaks-presence-the-ircd-parses-resid.json +432 -0
- agentirc_cli-9.12.0/.devague/plans/agentirc-now-speaks-presence-the-ircd-parses-resid.json +318 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/CHANGELOG.md +52 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/PKG-INFO +1 -1
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/config.py +74 -7
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/events.py +13 -3
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/ircd.py +2 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/protocol.py +23 -0
- agentirc_cli-9.12.0/agentirc/skills/presence.py +574 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/api-stability.md +77 -10
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/extension-api.md +114 -0
- agentirc_cli-9.12.0/docs/plans/2026-07-07-agentirc-now-speaks-presence-the-ircd-parses-resid.md +81 -0
- agentirc_cli-9.12.0/docs/specs/2026-07-07-agentirc-now-speaks-presence-the-ircd-parses-resid.md +87 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/pyproject.toml +1 -1
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_config_loader.py +160 -24
- agentirc_cli-9.12.0/tests/test_presence.py +701 -0
- agentirc_cli-9.12.0/tests/test_presence_federation.py +419 -0
- agentirc_cli-9.12.0/tests/test_presence_stale.py +372 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_protocol_bot_exports.py +2 -2
- agentirc_cli-9.12.0/tests/test_protocol_presence.py +45 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/uv.lock +1 -1
- agentirc_cli-9.11.0/.devague/current +0 -1
- agentirc_cli-9.11.0/.devague/current_plan +0 -1
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/ask-colleague/SKILL.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/ask-colleague/prompts/explore.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/ask-colleague/prompts/review.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/ask-colleague/prompts/write.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/ask-colleague/scripts/ask-colleague.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/cicd/SKILL.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/cicd/scripts/_resolve-nick.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/cicd/scripts/portability-lint.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/cicd/scripts/pr-reply.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/cicd/scripts/pr-status.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/cicd/scripts/workflow.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/communicate/SKILL.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/recall/SKILL.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/recall/scripts/recall.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/remember/SKILL.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/remember/scripts/remember.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/spec-to-plan/SKILL.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/think/SKILL.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills/think/scripts/think.sh +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.claude/skills.local.yaml.example +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.devague/frames/agentirc-9-7-0-ships-an-embedded-bot-framework-bot.json +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.devague/frames/agentirc-ships-an-agent-accessibility-release-ai-a.json +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.devague/plans/agentirc-9-7-0-ships-an-embedded-bot-framework-bot.json +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.devague/plans/agentirc-ships-an-agent-accessibility-release-ai-a.json +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.github/workflows/publish.yml +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.github/workflows/tests.yml +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/.gitignore +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/CLAUDE.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/LICENSE +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/README.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/__main__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/aio.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/bots/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/bots/bot_manager.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/bots/http_listener.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/cli_client.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/cli_shared/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/cli_shared/constants.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/cli_shared/mesh.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/constants.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/event_subscriptions.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/pidfile.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/protocol/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/protocol/message.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/protocol/replies.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/telemetry/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/telemetry/audit.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/telemetry/context.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/telemetry/metrics.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/telemetry/tracing.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/_internal/virtual_client.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/agent_client.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/bots/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/bots/bot.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/bots/bot_manager.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/bots/cli.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/bots/config.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/bots/filter_dsl.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/bots/http_listener.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/bots/template_engine.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/bots/virtual_client.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/channel.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/cli.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/client.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/history_store.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/remote_client.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/room_store.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/rooms_util.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/server_link.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/skill.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/skills/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/skills/history.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/skills/icon.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/skills/rooms.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/skills/threads.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/thread_store.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/agentirc/virtual_client.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/agent-walkthrough.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/bots.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/cli.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/deployment.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/plans/2026-06-12-agentirc-9-7-0-ships-an-embedded-bot-framework-bot.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/plans/2026-07-01-agentirc-ships-an-agent-accessibility-release-ai-a.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/specs/2026-06-12-agentirc-9-7-0-ships-an-embedded-bot-framework-bot.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/specs/2026-07-01-agentirc-ships-an-agent-accessibility-release-ai-a.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/specs/2026-07-02-agent-accessibility-gap-verification.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/specs/2026-07-02-agent-accessibility-release-audit.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/steward/onboarding.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/superpowers/specs/2026-04-30-bootstrap-design.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/superpowers/specs/2026-05-01-bot-extension-api-design.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/docs/superpowers/specs/2026-05-01-task14-audit.md +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/_helpers.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/bots/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/bots/test_bot.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/bots/test_bot_host.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/bots/test_bot_manager.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/bots/test_cli_bot.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/bots/test_config_bots.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/bots/test_filter_dsl.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/bots/test_http_listener.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/bots/test_public_surface.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/bots/test_template_engine.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/conftest.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/__init__.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/_fakes.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/_metrics_helpers.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_audit_emit.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_audit_lifecycle.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_audit_module.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_audit_parse_error.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_config.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_dispatch_span.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_emit_event_span.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_metrics_init.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_metrics_s2s.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_outbound_inject.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_parse_error.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_s2s_relay_span.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_server_init.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_server_link_inject.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/telemetry/test_tracing.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_agent_client.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_agent_walkthrough.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_api_stability_embedding.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_bot_capability.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_channel.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_cli.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_cli_client_verbs.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_cli_json.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_client_backfill.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_connection.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_discovery.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_disk_paths.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_dm_history.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_docs_promises.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_error_tokens.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_event_subscriptions.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_eventpub.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_events_basic.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_events_catalog.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_events_federation.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_events_history.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_events_lifecycle.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_events_reserved_nick.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_federation.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_history.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_history_since.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_link_reconnect.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_liveness.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_long_messages.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_mentions.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_message_tags.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_messaging.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_modes.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_reconnect_catchup.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_room_persistence.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_rooms_federation.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_rooms_integration.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_server_icon_skill.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_skills.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_threads.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_verb_discovery.py +0 -0
- {agentirc_cli-9.11.0 → agentirc_cli-9.12.0}/tests/test_wire_format_envelope.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
agentirc-now-speaks-presence-the-ircd-parses-resid
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
agentirc-now-speaks-presence-the-ircd-parses-resid
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "agentirc-now-speaks-presence-the-ircd-parses-resid",
|
|
3
|
+
"title": "agentirc now speaks PRESENCE: the IRCd parses resident presence heartbeats, tracks per-client presence state, propagates it across server links, flags presumed-hung residents via a stale-busy watchdog, and serves the aggregate to culture via PRESENCE LIST \u2014 unblocking culture resident presence v1 (issue #53)",
|
|
4
|
+
"schema_version": 1,
|
|
5
|
+
"status": "exported",
|
|
6
|
+
"created": "2026-07-07T03:23:58Z",
|
|
7
|
+
"updated": "2026-07-07T03:44:11Z",
|
|
8
|
+
"claims": [
|
|
9
|
+
{
|
|
10
|
+
"id": "c1",
|
|
11
|
+
"kind": "announcement",
|
|
12
|
+
"text": "agentirc now speaks PRESENCE: the IRCd parses resident presence heartbeats, tracks per-client presence state, propagates it across server links, flags presumed-hung residents via a stale-busy watchdog, and serves the aggregate to culture via PRESENCE LIST \u2014 unblocking culture resident presence v1 (issue #53)",
|
|
13
|
+
"origin": "user",
|
|
14
|
+
"status": "confirmed",
|
|
15
|
+
"honesty_conditions": [
|
|
16
|
+
{
|
|
17
|
+
"id": "h19",
|
|
18
|
+
"text": "End-to-end proof on a linked pair: resident publishes PRESENCE on server A; culture-shaped 'PRESENCE LIST' on server B returns that resident's row with correct server attribution; the full pytest suite stays green; culture's adapter shape is consumed unmodified",
|
|
19
|
+
"status": "confirmed"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"hard_questions": [],
|
|
23
|
+
"links": []
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "c2",
|
|
27
|
+
"kind": "audience",
|
|
28
|
+
"text": "Primary consumer is culture's front door (the 'culture residents' CLI verb t5 and the JSON endpoint t7 for the irc-lens console); secondary audience is mesh operators and future balancing policies, plus any embedder using agentirc.ircd.IRCd",
|
|
29
|
+
"origin": "llm",
|
|
30
|
+
"status": "confirmed",
|
|
31
|
+
"honesty_conditions": [
|
|
32
|
+
{
|
|
33
|
+
"id": "h20",
|
|
34
|
+
"text": "Culture's t5/t7 transport adapter consumes the reply unmodified \u2014 proven by matching their anticipated shape (PRESENCE LIST / PRESENCELIST json / PRESENCEEND / 421 degrade) byte-for-byte in tests",
|
|
35
|
+
"status": "confirmed"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"hard_questions": [],
|
|
39
|
+
"links": []
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "c3",
|
|
43
|
+
"kind": "before_state",
|
|
44
|
+
"text": "The mesh has no visibility into which residents are busy: no presence verb exists, culture's residents CLI degrades to 'server does not support PRESENCE' (421), and a hung agent is indistinguishable from a busy one",
|
|
45
|
+
"origin": "llm",
|
|
46
|
+
"status": "confirmed",
|
|
47
|
+
"honesty_conditions": [
|
|
48
|
+
{
|
|
49
|
+
"id": "h21",
|
|
50
|
+
"text": "Verified against 9.11.0: PRESENCE currently answers 421 via the stock unknown-verb path (regression-asserted so the degrade contract holds for older servers)",
|
|
51
|
+
"status": "confirmed"
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"hard_questions": [],
|
|
55
|
+
"links": []
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "c4",
|
|
59
|
+
"kind": "after_state",
|
|
60
|
+
"text": "Any server in the mesh can render a live aggregate of every connected resident: {nick, server, state, since, task, tokens_in, tokens_out, presumed_hung, last_refresh} \u2014 including residents connected to OTHER servers via S2S propagation",
|
|
61
|
+
"origin": "llm",
|
|
62
|
+
"status": "confirmed",
|
|
63
|
+
"honesty_conditions": [
|
|
64
|
+
{
|
|
65
|
+
"id": "h22",
|
|
66
|
+
"text": "A linked-pair end-to-end test shows one PRESENCE LIST containing BOTH a local and a remote resident, every row carrying all nine keys with correct server attribution",
|
|
67
|
+
"status": "confirmed"
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"hard_questions": [],
|
|
71
|
+
"links": []
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"id": "c5",
|
|
75
|
+
"kind": "why_it_matters",
|
|
76
|
+
"text": "Operators and balancing policies can act on active-resident counts and token spend; a kill -9'd resident that last reported busy is surfaced as presumed-hung with zero cooperation from the dead process",
|
|
77
|
+
"origin": "llm",
|
|
78
|
+
"status": "confirmed",
|
|
79
|
+
"honesty_conditions": [
|
|
80
|
+
{
|
|
81
|
+
"id": "h23",
|
|
82
|
+
"text": "The aggregate alone is sufficient for culture to compute active-resident counts and per-resident token spend \u2014 no additional server round-trips or side channels needed",
|
|
83
|
+
"status": "confirmed"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"hard_questions": [],
|
|
87
|
+
"links": []
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": "c6",
|
|
91
|
+
"kind": "boundary",
|
|
92
|
+
"text": "Observe-only v1: the server never declines, defers, or blocks work based on presence or spend; budget warnings are computed culture-side. The emitter (client harness) is cultureagent's parallel task t4 \u2014 agentirc implements only the IRCd side. Wire/identity strings stay culture.* (config filename, telemetry names), never culture_core.*",
|
|
93
|
+
"origin": "llm",
|
|
94
|
+
"status": "confirmed",
|
|
95
|
+
"honesty_conditions": [
|
|
96
|
+
{
|
|
97
|
+
"id": "h6",
|
|
98
|
+
"text": "The diff contains no code path where presence state or token counters gate/defer/reject any command, message, or connection; git grep culture_core over the diff is empty",
|
|
99
|
+
"status": "confirmed"
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
"hard_questions": [],
|
|
103
|
+
"links": []
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "c7",
|
|
107
|
+
"kind": "requirement",
|
|
108
|
+
"text": "PRESENCE verb: parse per the wire contract (state/since/optional task/optional tokens_in+tokens_out); it is a NEW verb \u2014 no RFC 2812 command is redefined, and unknown-verb behavior for vanilla clients (e.g. weechat in the same channel) is unchanged",
|
|
109
|
+
"origin": "llm",
|
|
110
|
+
"status": "confirmed",
|
|
111
|
+
"honesty_conditions": [
|
|
112
|
+
{
|
|
113
|
+
"id": "h1",
|
|
114
|
+
"text": "Payload parsing matches protocol/extensions/presence.md field-for-field (names, types, optionality), and a test proves a vanilla client without the feature still gets stock 421 unknown-command semantics for any other unknown verb",
|
|
115
|
+
"status": "confirmed"
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"hard_questions": [],
|
|
119
|
+
"links": []
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"id": "c8",
|
|
123
|
+
"kind": "requirement",
|
|
124
|
+
"text": "Per-client presence state: the server keeps latest presence per connected client \u2014 state (idle|listening|thinking|working|draining|offline), since, task, token counters, last_refresh",
|
|
125
|
+
"origin": "llm",
|
|
126
|
+
"status": "confirmed",
|
|
127
|
+
"honesty_conditions": [
|
|
128
|
+
{
|
|
129
|
+
"id": "h2",
|
|
130
|
+
"text": "A test drives two heartbeats and asserts the stored state reflects the LATEST one (state, since, task, counters) with last_refresh updated server-side",
|
|
131
|
+
"status": "confirmed"
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"hard_questions": [],
|
|
135
|
+
"links": []
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"id": "c9",
|
|
139
|
+
"kind": "requirement",
|
|
140
|
+
"text": "S2S propagation: presence propagates across server links (same pattern as existing S2S relay) so residents on other servers appear in any server's aggregate view",
|
|
141
|
+
"origin": "llm",
|
|
142
|
+
"status": "confirmed",
|
|
143
|
+
"honesty_conditions": [
|
|
144
|
+
{
|
|
145
|
+
"id": "h3",
|
|
146
|
+
"text": "A linked_servers test asserts a resident connected to server A appears in server B's PRESENCE LIST with the correct server attribution, and presence state survives the case where the update predates the link (burst or re-sync on link)",
|
|
147
|
+
"status": "confirmed"
|
|
148
|
+
}
|
|
149
|
+
],
|
|
150
|
+
"hard_questions": [],
|
|
151
|
+
"links": []
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"id": "c10",
|
|
155
|
+
"kind": "requirement",
|
|
156
|
+
"text": "Stale-busy watchdog: a client whose last state is busy (non-idle, non-offline) and whose last_refresh is older than configurable stale_after is flagged presumed_hung in the aggregate; a slow-but-alive resident heartbeating through a long LLM call is NOT flagged",
|
|
157
|
+
"origin": "llm",
|
|
158
|
+
"status": "confirmed",
|
|
159
|
+
"honesty_conditions": [
|
|
160
|
+
{
|
|
161
|
+
"id": "h4",
|
|
162
|
+
"text": "Watchdog test: freeze/patch time or use short stale_after \u2014 busy client with old last_refresh is presumed_hung=true; same client after one more heartbeat is presumed_hung=false; idle and offline states are never flagged",
|
|
163
|
+
"status": "confirmed"
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
"hard_questions": [],
|
|
167
|
+
"links": []
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"id": "c11",
|
|
171
|
+
"kind": "requirement",
|
|
172
|
+
"text": "Query surface: adopt culture's anticipated shape \u2014 client sends PRESENCE LIST; server replies one PRESENCELIST :<json> line per resident (JSON object per wire contract) terminated by PRESENCEEND; servers without the feature answer 421 so culture degrades gracefully",
|
|
173
|
+
"origin": "llm",
|
|
174
|
+
"status": "confirmed",
|
|
175
|
+
"honesty_conditions": [
|
|
176
|
+
{
|
|
177
|
+
"id": "h5",
|
|
178
|
+
"text": "Wire shape is byte-compatible with culture's adapter expectation: 'PRESENCE LIST' in, one 'PRESENCELIST :<json>' per resident out, 'PRESENCEEND' terminator; the JSON object carries exactly {nick, server, state, since, task, tokens_in, tokens_out, presumed_hung, last_refresh}",
|
|
179
|
+
"status": "confirmed"
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
"hard_questions": [],
|
|
183
|
+
"links": []
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"id": "c12",
|
|
187
|
+
"kind": "success_signal",
|
|
188
|
+
"text": "Acceptance: (1) a kill -9'd resident that last reported busy is flagged presumed-hung within stale_after with zero cooperation from the dead process; (2) a slow-but-alive resident heartbeating through a long LLM call is NOT flagged; (3) culture's adapter consumes PRESENCE LIST -> PRESENCELIST/PRESENCEEND unmodified; (4) full pytest suite passes; (5) reply posted on #53 with surface shape + release version",
|
|
189
|
+
"origin": "llm",
|
|
190
|
+
"status": "confirmed",
|
|
191
|
+
"honesty_conditions": [
|
|
192
|
+
{
|
|
193
|
+
"id": "h24",
|
|
194
|
+
"text": "Each acceptance item maps to a named pytest (watchdog flag, heartbeat non-flag, byte-shape) or a PR-description checklist item (suite green, #53 reply posted)",
|
|
195
|
+
"status": "confirmed"
|
|
196
|
+
}
|
|
197
|
+
],
|
|
198
|
+
"hard_questions": [],
|
|
199
|
+
"links": []
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"id": "c13",
|
|
203
|
+
"kind": "decision",
|
|
204
|
+
"text": "Release: lands as agentirc-cli 9.12.0 (minor bump over merged 9.11.0) \u2014 this is the version floor culture pins (plan risk r4)",
|
|
205
|
+
"origin": "llm",
|
|
206
|
+
"status": "confirmed",
|
|
207
|
+
"honesty_conditions": [
|
|
208
|
+
{
|
|
209
|
+
"id": "h7",
|
|
210
|
+
"text": "pyproject.toml lands at 9.12.0 in the PR (version-bump CI check green) and the merged release publishes agentirc-cli 9.12.0 to PyPI",
|
|
211
|
+
"status": "confirmed"
|
|
212
|
+
}
|
|
213
|
+
],
|
|
214
|
+
"hard_questions": [],
|
|
215
|
+
"links": []
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"id": "c14",
|
|
219
|
+
"kind": "decision",
|
|
220
|
+
"text": "Config: stale_after and heartbeat interval land in ServerConfig / server.yaml (culture-only keys remain ignored-if-unknown for older agentirc); defaults are ours to pick and document (plan risk r1)",
|
|
221
|
+
"origin": "llm",
|
|
222
|
+
"status": "confirmed",
|
|
223
|
+
"honesty_conditions": [
|
|
224
|
+
{
|
|
225
|
+
"id": "h8",
|
|
226
|
+
"text": "ServerConfig gains the presence keys with defaults; from_yaml on an existing culture server.yaml WITHOUT the keys still loads (backward compat test)",
|
|
227
|
+
"status": "confirmed"
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
"hard_questions": [],
|
|
231
|
+
"links": []
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"id": "c15",
|
|
235
|
+
"kind": "non_goal",
|
|
236
|
+
"text": "No enforcement, no budget math, no client-side emitter, no irc-lens page \u2014 those are culture-side tasks t4/t5/t7/t8",
|
|
237
|
+
"origin": "llm",
|
|
238
|
+
"status": "confirmed",
|
|
239
|
+
"honesty_conditions": [],
|
|
240
|
+
"hard_questions": [],
|
|
241
|
+
"links": []
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"id": "c16",
|
|
245
|
+
"kind": "requirement",
|
|
246
|
+
"text": "Wire syntax (authoritative, presence.md@b69705e): publish is 'PRESENCE :<json>' \u2014 JSON object as single trailing param; fields state (required, enum), since (required, ISO-8601 UTC), task (optional, capped 128 chars), tokens_in/tokens_out (optional cumulative ints, OMITTED not null when unknown); whole line <=512 bytes; publish is fire-and-forget, no ack. Server transitions a resident to offline implicitly on disconnect/QUIT \u2014 no final PRESENCE line required",
|
|
247
|
+
"origin": "llm",
|
|
248
|
+
"status": "confirmed",
|
|
249
|
+
"honesty_conditions": [
|
|
250
|
+
{
|
|
251
|
+
"id": "h9",
|
|
252
|
+
"text": "Parser tests cover: valid full payload, state-only payload (no task/tokens), task truncation/rejection at 128 chars, invalid state enum, malformed JSON, and missing required fields \u2014 with defined non-crashing behavior for each",
|
|
253
|
+
"status": "confirmed"
|
|
254
|
+
}
|
|
255
|
+
],
|
|
256
|
+
"hard_questions": [],
|
|
257
|
+
"links": []
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"id": "c17",
|
|
261
|
+
"kind": "decision",
|
|
262
|
+
"text": "Adopt culture's shipped config defaults verbatim (resolves plan risk r1 for agentirc): heartbeat_interval_seconds=30, stale_after_seconds=90, validated positive ints with stale_after strictly greater than heartbeat_interval, fail-fast at config load",
|
|
263
|
+
"origin": "llm",
|
|
264
|
+
"status": "confirmed",
|
|
265
|
+
"honesty_conditions": [
|
|
266
|
+
{
|
|
267
|
+
"id": "h10",
|
|
268
|
+
"text": "ServerConfig defaults are 30/90; a config with stale_after <= heartbeat_interval fails at load with a clear error; culture's shipped docs/resident-presence.md values match ours exactly",
|
|
269
|
+
"status": "confirmed"
|
|
270
|
+
}
|
|
271
|
+
],
|
|
272
|
+
"hard_questions": [],
|
|
273
|
+
"links": []
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"id": "c18",
|
|
277
|
+
"kind": "decision",
|
|
278
|
+
"text": "No CAP gating in v1: PRESENCE / PRESENCE LIST are plain new verbs (contract says a 'culture/presence' capability notification stream is a possible v2, out of scope); v1 never relays PRESENCE to clients \u2014 the server consumes it solely for aggregation",
|
|
279
|
+
"origin": "llm",
|
|
280
|
+
"status": "confirmed",
|
|
281
|
+
"honesty_conditions": [],
|
|
282
|
+
"hard_questions": [],
|
|
283
|
+
"links": []
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"id": "c19",
|
|
287
|
+
"kind": "decision",
|
|
288
|
+
"text": "Terminator lines match the anticipated contract byte-for-byte: 'PRESENCELIST :<json>' per resident, 'PRESENCEEND :End of presence list' terminator, and unsupported servers answer '421 <nick> PRESENCE :Unknown command'",
|
|
289
|
+
"origin": "llm",
|
|
290
|
+
"status": "confirmed",
|
|
291
|
+
"honesty_conditions": [
|
|
292
|
+
{
|
|
293
|
+
"id": "h11",
|
|
294
|
+
"text": "A byte-level test asserts the exact reply lines including the ':End of presence list' trailing and that an agentirc WITHOUT the feature (i.e. current 9.11.0 behavior) already produces 421 for PRESENCE",
|
|
295
|
+
"status": "confirmed"
|
|
296
|
+
}
|
|
297
|
+
],
|
|
298
|
+
"hard_questions": [],
|
|
299
|
+
"links": []
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"id": "c20",
|
|
303
|
+
"kind": "decision",
|
|
304
|
+
"text": "Implementation shape: a PresenceSkill (agentirc/skills/presence.py) following the rooms/threads/history/icon precedent \u2014 owns the PRESENCE verb (publish + LIST subcommand via skill.commands), the per-resident registry, and offline transitions via event hooks; PRESENCELIST/PRESENCEEND replies mirror the THREADS/THREADSEND template byte-shape",
|
|
305
|
+
"origin": "llm",
|
|
306
|
+
"status": "confirmed",
|
|
307
|
+
"honesty_conditions": [
|
|
308
|
+
{
|
|
309
|
+
"id": "h12",
|
|
310
|
+
"text": "The skill registers via IRCd.register_skill with commands={'PRESENCE'}; an unmodified 9.11.0 server (skill absent) answers PRESENCE with stock 421 \u2014 proven by the existing dispatch path, no gating code added",
|
|
311
|
+
"status": "confirmed"
|
|
312
|
+
}
|
|
313
|
+
],
|
|
314
|
+
"hard_questions": [],
|
|
315
|
+
"links": []
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
"id": "c21",
|
|
319
|
+
"kind": "decision",
|
|
320
|
+
"text": "S2S via the existing event bus: presence updates emit Event(type='presence.update') through IRCd.emit_event, free-riding the generic SEVENT relay with its origin-tag loop prevention (no new typed S2S verb, no hop counts); burst-on-link = on SERVER_LINK the skill re-emits the local presence snapshot (idempotent overwrites); on SERVER_UNLINK rows attributed to the lost server flip to offline; 'presence.update' joins NO_SURFACE_EVENT_TYPES so 30s heartbeats never spam #system",
|
|
321
|
+
"origin": "llm",
|
|
322
|
+
"status": "confirmed",
|
|
323
|
+
"honesty_conditions": [
|
|
324
|
+
{
|
|
325
|
+
"id": "h13",
|
|
326
|
+
"text": "linked_servers tests prove: (1) a presence update on A appears in B's LIST; (2) no relay loop (count_until_idle style, mirroring test_federated_event_does_not_loop); (3) a client connected BEFORE the link is established still appears on the peer after link-up (snapshot re-emit); (4) SERVER_UNLINK flips the lost server's rows to offline",
|
|
327
|
+
"status": "confirmed"
|
|
328
|
+
}
|
|
329
|
+
],
|
|
330
|
+
"hard_questions": [],
|
|
331
|
+
"links": []
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"id": "c22",
|
|
335
|
+
"kind": "decision",
|
|
336
|
+
"text": "presumed_hung is computed at read time (state is busy AND now - last_refresh > stale_after) rather than by a background sweep task \u2014 observably identical for the aggregate view ('flagged within stale-T' holds for any read after stale-T), zero new task lifecycle, and tests need only a small configured stale_after, no time-freezing",
|
|
337
|
+
"origin": "llm",
|
|
338
|
+
"status": "confirmed",
|
|
339
|
+
"honesty_conditions": [
|
|
340
|
+
{
|
|
341
|
+
"id": "h14",
|
|
342
|
+
"text": "With stale_after configured small in a test: a client that publishes a busy state then goes silent (connection open) reads presumed_hung=true after stale_after; one more heartbeat flips it back to false; idle/offline rows never flag",
|
|
343
|
+
"status": "confirmed"
|
|
344
|
+
}
|
|
345
|
+
],
|
|
346
|
+
"hard_questions": [],
|
|
347
|
+
"links": []
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"id": "c23",
|
|
351
|
+
"kind": "decision",
|
|
352
|
+
"text": "Config: a PresenceConfig dataclass (heartbeat_interval_seconds=30, stale_after_seconds=90) on ServerConfig, parsed from the nested 'presence:' YAML section exactly as culture ships it (TelemetryConfig precedent), so one ~/.culture/server.yaml keeps driving both daemons; fail-fast at load when stale_after <= heartbeat_interval",
|
|
353
|
+
"origin": "llm",
|
|
354
|
+
"status": "confirmed",
|
|
355
|
+
"honesty_conditions": [
|
|
356
|
+
{
|
|
357
|
+
"id": "h15",
|
|
358
|
+
"text": "from_yaml on culture's shipped presence: section yields 30/90; absent section yields the same defaults; stale<=heartbeat raises at load with a clear message; unknown keys inside presence: are ignored like other culture-only keys",
|
|
359
|
+
"status": "confirmed"
|
|
360
|
+
}
|
|
361
|
+
],
|
|
362
|
+
"hard_questions": [],
|
|
363
|
+
"links": []
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"id": "c24",
|
|
367
|
+
"kind": "decision",
|
|
368
|
+
"text": "PRESENCELIST rows always emit all nine keys ({nick, server, state, since, task, tokens_in, tokens_out, presumed_hung, last_refresh}) with JSON null for unknown task/token values \u2014 stable shape for culture's parser; since/last_refresh are ISO-8601 UTC",
|
|
369
|
+
"origin": "llm",
|
|
370
|
+
"status": "confirmed",
|
|
371
|
+
"honesty_conditions": [
|
|
372
|
+
{
|
|
373
|
+
"id": "h16",
|
|
374
|
+
"text": "A byte-level test parses each PRESENCELIST trailing param as JSON and asserts exactly the nine keys, null task/tokens for a state-only publisher, and ISO-8601 UTC since/last_refresh",
|
|
375
|
+
"status": "confirmed"
|
|
376
|
+
}
|
|
377
|
+
],
|
|
378
|
+
"hard_questions": [],
|
|
379
|
+
"links": []
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
"id": "c25",
|
|
383
|
+
"kind": "assumption",
|
|
384
|
+
"text": "A 9.11 peer receiving SEVENT presence.update tolerates the unknown event type (the 9.5.0 EVENTPUB feature already federates custom-typed events), so a mixed-version mesh degrades gracefully \u2014 to be code-verified during implementation",
|
|
385
|
+
"origin": "llm",
|
|
386
|
+
"status": "confirmed",
|
|
387
|
+
"honesty_conditions": [
|
|
388
|
+
{
|
|
389
|
+
"id": "h17",
|
|
390
|
+
"text": "Code-read of 9.11.0 _handle_sevent + emit_event confirms unknown type strings flow as custom events without exception (or a mixed-version test proves it); finding otherwise forces a typed-relay redesign before merge",
|
|
391
|
+
"status": "confirmed"
|
|
392
|
+
}
|
|
393
|
+
],
|
|
394
|
+
"hard_questions": [],
|
|
395
|
+
"links": []
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
"id": "c26",
|
|
399
|
+
"kind": "assumption",
|
|
400
|
+
"text": "kill -9 that produces a clean TCP FIN yields an accurate 'offline' row (the contract mandates implicit offline on disconnect); presumed_hung covers silent deaths \u2014 partitions, lost FINs, stalled-but-connected processes \u2014 so the acceptance test simulates a client that stops heartbeating WITHOUT disconnecting",
|
|
401
|
+
"origin": "llm",
|
|
402
|
+
"status": "confirmed",
|
|
403
|
+
"honesty_conditions": [
|
|
404
|
+
{
|
|
405
|
+
"id": "h18",
|
|
406
|
+
"text": "The watchdog acceptance test drives a real TCP client that publishes working, then stalls silently; it is flagged within stale_after with zero further writes from the client",
|
|
407
|
+
"status": "confirmed"
|
|
408
|
+
}
|
|
409
|
+
],
|
|
410
|
+
"hard_questions": [],
|
|
411
|
+
"links": []
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
"id": "c27",
|
|
415
|
+
"kind": "decision",
|
|
416
|
+
"text": "Offline-row retention (q1, user-decided): on disconnect a resident's row flips to state=offline and STAYS in the aggregate \u2014 keyed by nick, overwritten on reconnect, cleared on server restart; no TTL/prune in v1",
|
|
417
|
+
"origin": "user",
|
|
418
|
+
"status": "confirmed",
|
|
419
|
+
"honesty_conditions": [],
|
|
420
|
+
"hard_questions": [],
|
|
421
|
+
"links": []
|
|
422
|
+
}
|
|
423
|
+
],
|
|
424
|
+
"open_vagueness": [
|
|
425
|
+
{
|
|
426
|
+
"id": "v1",
|
|
427
|
+
"text": "Whether presence transitions should also emit into the existing EVENTSUB event stream (EVENT_TYPE_PRESENCE_*) so bots can react \u2014 contract is silent; keep v1 scope tight, revisit as v2 alongside the culture/presence CAP notification stream",
|
|
428
|
+
"kind": "follow_up",
|
|
429
|
+
"claim_id": null
|
|
430
|
+
}
|
|
431
|
+
]
|
|
432
|
+
}
|