To tackle this problem, we first need to translate the given natural language description into a symbolic representation. This involves defining variables for 'hours worked by John' and 'hours worked by Hank', formulating the objective function with these variables, and listing all constraints in terms of these variables.

Let's define:
- $x_0$ as 'hours worked by John'
- $x_1$ as 'hours worked by Hank'

The objective function to maximize is: $3.94x_0 + 7.71x_1$

Given the constraints:
1. The total combined productivity rating from hours worked by John and Hank should be at least 16.
2. The total combined organization score from hours worked by John plus hours worked by Hank should be at least 40.
3. $8x_0 - 2x_1 \geq 0$
4. The total combined productivity rating from hours worked by John plus hours worked by Hank should be 87 or less.
5. The total combined organization score from hours worked by John plus hours worked by Hank should be no more than 100 (corrected to reflect the original problem statement's upper bound for organization score, not 87 as mistakenly repeated).
6. $x_0$ must be an integer.

The symbolic representation of the problem is:
```json
{
    'sym_variables': [('x0', 'hours worked by John'), ('x1', 'hours worked by Hank')],
    'objective_function': '3.94*x0 + 7.71*x1',
    'constraints': [
        '15*x0 + 3*x1 >= 16', 
        '6*x0 + 8*x1 >= 40', 
        '8*x0 - 2*x1 >= 0', 
        '15*x0 + 3*x1 <= 87', 
        '6*x0 + 8*x1 <= 100',
    ]
}
```

Now, let's implement this optimization problem using Gurobi in Python:

```python
from gurobipy import *

# Create a new model
m = Model("Optimization_Problem")

# Define variables
x0 = m.addVar(vtype=GRB.INTEGER, name="hours_worked_by_John")
x1 = m.addVar(vtype=GRB.CONTINUOUS, name="hours_worked_by_Hank")

# Set the objective function
m.setObjective(3.94*x0 + 7.71*x1, GRB.MAXIMIZE)

# Add constraints
m.addConstr(15*x0 + 3*x1 >= 16, "productivity_rating")
m.addConstr(6*x0 + 8*x1 >= 40, "organization_score_min")
m.addConstr(8*x0 - 2*x1 >= 0, "constraint_1")
m.addConstr(15*x0 + 3*x1 <= 87, "productivity_rating_max")
m.addConstr(6*x0 + 8*x1 <= 100, "organization_score_max")

# Optimize the model
m.optimize()

# Print the results
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Hours worked by John: {x0.x}")
    print(f"Hours worked by Hank: {x1.x}")
    print(f"Objective function value: {m.objVal}")
else:
    print("No optimal solution found")
```