Skip to content

Complete HBNJ eight-day compatibility pass - #5

Merged
ColinGamez merged 1 commit into
mainfrom
agent/hbnj-compatibility-pass
Jul 24, 2026
Merged

Complete HBNJ eight-day compatibility pass#5
ColinGamez merged 1 commit into
mainfrom
agent/hbnj-compatibility-pass

Conversation

@ColinGamez

@ColinGamez ColinGamez commented Jul 24, 2026

Copy link
Copy Markdown
Owner

What changed

  • collect and merge all eight native TV no Tomo broadcast days
  • populate the recovered 12-entry Japanese genre table in header.bin
  • keep header.bin current through a dedicated daily WC24 task
  • reject unknown numeric areas instead of serving the oversized national guide
  • enforce program, LZ10, and 4 MiB VFF capacity limits before publication
  • repair scheduled-task UTF-8 logging and keep the expanded build within its runtime budget
  • update public HBNJ status and architecture documentation

Why

The working one-day guide still left the date carousel mostly empty, Genre Search had no labels because cached setup metadata contained a zero-count table, and an unknown area route could fall back to a package far beyond the channel's 24-station model.

Validation

  • full 2026-07-24 through 2026-07-31 build: 54 areas, 376 stations, 123,803 programs
  • independent HDPK parse: 12 genres and 104,665 descriptions
  • all 54 regional EPG/string pairs cross-validated
  • Gunma VFF payload envelope: 765,258 bytes of 4 MiB
  • live WC24 AES-OFB/LZ10 delivery verified for header, EPG, and strings
  • activation, query, popularity, and /bin1/ CGI contracts verified
  • unknown-area request verified as HTTP 404
  • Python compilation, PowerShell parsing, and diff checks passed

Summary by Sourcery

Extend the HBNJ adapter to build and serve a native eight-day guide window while keeping header metadata and payload sizes within original channel constraints.

New Features:

  • Support collection and publication of up to eight consecutive broadcast days across all HBNJ broadcast areas.
  • Populate the native header genre table with 12 Japanese category labels to restore in-channel genre search.
  • Record per-area multi-day source metadata, including dates, URLs, and daily program counts, in the guide output.

Bug Fixes:

  • Reject unknown numeric area requests with HTTP 404 instead of falling back to an oversized national payload.
  • Ensure scheduled Windows WC24 daily tasks log UTF-8 output correctly without breaking PowerShell execution.

Enhancements:

  • Tighten guide validation to enforce multi-day consistency, per-channel date coverage, native program capacity limits, and area payload size ceilings for LZ10 and 4 MiB VFF.
  • Refine header, EPG, and string payload validation with genre-table checks and area-level size reporting.
  • Update HBNJ user-facing documentation to describe the full eight-day window, restored genre search, and tightened publication process.
  • Adjust the daily build workflow defaults to collect eight days with a shorter courtesy delay, keeping the job within its runtime budget.

Tests:

  • Expand validation tooling to cover multi-day guide windows, genre-table integrity, per-area payload capacity, and native payload audits.

@sourcery-ai

sourcery-ai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Reviewer's Guide

Extend the HBNJ tooling and adapter to collect, validate, pack, and serve an eight-day native TV no Tomo guide, while enforcing payload capacity limits and tightening WC24/runtime behavior and documentation.

Sequence diagram for HBNJ area payload GET handling with unknown-area rejection

sequenceDiagram
    actor WiiClient
    participant HBNJServer as jwc24_server
    participant FileSystem

    WiiClient->>HBNJServer: do_GET
    HBNJServer->>FileSystem: resolve area_payload path
    alt area_payload exists
        HBNJServer->>FileSystem: read_bytes
        alt item.compression == nintendo-lz10
            HBNJServer->>HBNJServer: _nintendo_lz10_literal(body)
        end
        HBNJServer-->>WiiClient: 200 OK native payload
    else area_payload missing
        HBNJServer->>WiiClient: send_error(HTTPStatus.NOT_FOUND)
    end
Loading

Flow diagram for eight-day HBNJ guide collection and capacity validation

flowchart LR
    update_hbnj_daily[update_hbnj_daily.py main]
    collect_all[collect_hbnj_all.py main]
    validate_guide[validate_hbnj_guide.py main]
    validate_area[validate_hbnj_area_payloads.py main]
    pack_header[pack_hbnj_guide.py make_header]
    validate_payloads[validate_hbnj_payloads.py main]
    publish[collect_hbnj_region.atomic_json]

    update_hbnj_daily --> collect_all
    collect_all --> validate_guide
    validate_guide --> validate_area
    validate_area --> pack_header
    pack_header --> validate_payloads
    validate_payloads --> publish

    subgraph Multi_day_collection
        collect_all_days[collect_hbnj_all: iterate broadcast_dates]
        merge_programs[merge_duplicate_program per area]
        annotate_sources[per-area source_urls broadcast_dates daily_program_counts]
        collect_all --> collect_all_days --> merge_programs --> annotate_sources
    end

    subgraph Capacity_checks
        guide_limits[validate_hbnj_guide: days 1..8, per-channel 768-program limit]
        area_limits[validate_hbnj_area_payloads: literal_lz10_size, VFF_CAPACITY]
        header_genres[validate_hbnj_payloads: header genre table labels]
        validate_guide --> guide_limits
        validate_area --> area_limits
        validate_payloads --> header_genres
    end
Loading

File-Level Changes

Change Details Files
Collect and merge up to eight consecutive broadcast days per area into a single canonical guide document.
  • Add a --days parameter (1–8) and derive the broadcast date window from the starting date
  • Introduce collect_with_retry to centralize fetch/parse retry logic with exponential backoff
  • Normalize per-day regional channels to a canonical per-area lineup and merge duplicate programs across days with consistency checks
  • Aggregate per-area multi-day program sets, source URLs, broadcast_dates, and daily_program_counts into the guide sources metadata
  • Annotate the top-level guide with broadcast_end_date and days fields
tools/collect_hbnj_all.py
Tighten guide-level validation for multi-day coverage and per-channel capacity constraints.
  • Validate days field range and ensure broadcast_end_date matches the requested window
  • Derive the set of expected broadcast_dates and require each channel to have program starts on every date
  • Enforce native 768-program maximum per channel and detect overlapping program windows
  • Verify multi-day source metadata completeness (broadcast_dates, source_urls, daily_program_counts)
  • Extend validation output to include days in the summary line
tools/validate_hbnj_guide.py
Populate and validate the native header genre-search table with 12 canonical Japanese category labels.
  • Define GENRE_NAMES for the 12 ARIB-aligned Japanese genre labels
  • Lay out the genre table in header.bin with count/pointer, ordered entries, and text offsets matching one-based genre IDs
  • Append encoded genre strings to the header text section alongside stations and areas
  • Add EXPECTED_GENRE_NAMES and checks that header genre table count/pointer, positions, and labels match the canonical set
  • Include genre_count in the native payload validation summary
tools/pack_hbnj_guide.py
tools/validate_hbnj_payloads.py
Enforce Nintendo LZ10 and 4 MiB VFF capacity limits on per-area native payloads before publication.
  • Introduce LZ10_MAX_INPUT and VFF_CAPACITY constants and a literal_lz10_size helper that models worst-case LZ10 size and validates representability
  • Include header.hdpk size when computing per-area VFF payload envelopes
  • Calculate raw, WC24 (compressed) and aggregate VFF payload bytes for each area and fail if they approach or exceed 4 MiB
  • Report detailed per-area size metrics and total raw bytes in validation output
tools/validate_hbnj_area_payloads.py
Adjust WC24 server and scheduled-task behavior for eight-day operation and stricter area handling.
  • Ensure area-specific /bin* requests 404 for unknown numeric area IDs instead of falling back to the oversized national payload
  • Lower the default courtesy delay for the daily update job and add a --days parameter wired into collection
  • Set UTF‑8 console output encoding in the PowerShell runner and configure PYTHONIOENCODING to avoid mangled logs
  • Update README and HBNJ adapter documentation to describe eight-day windows, genre table population, payload validation, and revised operational statistics
jwc24/server.py
tools/update_hbnj_daily.py
tools/run_hbnj_daily.ps1
channels/hbnj/README.md
README.md
channels/hbnj/channel.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@ColinGamez
ColinGamez marked this pull request as ready for review July 24, 2026 00:54
@ColinGamez
ColinGamez merged commit 2131d05 into main Jul 24, 2026
3 checks passed
@ColinGamez
ColinGamez deleted the agent/hbnj-compatibility-pass branch July 24, 2026 00:55

@sourcery-ai sourcery-ai 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.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="tools/validate_hbnj_guide.py" line_range="106-113" />
<code_context>
                 )
         descriptions += bool(description)
         programs_by_channel[channel_id].append((start, end))
+        dates_by_channel[channel_id].add(start.strftime("%Y%m%d"))

     empty_channels = set(channel_ids) - programs_by_channel.keys()
     if empty_channels:
         fail(f"channels without programs: {sorted(empty_channels)[:5]}")
     for channel_id, windows in programs_by_channel.items():
+        missing_dates = broadcast_dates - dates_by_channel[channel_id]
+        if missing_dates:
+            fail(
+                f"channel {channel_id} has no program starts on broadcast dates "
</code_context>
<issue_to_address>
**question:** The per-channel date coverage check only considers program starts, not full-day coverage.

This logic only verifies that each channel has a program *start* on each broadcast date. A long-running program that begins before the window and spans an entire day will be treated as missing, even though coverage exists. If the goal is to ensure per-day viewer coverage, consider validating based on time windows (start/end) rather than starts only, or clearly document the assumption that there must be at least one program start per channel per day.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +106 to +113
dates_by_channel[channel_id].add(start.strftime("%Y%m%d"))

empty_channels = set(channel_ids) - programs_by_channel.keys()
if empty_channels:
fail(f"channels without programs: {sorted(empty_channels)[:5]}")
for channel_id, windows in programs_by_channel.items():
missing_dates = broadcast_dates - dates_by_channel[channel_id]
if missing_dates:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

question: The per-channel date coverage check only considers program starts, not full-day coverage.

This logic only verifies that each channel has a program start on each broadcast date. A long-running program that begins before the window and spans an entire day will be treated as missing, even though coverage exists. If the goal is to ensure per-day viewer coverage, consider validating based on time windows (start/end) rather than starts only, or clearly document the assumption that there must be at least one program start per channel per day.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8dd2faa381

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"refresh_minutes": 1440,
"retry_minutes": 5,
"unsigned": false,
"mode": "create",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Maintain the task-table count when creating the header task

When this manifest is applied to a clean post-setup table containing only the native EPG and string tasks, mode: "create" invokes _write_task(), which writes slot 12 but never increments the active-entry count at offset 0x10 that dl_list.validate() identifies as an entry count. Unlike the duplicate-migration case, no entry is removed to balance this addition, so provisioning leaves nwc24dl.bin internally inconsistent and the new daily header task may not be scheduled; update the count when adding or removing entries.

Useful? React with 👍 / 👎.

Comment on lines +93 to +95
wc24_download_bytes = literal_lz10_size(epg_size) + literal_lz10_size(string_size)
vff_payload_bytes = header_size + wc24_download_bytes
if vff_payload_bytes >= VFF_CAPACITY:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Account for the compressed header and VFF filesystem overhead

For an area whose three files approach the 4 MiB limit, this calculation can accept a package that cannot fit in wc24dl.vff: the manifest stores header.bin with Nintendo LZ10 compression, but header_size is counted as raw HDPK bytes rather than literal_lz10_size(header_size), and the comparison reserves nothing for the FAT copies, directory, boot sector, or per-file cluster rounding. Use the VFF's actual usable data-cluster capacity and the stored sizes of all three files so the newly added size guard cannot publish an undownloadable guide.

Useful? React with 👍 / 👎.

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