Skip to content

fix(node): a respawn is not a first sighting - #6463

Merged
vivekchand merged 1 commit into
mainfrom
fix/node-activity-signal
Oct 16, 2026
Merged

vivekchand merged 1 commit into
mainfrom
fix/node-activity-signal

Conversation

@vivekchand

@vivekchand vivekchand commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Requirement: https://factory.8090.ai/project/b415065f-ab2f-4f53-8864-0c009fd098cb/requirements/d33e1d0b-43c1-4d3f-8d0d-8de6628d0583

Follows #6445, which landed the readable counts, the lsof listener fallback, measured process CPU and the removal of the attribution map. This PR is now only the defect that one did not reach, in node_activity_store.py.

The defect

On a live macOS node, 1,999 of the 2,000 retained events were "A process was first observed":

Program Announcements in the window
contactsd 556
mdworker_shared 462
Google Chrome Helper 150

1,930 of the 1,999 were repeat announcements of 165 programs. The declared 24 hour retention window held 3.1 hours of real history, so a sensitive-settings change or a new listener is evicted by operating-system daemon churn long before an operator sees it. Replay, the event list and the Guard view all read as noise, and the snapshot pushed to cloud carried 2.7 MB of it.

The cause

The sighting ledger was keyed by the run: the PID plus its measured start time. Every respawn of a daemon is a new run, so every respawn satisfied "a process identity not known in the current retained-history context" and announced itself again. The run is the correct identity for the inventory and for the comparison baseline, and both keep it. It is the wrong identity for the sentence the event states.

The fix

A program ledger beside the run ledger, bounded at 4,096 and expiring on the same retained window, so a program absent for the whole window is news again when it returns. A run of an already-announced program still lands in the process list and in the comparison baseline, just without a second announcement.

Verification

  • 97 tests green across the five node-activity suites on top of fix: make node observations understandable and measurable #6445.
  • The guard reproduces the defect rather than restating the fix: against the unfixed ledger it reports 7 sightings for one program where it wants 1. Run, seen to fail, restored, seen to pass.
  • Fixture rows gain distinct program names. A fixture sharing one name would have measured the dedup instead of the case under test, and the counts in six existing tests would have silently become 1.
  • Installed into the live daemon and restarted: 44 announcements since, none of them a repeat, and process_count reads 454 rather than null.

The 2,000 churn events already stored age out over the next 24 hours; nothing is deleted to make the screen look better.

🤖 Generated with Claude Code

@8090-software-factory

Copy link
Copy Markdown

⚠️ Drift Bot (ClawMetry): 1 potential drift finding(s)

1. Requirement: Node activity: observe changes, review risk and show coverage

File: clawmetry/node_activity_store.py:321

The code implements "operator" as a new actor kind for preference-change events, but this actor kind and its meaning are not documented in the Node activity requirements or the related clarity follow-up requirement. REQ-GOV-NODE-003.1 specifies that unattributed activity "shall not invent a human, agent, or attacker identity," but does not document operator-initiated actions as a supported attribution type.

@github-actions

Copy link
Copy Markdown
Contributor

Visual diff

Comparing 0a72fa63cb40 (head) against the PR base branch.

2 of 86 comparison(s) flagged (>1% pixel diff).

View Before After Diff
desktop overview before after diff · 0.00%
desktop flow before after diff · 0.04%
desktop brain before after diff · 0.00%
desktop usage before after diff · 0.00%
desktop crons before after diff · 0.00%
desktop memory before after diff · 0.03%
desktop security before after diff · 0.00%
desktop subagents before after diff · 0.00%
desktop transcripts before after diff · 0.00%
desktop logs before after diff · 0.00%
desktop skills before after diff · 0.01%
desktop models before after diff · 0.01%
desktop approvals before after diff · 0.03%
desktop alerts before after diff · 0.00%
desktop notifications before after diff · 0.01%
desktop limits before after diff · 0.01%
desktop history before after diff · 0.01%
desktop channels before after diff · 0.01%
desktop harness before after diff · 0.00%
desktop inventory before after diff · 0.00%
desktop node-activity ⚠️ before after diff · 100.00%
desktop assistant before after diff · 0.00%
desktop setup before after diff · 0.01%
desktop improve before after diff · 0.02%
desktop nemoclaw before after diff · 0.00%
desktop guard before after diff · 0.01%
desktop signals before after diff · 0.01%
desktop policy before after diff · 0.00%
desktop selfevolve before after diff · 0.00%
desktop swimlane before after diff · 0.01%
desktop tool-catalog before after diff · 0.01%
desktop tracing before after diff · 0.00%
desktop turn-anatomy before after diff · 0.02%
desktop version-impact before after diff · 0.01%
desktop context-economics before after diff · 0.00%
desktop agents before after diff · 0.01%
desktop dives before after diff · 0.00%
desktop evals before after diff · 0.00%
desktop bench before after diff · 0.01%
desktop trail before after diff · 0.00%
desktop compliance before after diff · 0.01%
desktop price-book before after diff · 0.00%
desktop delivery before after diff · 0.01%
mobile overview before after diff · 0.00%
mobile flow before after diff · 0.00%
mobile brain before after diff · 0.03%
mobile usage before after diff · 0.00%
mobile crons before after diff · 0.00%
mobile memory before after diff · 0.03%
mobile security before after diff · 0.03%
mobile subagents before after diff · 0.00%
mobile transcripts before after diff · 0.00%
mobile logs before after diff · 0.63%
mobile skills before after diff · 0.01%
mobile models before after diff · 0.00%
mobile approvals before after diff · 0.08%
mobile alerts before after diff · 0.00%
mobile notifications before after diff · 0.00%
mobile limits before after diff · 0.00%
mobile history before after diff · 0.00%
mobile channels before after diff · 0.00%
mobile harness before after diff · 0.00%
mobile inventory before after diff · 0.00%
mobile node-activity ⚠️ before after diff · 100.00%
mobile assistant before after diff · 0.00%
mobile setup before after diff · 0.00%
mobile improve before after diff · 0.05%
mobile nemoclaw before after diff · 0.00%
mobile guard before after diff · 0.00%
mobile signals before after diff · 0.00%
mobile policy before after diff · 0.00%
mobile selfevolve before after diff · 0.00%
mobile swimlane before after diff · 0.00%
mobile tool-catalog before after diff · 0.00%
mobile tracing before after diff · 0.00%
mobile turn-anatomy before after diff · 0.03%
mobile version-impact before after diff · 0.00%
mobile context-economics before after diff · 0.00%
mobile agents before after diff · 0.00%
mobile dives before after diff · 0.00%
mobile evals before after diff · 0.00%
mobile bench before after diff · 0.00%
mobile trail before after diff · 0.00%
mobile compliance before after diff · 0.00%
mobile price-book before after diff · 0.00%
mobile delivery before after diff · 0.00%

Folder: 0a72fa63cb40. Full PNGs also attached as a workflow artefact.

Generated by visual-diff bot. Pixel diffs >1% flagged; eyeball the table before merging. This check is non-blocking — fail = bot bug, not a code problem.

On a live macOS node, 1,999 of the 2,000 retained Node activity events were
"A process was first observed": contactsd 556 times, mdworker_shared 462,
Google Chrome Helper 150. The declared 24 hour retention window therefore
held 3.1 hours of history, so a sensitive-settings change or a new listener
is evicted by operating-system daemon churn long before an operator sees it.

The sighting ledger was keyed by the run, that is the PID plus its measured
start time. Every respawn of a daemon is a new run, so every respawn read as
a first sighting. The run is the right identity for the inventory and for the
comparison baseline, and both keep it. It is the wrong identity for the
sentence the event states.

The ledger now carries a program ledger alongside the run ledger, bounded at
4,096 programs and expiring on the same retained window, so a program absent
for the whole window is news again when it returns. Runs of an
already-announced program stay in the process list and the baseline without a
second announcement.

Measured after installing this on that node: 44 announcements, none of them a
repeat. The guard reproduces the defect directly and reports 7 sightings for
one program against the unfixed ledger where it wants 1. Fixture rows gain
distinct program names, because a fixture that shares one name would measure
the dedup instead of the case under test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vivekchand
vivekchand force-pushed the fix/node-activity-signal branch from 0a72fa6 to 5fb63ee Compare October 16, 2026 22:36
@vivekchand vivekchand changed the title fix(node): say what was observed, once, and only when a lane can be filled fix(node): a respawn is not a first sighting Oct 16, 2026
@8090-software-factory

Copy link
Copy Markdown

✅ Drift Bot (ClawMetry): no drift detected

Drift Bot analyzed the changed files against this project's blueprints and requirements and found no drift.

@vivekchand
vivekchand merged commit da8fae6 into main Oct 16, 2026
50 of 51 checks passed
vivekchand added a commit that referenced this pull request Oct 16, 2026
…ted (carries #6463 and #6445) (#6464)

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@vivekchand
vivekchand deleted the fix/node-activity-signal branch October 17, 2026 00:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant