Skip to content

data: rebake osint-v3 — store GUID tiers in declared field order (hi/lo fix)#86

Merged
AdaWorldAPI merged 3 commits into
mainfrom
claude/osint-v3-rebake
Jul 6, 2026
Merged

data: rebake osint-v3 — store GUID tiers in declared field order (hi/lo fix)#86
AdaWorldAPI merged 3 commits into
mainfrom
claude/osint-v3-rebake

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

Resolves the byte-order mismatch flagged in #84 (operator-approved rebake): the V3 bake stored u16 GUID tiers little-endian (lo,hi) while the field declarations (OSINT_SYSTEM_FIELDS/OSINT_PERSON_FIELDS and the contract law field position i = facet byte i) read (hi,lo). The data is now stored in declared field order — no code changes needed or made.

Decode rates (measured, no swap, against the codebook)

before after
GUID1 (611 nodes) 16/611 609/611
GUID2 (133 persons) 52/133 133/133

The finding from #84 reproduced exactly before transforming. A second independent smoking gun surfaced: pre-fix, the person motive value sat in the TWIG _ padding byte; post-fix the padding byte is 0 for all 133 persons.

Method

No in-repo baker exists (data/osint-v3/ comes from the external aiwar-neo4j-harvest; the in-repo osint-bake crate produces a different artifact). One-shot transform checked in at scripts/osint_v3_rebake_hilo.py: swaps tier bytes 4..16 pairwise per GUID, leaves classid (0x07011000)/row_id/header byte-identical, rewrites .soa + nodes.json consistently, cross-verifies byte-for-byte, and refuses to re-run on already-corrected data (pairwise swap is self-inverse).

Verification beyond the script's own asserts: header/stride/len intact (3/36/22012); 0 .soanodes.json mismatches; unswap(new)==old for all 611 rows; non-GUID fields identical; 611 rows / 133 persons unchanged. Independent spot-probe (orchestrator): LiorDiv guid2 [4,1,2,3,2,0,…] → stage=IV, need=nPow, receptor=STATUS, rubicon=ACTIONAL, motive=STATUS, padding=0 — all in-vocab.

Findings recorded in the bake README (dated note)

  • McClelland indexing is 1-based (empirical: every field's observed max equals its vocab length; 0-indexing would overflow 26/133). This unblocks the guid2 decode that cockpit: unified ClassView card — OSINT node detail popup + generic /api/card.html route #84 deliberately left off — follow-up: build the person-tier reverse map in osint_classview.rs with vocab[v-1].
  • Residual 2/611 guid1 out-of-vocab are genuine codebook↔harvest gaps, not swap artifacts: DreamSecurity MLType=30 (vocab max 29), Shoebox civicUse=17 (max 16).

With this merged, the mechanical OSINT_DECODE in the cockpit card starts hitting ~609/611 automatically — analyst-readable values in the node detail popup instead of raw bytes.

🤖 Generated with Claude Code


Generated by Claude Code

…lo fix)

The bake stored each 6x(8:8) tier as a little-endian u16, landing the two
bytes of every hi:lo pair as (lo, hi). The field cards in
crates/cockpit-server/src/osint_classview.rs (OSINT_SYSTEM_FIELDS 12,
OSINT_PERSON_FIELDS 5) and the contract position law (field position i =
facet byte i, hi:lo reading) read position i as facet byte i. The two
disagreed by a byte swap within each tier pair.

Decoding the pre-fix bake against the codebook's declared order landed only
16/611 GUID1 and 52/133 GUID2 values in-vocabulary; swapping each tier
pair's two bytes raises that to 609/611 GUID1 and 133/133 GUID2. (The 52/133
GUID2 "before" counts the 5 McClelland fields 1-based ignoring the TWIG "_"
padding byte; the stricter count that also requires the padding byte empty is
0/133 -> 133/133, because pre-fix the motive value sat in the padding slot,
not its own position.) Per operator ruling the DATA is fixed, not the field
declarations.

Transform: scripts/osint_v3_rebake_hilo.py (checked in) — no in-repo baker
exists (baked from the external aiwar-neo4j-harvest, not regenerable offline),
so a deliberate one-shot swaps tier bytes 4..16 pairwise per GUID while
leaving the classid u32 (0x07011000), row_id, header, and every non-GUID
node field byte-identical (unswap(new) == old for all 611 rows). The .soa and
osint_v3_nodes.json are rewritten consistently and cross-verified
byte-for-byte; row count 611 and persons 133 unchanged. The script refuses to
re-run on already-corrected data (a pairwise swap is its own inverse).

The residual 2/611 GUID1 out-of-vocab after the fix are genuine
codebook-vs-harvest gaps, not swap artifacts: DreamSecurity MLType=30 (vocab
max 29) and Shoebox civicUse=17 (vocab max 16).

McClelland indexing (GUID2 persons): the corrected tiers are 1-indexed against
mcclelland_vocab (value v -> vocab[v-1]). Every field's values fall in 1..=len
with observed max equal to the vocab length and no meaningful zeros; under
0-indexing 26/133 would overflow their arrays. The TWIG "_" padding byte is 0
for all 133 persons after the fix (pre-fix it carried the motive value).

No code or tests changed: no Rust source reads these tier bytes (osint_gotham.rs
bakes its own separate osint_scene.soa) and the osint_classview.rs tests assert
only field labels/counts, with no hardcoded GUID bytes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jEwwaT5JZ5x8qWvcnaMYC
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AdaWorldAPI, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 2 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4becce98-04f4-4f95-a416-bb5a40075d5a

📥 Commits

Reviewing files that changed from the base of the PR and between cb8a841 and f7fa4f8.

📒 Files selected for processing (5)
  • .gitignore
  • data/osint-v3/OSINT_V3_BAKE_README.md
  • data/osint-v3/osint_v3.soa
  • data/osint-v3/osint_v3_nodes.json
  • scripts/osint_v3_rebake_hilo.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f637227. Configure here.

print(f" GUID2 in-vocab: as-stored {g2}/{npers} if-swapped {g2s}/{npers}")

if check_only:
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check mode skips SoA JSON sync

Medium Severity

With --check, the script validates the .soa header and row count, then reports in-vocabulary decode rates using only osint_v3_nodes.json. It never compares each record’s GUID bytes in osint_v3.soa to the matching guid1/guid2 hex fields, so a successful --check exit can happen while the binary and JSON disagree.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f637227. Configure here.

….json

Cursor Bugbot (PR #86, Medium) found that --check validated the .soa header and
row count and reported in-vocabulary decode rates from osint_v3_nodes.json only,
never comparing each row's stored GUID bytes to the matching guid1/guid2 hex
fields — so a --check could exit 0 while the binary and the JSON disagreed. The
byte-for-byte cross-verify that already lived inline in the transform path is
now factored into a shared cross_verify_soa_vs_nodes() helper (row_id agreement,
GUID1/GUID2 full-hex agreement, null-guid2 all-zero, canonical classid prefix),
which both --check and the transform path call so they cannot drift. In check
mode it iterates every stride-36 row, and on any mismatch prints the first few
offending rows (row id + field + soa/json hex) and exits non-zero; the existing
decode-rate reporting is unchanged. Verified against the current rebaked data:
--check reports "CROSS-VERIFY OK: 611 rows" and exits 0. Detection proven on an
isolated scratchpad copy (real files untouched) by flipping one GUID1 byte at
row 42 — check printed "CROSS-VERIFY FAILED: 1 mismatch ... row_index=42
row_id=42 field=guid1" and exited 1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jEwwaT5JZ5x8qWvcnaMYC

AdaWorldAPI commented Jul 6, 2026

Copy link
Copy Markdown
Owner Author

Bugbot finding addressed in 377fbfeb: --check now cross-verifies every .soa row's GUID1/GUID2 bytes against the row-matched nodes.json entry (plus row_id agreement and the canonical classid prefix). The byte-for-byte verify that lived inline in the transform path was factored into one shared helper both paths call, so they cannot drift apart.

Proof both ways:

  • Real rebaked data: CROSS-VERIFY OK: 611 rows — exit 0
  • Deliberately corrupted scratchpad copy (one GUID1 byte flipped at row 42): CROSS-VERIFY FAILED: 1 mismatch(es) … row_index=42 field=guid1 soa=… json=… — exit 1, first offending rows named

Generated by Claude Code

@AdaWorldAPI AdaWorldAPI merged commit 5293613 into main Jul 6, 2026
4 checks passed
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.

2 participants